From 77f19ea5a9aa5fec9ada8fcd672433976cca7373 Mon Sep 17 00:00:00 2001 From: Martin Azpillaga Aldalur Date: Fri, 3 Jan 2025 22:34:08 +0100 Subject: [PATCH 1/3] define data structures for semantic highlighting --- .../semanticHighlighting/SemanticToken.kt | 9 +++++++ .../SemanticTokenModifier.kt | 14 ++++++++++ .../semanticHighlighting/SemanticTokenType.kt | 27 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticToken.kt create mode 100644 library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenModifier.kt create mode 100644 library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenType.kt diff --git a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticToken.kt b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticToken.kt new file mode 100644 index 0000000..ae9e50b --- /dev/null +++ b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticToken.kt @@ -0,0 +1,9 @@ +package com.strumenta.kolasu.languageserver.semanticHighlighting + +import com.strumenta.kolasu.model.Position + +data class SemanticToken( + val position: Position, + val type: SemanticTokenType, + val modifiers: List +) diff --git a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenModifier.kt b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenModifier.kt new file mode 100644 index 0000000..c9c54e5 --- /dev/null +++ b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenModifier.kt @@ -0,0 +1,14 @@ +package com.strumenta.kolasu.languageserver.semanticHighlighting + +enum class SemanticTokenModifier(val legendName: String, val bit: Int) { + DECLARATION("declaration", 1), + DEFINITION("definition", 2), + READ_ONLY("readonly", 4), + STATIC("static", 8), + DEPRECATED("deprecated", 16), + ABSTRACT("abstract", 32), + ASYNCHRONOUS("async", 64), + MODIFICATION("modification", 128), + DOCUMENTATION("documentation", 256), + DEFAULT_LIBRARY("defaultLibrary", 512) +} \ No newline at end of file diff --git a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenType.kt b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenType.kt new file mode 100644 index 0000000..4612f85 --- /dev/null +++ b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/SemanticTokenType.kt @@ -0,0 +1,27 @@ +package com.strumenta.kolasu.languageserver.semanticHighlighting + +enum class SemanticTokenType (val legendName: String) { + NAMESPACE("namespace"), + CLASS("class"), + ENUM("enum"), + INTERFACE("interface"), + STRUCT("struct"), + TYPE_PARAMETER("typeParameter"), + TYPE("type"), + PARAMETER("parameter"), + VARIABLE("variable"), + PROPERTY("property"), + ENUM_MEMBER("enumMember"), + DECORATOR("decorator"), + EVENT("event"), + FUNCTION("function"), + METHOD("method"), + MACRO("macro"), + LABEL("label"), + COMMENT("comment"), + STRING("string"), + KEYWORD("keyword"), + NUMBER("number"), + REGULAR_EXPRESSION("regexp"), + OPERATOR("operator") +} From f59c77dee7978d8b1628625e5be9ece72c6d26af Mon Sep 17 00:00:00 2001 From: Martin Azpillaga Aldalur Date: Fri, 3 Jan 2025 22:46:41 +0100 Subject: [PATCH 2/3] encode semantic token list into lsp relative integers --- .../semanticHighlighting/Encoding.kt | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/Encoding.kt diff --git a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/Encoding.kt b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/Encoding.kt new file mode 100644 index 0000000..81af25d --- /dev/null +++ b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/semanticHighlighting/Encoding.kt @@ -0,0 +1,27 @@ +package com.strumenta.kolasu.languageserver.semanticHighlighting + +import com.strumenta.kolasu.model.Point +import com.strumenta.kolasu.model.Position +import org.eclipse.lsp4j.SemanticTokens + +fun encode(tokens: List, code: String): SemanticTokens { + // Create synthetic token at start to compute relative positions from + var lastToken = SemanticToken(Position(Point(1, 0), Point(1, 0)), SemanticTokenType.TYPE, listOf()) + + val data = mutableListOf() + for (token in tokens) { + val deltaLine = token.position.start.line - (lastToken.position.start.line) + val deltaStart = if (token.position.start.line == lastToken.position.start.line) { + token.position.start.column - lastToken.position.start.column + } else { + token.position.start.column + } + val length = token.position.length(code) + val tokenType = token.type.ordinal + val tokenModifiers = token.modifiers.sumOf { it.bit } + + data.addAll(listOf(deltaLine, deltaStart, length, tokenType, tokenModifiers)) + lastToken = token + } + return SemanticTokens(data) +} From 130d70c15178c17ba3bb441165530fa2c549d643 Mon Sep 17 00:00:00 2001 From: Martin Azpillaga Aldalur Date: Fri, 3 Jan 2025 22:58:03 +0100 Subject: [PATCH 3/3] configure language server defaults for semantic highlighting --- .../kolasu/languageserver/KolasuServer.kt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/KolasuServer.kt b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/KolasuServer.kt index 0d7e4cc..8e59e53 100644 --- a/library/src/main/kotlin/com/strumenta/kolasu/languageserver/KolasuServer.kt +++ b/library/src/main/kotlin/com/strumenta/kolasu/languageserver/KolasuServer.kt @@ -1,6 +1,10 @@ package com.strumenta.kolasu.languageserver import com.google.gson.JsonObject +import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticToken +import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticTokenModifier +import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticTokenType +import com.strumenta.kolasu.languageserver.semanticHighlighting.encode import com.strumenta.kolasu.model.Node import com.strumenta.kolasu.model.Point import com.strumenta.kolasu.model.PossiblyNamed @@ -60,6 +64,10 @@ import org.eclipse.lsp4j.Range import org.eclipse.lsp4j.ReferenceParams import org.eclipse.lsp4j.Registration import org.eclipse.lsp4j.RegistrationParams +import org.eclipse.lsp4j.SemanticTokens +import org.eclipse.lsp4j.SemanticTokensLegend +import org.eclipse.lsp4j.SemanticTokensParams +import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions import org.eclipse.lsp4j.ServerCapabilities import org.eclipse.lsp4j.SetTraceParams import org.eclipse.lsp4j.ShowMessageRequestParams @@ -155,6 +163,12 @@ open class KolasuServer( capabilities.setDefinitionProvider(this.enableDefinitionCapability) capabilities.setReferencesProvider(this.enableReferencesCapability) + + capabilities.semanticTokensProvider = SemanticTokensWithRegistrationOptions().apply { + legend = SemanticTokensLegend(SemanticTokenType.values().map { it.legendName }, SemanticTokenModifier.values().map { it.legendName }); + full = Either.forLeft(true) + } + return CompletableFuture.completedFuture(InitializeResult(capabilities)) } @@ -567,6 +581,16 @@ open class KolasuServer( val reader = DirectoryReader.open(FSDirectory.open(indexPath)) indexSearcher = IndexSearcher(reader) } + + + override fun semanticTokensFull(params: SemanticTokensParams): CompletableFuture { + val ast = files[params.textDocument.uri]?.root ?: return CompletableFuture.completedFuture(SemanticTokens()) + val code = files[params.textDocument.uri]?.code ?: return CompletableFuture.completedFuture(SemanticTokens()) + val tokens = semanticTokens(ast) + return CompletableFuture.completedFuture(encode(tokens, code)) + } + + open fun semanticTokens(ast: T): List = listOf() } interface CodeGenerator {