Skip to content
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

Semantic highlighting #79

Closed
wants to merge 4 commits into from
Closed
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
Expand Up @@ -81,6 +81,10 @@ import org.eclipse.lsp4j.services.LanguageClientAware
import org.eclipse.lsp4j.services.LanguageServer
import org.eclipse.lsp4j.services.TextDocumentService
import org.eclipse.lsp4j.services.WorkspaceService
import org.eclipse.lsp4j.SemanticTokensWithRegistrationOptions
import org.eclipse.lsp4j.SemanticTokensLegend
import org.eclipse.lsp4j.SemanticTokensParams
import org.eclipse.lsp4j.SemanticTokens
import java.io.File
import java.io.InputStream
import java.io.OutputStream
Expand All @@ -91,6 +95,10 @@ import java.nio.file.Paths
import java.util.UUID
import java.util.concurrent.CompletableFuture
import kotlin.system.exitProcess
import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticTokenType;
import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticTokenModifier;
import com.strumenta.kolasu.languageserver.semanticHighlighting.encode
import com.strumenta.kolasu.languageserver.semanticHighlighting.SemanticToken

open class KolasuServer<T : Node>(
protected open val parser: ASTParser<T>?,
Expand Down Expand Up @@ -155,6 +163,11 @@ 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 +580,15 @@ 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,29 @@
package com.strumenta.kolasu.languageserver.semanticHighlighting

import com.strumenta.kolasu.model.Point
import com.strumenta.kolasu.model.Position
import org.eclipse.lsp4j.SemanticTokens

data class SemanticToken(val position: Position, val type: SemanticTokenType, val modifiers: List<SemanticTokenModifier>)

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,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")
}
Loading