Skip to content

Semantic highlighting #80

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 3 commits into
base: main
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
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -155,6 +163,12 @@ open class KolasuServer<T : Node>(
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))
}

Expand Down Expand Up @@ -567,6 +581,16 @@ open class KolasuServer<T : Node>(
val reader = DirectoryReader.open(FSDirectory.open(indexPath))
indexSearcher = IndexSearcher(reader)
}


override fun semanticTokensFull(params: SemanticTokensParams): CompletableFuture<SemanticTokens> {
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<SemanticToken> = listOf()
}

interface CodeGenerator<T : Node> {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<SemanticToken>, 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<Int>()
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)
}
Original file line number Diff line number Diff line change
@@ -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<SemanticTokenModifier>
)
Original file line number Diff line number Diff line change
@@ -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)
}
Original file line number Diff line number Diff line change
@@ -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")
}