Skip to content

Commit b324b6e

Browse files
committed
implemented codelens and codelens resolution
1 parent 3d2c197 commit b324b6e

File tree

3 files changed

+134
-4
lines changed

3 files changed

+134
-4
lines changed

server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class KotlinLanguageServer(
9393
serverCapabilities.documentRangeFormattingProvider = Either.forLeft(true)
9494
serverCapabilities.executeCommandProvider = ExecuteCommandOptions(ALL_COMMANDS)
9595
serverCapabilities.documentHighlightProvider = Either.forLeft(true)
96+
serverCapabilities.codeLensProvider = CodeLensOptions(true)
9697

9798
val storagePath = getStoragePath(params)
9899
databaseService.setup(storagePath)

server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import java.io.Closeable
3434
import java.nio.file.Path
3535
import java.time.Duration
3636
import java.util.concurrent.CompletableFuture
37+
import org.javacs.kt.codelens.findCodeLenses
3738

3839
class KotlinTextDocumentService(
3940
private val sf: SourceFiles,
@@ -144,8 +145,14 @@ class KotlinTextDocumentService(
144145
))
145146
}
146147

147-
override fun codeLens(params: CodeLensParams): CompletableFuture<List<CodeLens>> {
148-
TODO("not implemented")
148+
override fun codeLens(params: CodeLensParams): CompletableFuture<List<CodeLens>> = async.compute {
149+
reportTime {
150+
LOG.info("Finding code lenses in {}", describeURI(params.textDocument.uri))
151+
152+
val uri = parseURI(params.textDocument.uri)
153+
val file = sp.currentVersion(uri)
154+
return@compute findCodeLenses(file)
155+
}
149156
}
150157

151158
override fun rename(params: RenameParams) = async.compute {
@@ -263,8 +270,66 @@ class KotlinTextDocumentService(
263270
}
264271
}
265272

266-
override fun resolveCodeLens(unresolved: CodeLens): CompletableFuture<CodeLens> {
267-
TODO("not implemented")
273+
override fun resolveCodeLens(unresolved: CodeLens): CompletableFuture<CodeLens> = async.compute {
274+
reportTime {
275+
LOG.info("Resolving code lens {}", unresolved.command?.command)
276+
277+
val command = unresolved.command
278+
if (command == null) {
279+
return@compute unresolved
280+
}
281+
282+
val args = command.arguments as List<*>
283+
if (args.size != 3) {
284+
return@compute unresolved
285+
}
286+
287+
val uri = args[0] as String
288+
val line = args[1] as Int
289+
val character = args[2] as Int
290+
291+
val file = sp.currentVersion(parseURI(uri))
292+
val content = sp.content(parseURI(uri))
293+
val offset = offset(content, line, character)
294+
295+
when (command.command) {
296+
"kotlin.showImplementations" -> {
297+
val implementations = findImplementation(sp, sf, file, offset)
298+
if (implementations.isNotEmpty()) {
299+
unresolved.command = Command(
300+
command.title,
301+
command.command,
302+
listOf(uri, line, character, implementations)
303+
)
304+
}
305+
}
306+
"kotlin.showSubclasses" -> {
307+
val implementations = findImplementation(sp, sf, file, offset)
308+
if (implementations.isNotEmpty()) {
309+
unresolved.command = Command(
310+
command.title,
311+
command.command,
312+
listOf(uri, line, character, implementations)
313+
)
314+
}
315+
}
316+
"kotlin.showReferences" -> {
317+
val filePath = parseURI(uri).filePath
318+
if (filePath != null) {
319+
val references = findReferences(filePath, offset, sp)
320+
if (references.isNotEmpty()) {
321+
unresolved.command = Command(
322+
command.title,
323+
command.command,
324+
listOf(uri, line, character, references)
325+
)
326+
}
327+
}
328+
}
329+
}
330+
331+
return@compute unresolved
332+
}
268333
}
269334

270335
private fun describePosition(position: TextDocumentPositionParams): String {
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package org.javacs.kt.codelens
2+
3+
import org.eclipse.lsp4j.CodeLens
4+
import org.eclipse.lsp4j.Command
5+
import org.eclipse.lsp4j.Range
6+
import org.javacs.kt.CompiledFile
7+
import org.javacs.kt.LOG
8+
import org.javacs.kt.position.location
9+
import org.jetbrains.kotlin.descriptors.ClassDescriptor
10+
import org.jetbrains.kotlin.descriptors.ClassKind
11+
import org.jetbrains.kotlin.psi.KtClassOrObject
12+
import org.jetbrains.kotlin.psi.KtNamedFunction
13+
import org.jetbrains.kotlin.resolve.BindingContext
14+
import java.nio.file.Paths
15+
16+
fun findCodeLenses(file: CompiledFile): List<CodeLens> {
17+
val codeLenses = mutableListOf<CodeLens>()
18+
val parsedFile = file.parse
19+
val filePath = Paths.get(parsedFile.containingFile.virtualFile.path)
20+
val uri = filePath.toUri().toString()
21+
22+
// Add code lenses for classes and interfaces
23+
parsedFile.declarations.filterIsInstance<KtClassOrObject>().forEach { ktClass ->
24+
val classDesc = file.compile.get(BindingContext.CLASS, ktClass)
25+
if (classDesc != null) {
26+
when (classDesc.kind) {
27+
ClassKind.INTERFACE -> {
28+
// Add "Show Implementations" code lens for interfaces
29+
location(ktClass)?.let { loc ->
30+
codeLenses.add(CodeLens(
31+
loc.range,
32+
Command("Show Implementations", "kotlin.showImplementations", listOf(uri, loc.range.start.line, loc.range.start.character)),
33+
null
34+
))
35+
}
36+
}
37+
ClassKind.CLASS -> {
38+
// Add "Show Subclasses" code lens for classes
39+
location(ktClass)?.let { loc ->
40+
codeLenses.add(CodeLens(
41+
loc.range,
42+
Command("Show Subclasses", "kotlin.showSubclasses", listOf(uri, loc.range.start.line, loc.range.start.character)),
43+
null
44+
))
45+
}
46+
}
47+
else -> {}
48+
}
49+
}
50+
}
51+
52+
// Add code lenses for functions
53+
parsedFile.declarations.filterIsInstance<KtNamedFunction>().forEach { ktFunction ->
54+
location(ktFunction)?.let { loc ->
55+
codeLenses.add(CodeLens(
56+
loc.range,
57+
Command("Show References", "kotlin.showReferences", listOf(uri, loc.range.start.line, loc.range.start.character)),
58+
null
59+
))
60+
}
61+
}
62+
63+
return codeLenses
64+
}

0 commit comments

Comments
 (0)