Skip to content

Extend trait 'LanguageService' and methods with additional 'config' parameter #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: feature/support-notebooks
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Continuous Integration

env:
JAVA_VERSION: '11'

on:
push:
branches:
- main
pull_request:

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- name: Set up JDK ${{ env.JAVA_VERSION }}
uses: actions/setup-java@v4
with:
java-version: ${{ env.JAVA_VERSION }}
distribution: 'zulu'
cache: 'sbt'

- name: Setup SBT
uses: sbt/setup-sbt@v1

- name: Run tests
run: sbt clean test
13 changes: 9 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ lazy val replDependencies = Seq(

lazy val lspDependencies = Seq(
"org.eclipse.lsp4j" % "org.eclipse.lsp4j" % "0.23.1",
"com.google.code.gson" % "gson" % "2.8.2"
"com.google.code.gson" % "gson" % "2.11.0"
)

lazy val testingDependencies = Seq(
"org.scala-sbt" %% "io" % "1.6.0" % Test,
"org.scalameta" %% "munit" % "0.7.29" % Test
)

lazy val kiama: CrossProject = crossProject(JSPlatform, JVMPlatform).in(file("."))
Expand All @@ -32,7 +37,7 @@ lazy val kiama: CrossProject = crossProject(JSPlatform, JVMPlatform).in(file("."
name := "kiama"
)
.jvmSettings(
libraryDependencies ++= (replDependencies ++ lspDependencies),
libraryDependencies += "com.lihaoyi" %% "utest" % "0.8.2" % "test",
testFrameworks += new TestFramework("utest.runner.Framework")
libraryDependencies ++= (replDependencies ++ lspDependencies ++ testingDependencies),

Test / testOptions += Tests.Argument(TestFrameworks.MUnit, "-oD"),
)
2 changes: 1 addition & 1 deletion jvm/src/main/scala/kiama/util/Compiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ trait Compiler[C <: Config, M <: Message] {
}

/**
* Run the compiler given a configuration. Overriden in Server to
* Run the compiler given a configuration. Overwritten in Server to
* also provide LSP services.
*/
def run(config: C): Unit = ()
Expand Down
49 changes: 27 additions & 22 deletions jvm/src/main/scala/kiama/util/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import scala.jdk.CollectionConverters._
* A language server that is mixed with a compiler that provide the basis
* for its services. Allows specialisation of configuration via `C`.
*/
trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageService[N] {
trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageService[N, C] {

import com.google.gson.{ JsonArray, JsonElement, JsonObject }
import java.util.Collections
Expand Down Expand Up @@ -215,7 +215,7 @@ trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageS
val after = cells.drop(start + deleteCount)

// create if not already exist (this can be the case if cells are re-ordered=delete+insert)
insertedUris.foreach { uri => sources.getOrElseUpdate(uri, RopeSource(Rope.empty, uri)) }
insertedUris.foreach { uri => sources.getOrElseUpdate(uri, BufferSource(GapBuffer.empty, uri)) }
val inserted = insertedUris.map(NotebookCell.apply)

val updated = (before ++ inserted ++ after).map(c => c.uri -> c).toMap
Expand All @@ -229,7 +229,8 @@ trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageS
def onNotebookContentChange(
notebookUri: String,
cellUri: String,
changes: Seq[TextDocumentContentChangeEvent]
changes: Seq[TextDocumentContentChangeEvent],
config: C
): Unit = {
val bs = sources.get(cellUri) match {
case Some(buffer: BufferSource) => buffer
Expand Down Expand Up @@ -261,18 +262,18 @@ trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageS
// Update and process notebook accordingly
notebooks.get(notebookUri).foreach { notebook =>
notebook.cells.get(cellUri).foreach { cell =>
processCell(cell, notebook)
processCell(cell, notebook, config)
}
}
}

/**
* Called when a notebook is saved.
**/
def onNotebookSave(notebookUri: String): Unit = {
def onNotebookSave(notebookUri: String, config: C): Unit = {
notebooks.get(notebookUri).foreach { notebook =>
notebook.cells.values.foreach { cell =>
processCell(cell, notebook)
processCell(cell, notebook, config)
// comment this in to see state of the notebook on save (in server debug mode)
// println(sources.get(cell.uri))
}
Expand Down Expand Up @@ -317,9 +318,19 @@ trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageS
}
}

def toURI(filename: String): String = filename match {
case _ if filename startsWith "file:" =>
filename
case _ if filename startsWith "vscode-notebook-cell:" =>
filename
case _ if filename startsWith "./" =>
s"file://${Filenames.cwd()}/${Filenames.dropPrefix(filename, ".")}"
case _ =>
s"file://$filename"
}

def publishDiagnostics(name: String, diagnostics: Vector[Diagnostic]): Unit = {
val uri = if (name startsWith "file://") name else s"file://$name"
val params = new PublishDiagnosticsParams(uri, seqToJavaList(diagnostics))
val params = new PublishDiagnosticsParams(toURI(name), seqToJavaList(diagnostics))
client.publishDiagnostics(params)
}

Expand Down Expand Up @@ -459,29 +470,22 @@ trait Server[N, C <: Config, M <: Message] extends Compiler[C, M] with LanguageS
}

// Support for services

def locationOfNode(node: N): Location = {
(positions.getStart(node), positions.getFinish(node)) match {
case (start @ Some(st), finish @ Some(_)) =>
st.source match {
case StringSource(_, name) =>
val s = convertPosition(start)
val f = convertPosition(finish)
new Location(name, new LSPRange(s, f))
case _ =>
null
}
val s = convertPosition(start)
val f = convertPosition(finish)
new Location(toURI(st.source.name), new LSPRange(s, f))
case _ =>
null
}
}

def rangeOfNode(node: N): LSPRange =
convertRange(positions.getStart(node), positions.getFinish(node))

}

trait LanguageService[N] {
trait LanguageService[N, C] {

/**
* A representation of a simple named code action that replaces
Expand Down Expand Up @@ -547,7 +551,7 @@ trait LanguageService[N] {
* Process a cell in the given notebook. Default is to do nothing,
* meaning cells won't be processed until a compiler overrides this.
*/
def processCell(cell: NotebookCell, notebook: Notebook): Unit = ()
def processCell(cell: NotebookCell, notebook: Notebook, config: C): Option[Any] = None
}

class Services[N, C <: Config, M <: Message](
Expand Down Expand Up @@ -702,7 +706,8 @@ class Services[N, C <: Config, M <: Message](
server.onNotebookContentChange(
notebookUri,
change.getDocument.getUri,
change.getChanges.asScala.toSeq
change.getChanges.asScala.toSeq,
config
)
}
}
Expand All @@ -716,7 +721,7 @@ class Services[N, C <: Config, M <: Message](

@JsonNotification("notebookDocument/didSave")
def notebookDidSave(params: DidSaveNotebookDocumentParams): Unit = {
server.onNotebookSave(params.getNotebookDocument.getUri)
server.onNotebookSave(params.getNotebookDocument.getUri, config)
}

@JsonNotification("notebookDocument/didClose")
Expand Down
Loading