Skip to content

Commit 5a18965

Browse files
committed
Implement predicated traversals and ranged semantic tokens
1 parent 9561f35 commit 5a18965

File tree

2 files changed

+22
-9
lines changed

2 files changed

+22
-9
lines changed

server/src/main/kotlin/org/javacs/kt/semantictokens/SemanticTokens.kt

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import org.eclipse.lsp4j.SemanticTokensLegend
66
import org.eclipse.lsp4j.Range
77
import org.javacs.kt.CompiledFile
88
import org.javacs.kt.position.range
9+
import org.javacs.kt.position.offset
910
import org.javacs.kt.util.preOrderTraversal
1011
import org.jetbrains.kotlin.descriptors.ClassDescriptor
1112
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -51,8 +52,12 @@ val semanticTokensLegend = SemanticTokensLegend(
5152

5253
private data class SemanticToken(val range: Range, val type: SemanticTokenType, val modifiers: Set<SemanticTokenModifier> = setOf())
5354

54-
fun semanticTokens(file: CompiledFile): List<Int> =
55-
encodeTokens(elementTokens(file.parse, file.compile))
55+
/**
56+
* Computes semantic tokens for the given range in the document.
57+
* No range means the entire document.
58+
*/
59+
fun semanticTokens(file: CompiledFile, range: Range? = null): List<Int> =
60+
encodeTokens(elementTokens(file.parse, file.compile, range))
5661

5762
private fun encodeTokens(tokens: Sequence<SemanticToken>): List<Int> {
5863
val encoded = mutableListOf<Int>()
@@ -84,9 +89,13 @@ private fun encodeModifiers(modifiers: Set<SemanticTokenModifier>): Int = modifi
8489
.map { 1 shl it.ordinal }
8590
.fold(0, Int::or)
8691

87-
private fun elementTokens(element: PsiElement, bindingContext: BindingContext): Sequence<SemanticToken> = element
88-
.preOrderTraversal()
89-
.mapNotNull { elementToken(it, bindingContext) }
92+
private fun elementTokens(element: PsiElement, bindingContext: BindingContext, range: Range? = null): Sequence<SemanticToken> {
93+
val file = element.containingFile
94+
val offsets = range?.let { Pair(offset(file.text, it.start), offset(file.text, it.end)) }
95+
return element
96+
.preOrderTraversal { offsets?.let { element.textRange.containsRange(it.first, it.second) } ?: true }
97+
.mapNotNull { elementToken(it, bindingContext) }
98+
}
9099

91100
private fun elementToken(element: PsiElement, bindingContext: BindingContext): SemanticToken? {
92101
val file = element.containingFile

server/src/main/kotlin/org/javacs/kt/util/PsiUtils.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,18 @@ import java.nio.file.Path
88
inline fun<reified Find> PsiElement.findParent() =
99
this.parentsWithSelf.filterIsInstance<Find>().firstOrNull()
1010

11-
fun PsiElement.preOrderTraversal(): Sequence<PsiElement> {
11+
fun PsiElement.preOrderTraversal(shouldTraverse: (PsiElement) -> Boolean = { true }): Sequence<PsiElement> {
1212
val root = this
1313

1414
return sequence {
15-
yield(root)
15+
if (shouldTraverse(root)) {
16+
yield(root)
1617

17-
for (child in root.children) {
18-
yieldAll(child.preOrderTraversal())
18+
for (child in root.children) {
19+
if (shouldTraverse(child)) {
20+
yieldAll(child.preOrderTraversal(shouldTraverse))
21+
}
22+
}
1923
}
2024
}
2125
}

0 commit comments

Comments
 (0)