@@ -4,7 +4,12 @@ import org.eclipse.lsp4j.SemanticTokenTypes
4
4
import org.eclipse.lsp4j.SemanticTokenModifiers
5
5
import org.eclipse.lsp4j.SemanticTokensLegend
6
6
import org.eclipse.lsp4j.Range
7
- import org.jetbrains.kotlin.psi.KtElement
7
+ import org.javacs.kt.position.range
8
+ import org.javacs.kt.util.preOrderTraversal
9
+ import org.jetbrains.kotlin.psi.KtProperty
10
+ import org.jetbrains.kotlin.psi.KtVariableDeclaration
11
+ import org.jetbrains.kotlin.psi.KtNamedDeclaration
12
+ import com.intellij.psi.PsiElement
8
13
9
14
private enum class SemanticTokenType (val typeName : String ) {
10
15
VARIABLE (SemanticTokenTypes .Variable ),
@@ -22,9 +27,51 @@ val semanticTokensLegend = SemanticTokensLegend(
22
27
SemanticTokenModifier .values().map { it.modifierName }
23
28
)
24
29
25
- private data class SemanticToken (val range : Range , val type : SemanticTokenType , val modifiers : Set <SemanticTokenModifier >)
30
+ private data class SemanticToken (val range : Range , val type : SemanticTokenType , val modifiers : Set <SemanticTokenModifier > = setOf() )
26
31
27
- private fun semanticTokens (element : KtElement ): List <Int > {
28
- return listOf () // TODO
32
+ fun semanticTokens (element : PsiElement ): List <Int > = encodeTokens(elementTokens(element))
33
+
34
+ private fun encodeTokens (tokens : Sequence <SemanticToken >): List <Int > {
35
+ val encoded = mutableListOf<Int >()
36
+ var last: SemanticToken ? = null
37
+
38
+ for (token in tokens) {
39
+ // Tokens must be on a single line
40
+ if (token.range.start.line == token.range.end.line) {
41
+ val deltaLine = token.range.start.line - (last?.let { it.range.start.line } ? : 0 )
42
+ val deltaStart = token.range.start.character - (last?.let { it.range.start.character } ? : 0 )
43
+ val length = token.range.end.character - token.range.start.character
44
+
45
+ encoded.add(deltaLine)
46
+ encoded.add(deltaStart)
47
+ encoded.add(length)
48
+ encoded.add(encodeType(token.type))
49
+ encoded.add(encodeModifiers(token.modifiers))
50
+
51
+ last = token
52
+ }
53
+ }
54
+
55
+ return encoded
29
56
}
30
57
58
+ private fun encodeType (type : SemanticTokenType ): Int = type.ordinal
59
+
60
+ private fun encodeModifiers (modifiers : Set <SemanticTokenModifier >): Int = modifiers
61
+ .map { 1 << it.ordinal }
62
+ .fold(0 , |)
63
+
64
+ private fun elementTokens (element : PsiElement ): Sequence <SemanticToken > = element
65
+ .preOrderTraversal()
66
+ .mapNotNull { (it as ? KtNamedDeclaration )?.nameIdentifier }
67
+ .mapNotNull { elementToken(it) }
68
+
69
+ private fun elementToken (element : PsiElement ): SemanticToken ? {
70
+ val file = element.containingFile
71
+ val elementRange = range(file.text, element.textRange)
72
+ return when (element) {
73
+ is KtProperty -> SemanticToken (elementRange, SemanticTokenType .PROPERTY )
74
+ is KtVariableDeclaration -> SemanticToken (elementRange, SemanticTokenType .VARIABLE )
75
+ else -> null
76
+ }
77
+ }
0 commit comments