-
Notifications
You must be signed in to change notification settings - Fork 84
KTL-3015 implement Kotlin LSP proxy for completions #878
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
Merged
S-furi
merged 85 commits into
JetBrains:kotlin-community/dev
from
S-furi:exp/isolated-documents
Oct 31, 2025
Merged
Changes from all commits
Commits
Show all changes
85 commits
Select commit
Hold shift + click to select a range
c9cc370
feat: implement LSP-based completions
S-furi 33933bb
chore: remove unnecessary gradle files for lsp projects roots
S-furi a6dca44
chore: use version catalog for springboot deps
S-furi 14beab1
refactor: bring public function above private ones
S-furi b45bc01
refactor: rename completion test base
S-furi ecbc85d
refactor: remove and move completion-related tests into appropriate p…
S-furi 9ae355f
fix: guard sigle LSPClient creation when multiple `requires` are invoked
S-furi 97cae39
chore: add simple REST completion retrieval extension function
S-furi ef840d3
chore: rebase fixes
S-furi 9874cf4
chore: provide jackson's object mapper through a spring bean
S-furi 9f6e8e6
refactor: move lsp exception handler in exceptions' package
S-furi 6328221
refactor: move rest controller in rest package
S-furi a8fb85a
chore: make a global exception handler for completions' exceptions
S-furi 791624b
refactor: rename WS completion request dto
S-furi 0187604
refactor: simplify `Project` and `LspProject` logic
S-furi 8d010b6
fix: fix failing tests
S-furi 8c4b8e2
refactor: move `Completion` from `common` subproject to `completions`…
S-furi 00a447e
refactor: extract `FuzzyCompletionRanking` into util package
S-furi 9debbd7
chore: improve completion ranking
S-furi e78a763
fix: propagate rest endpoint refactor
S-furi eaf51da
chore: use JUnit assumption to ignore JS tests for LSP completions
S-furi f83349c
refactor: name BaseCompletionTest companion object
S-furi f01c7fe
refactor: use `extractCaret` function instead of manually specifying …
S-furi 7340f17
refactor: avoid duplicating code for JVM and JS tests
S-furi dc8c291
build: force `linux/amd64` when running LSP integration tests
S-furi 697db32
fix: adapt import test to LSP-based completions
S-furi 65c01c9
chore: do not include package in brackets when completion reference i…
S-furi a545867
test(lsp): make use of built docker image for lsp-tests
S-furi cfdac8d
refactor: move `Completion` from `common` subproject to `completions`…
S-furi 5fdfbef
chore: do not include package in brackets when completion reference i…
S-furi 1cc62aa
perf: make restful endpoint properly enqueue requests without blockin…
S-furi fbb92c7
test: implement `ConcurrencyCompletionRunnerTest` for LSP-based RESTf…
S-furi 672ad72
chore: add references to IntelliJ bug
S-furi 2198c9b
test: test stateless (RESTful) LSP-based completion service with Impo…
S-furi b24418a
chore: add jackson dependency for `ImportTest`
S-furi 1d817c4
chore: remove unused test
S-furi 02a5b34
fix: fix completion test
S-furi 1117658
chore: properly ignore test with related YouTrack issue
S-furi 145c9ca
test: implement import test for WS-based completions
S-furi 5fc82e4
chore: update backoff and reconnect parameters
S-furi 842422f
fix: avoid using lazy initialization, prefer `@BeforeAll` annotation
S-furi dc20743
chore: do not use coroutines apis for containerized LSP init healthcheck
S-furi d50ba6b
chore: increase initial connection timeout on WS tests
S-furi c0bb6bf
refactor: reuse completions check logic
S-furi da1dfcd
build: create common conventions for spring-boot based applications
S-furi 4ce3b74
refactor: extract test websocket client
S-furi 9ee8910
test: test WS endpoint with high concurrency
S-furi 865606c
chore: try increase WS timeout on concurrency test for passing in CI
S-furi f8b1114
chore: free warmup client when instanciating WS tests
S-furi e1be89f
refactor: refactor concurrency tests
S-furi 98cedb4
chore: add missing packages that has to be excluded from completion r…
S-furi 84f3959
docs: add KDoc for `LspCompletionQueue`
S-furi 6a108e9
chore(build): use settings plugin to resolve version catalog instead …
S-furi cb01d70
refactor: use `CompletionResponse` instead of plain `Completion`
S-furi ca34185
refactor: make `LspCompletionParser` managed by Spring's lifecycle ma…
S-furi 3f62093
chore: configure LSP parameters through spring's application configur…
S-furi 2879392
build: do not checkout repository with git large file system
S-furi 8454598
refactor: make use of `jackson`'s object mapper instead of `kotlinx.s…
S-furi cb0260e
chore: remove from base-project build file what's already defined in …
S-furi 2e16ed0
fix: write user's related files into `/tmp`
S-furi 8d3d609
feat: containerize `Completion` application
S-furi 6cdad72
chore: reorder completion parsing logic
S-furi da52ece
chore: move jackson's extension in proper package
S-furi 7c02e5e
chore: move `Icon` in enums package
S-furi ab4ef01
refactor: remove package declaration in build file
S-furi f77e871
chore: link YT issue to todo
S-furi ae108d9
chore: forward kotlin-lsp ports when running docker compose
S-furi 3114371
feat: use spring's docker compose support for kotlin-lsp
S-furi 3bb3a82
chore: pass LspConfig to clients
S-furi be1136a
chore: use `local` spring profile for running with local compose
S-furi 3c22338
chore: try use websites-team `intellij-lsp` docker image
S-furi 6ff3f95
fix: make tests use lsp configuration taken from compose
S-furi aaa9ee3
chore: use websites-team registry intellij-lsp docker image
S-furi bfc4a9e
chore: increase lsp-connection timeout in containerized environments
S-furi 88e51fb
fix: fix typo in application-local config
S-furi 7583164
refactor: distinguish between springdoc versions (webmvc or webflux)
S-furi ab77dd8
chore: set up springdoc for completions subproject
S-furi 825c065
fix: use single project root workspace as remote for lsp
S-furi 529d1b8
fix: do not start spring docker compose with prod config
S-furi abd08d9
chore: use single compose file for lsp
S-furi 5a8ee28
refactor: rename jackson extensions
S-furi f104477
chore: add additional config to spring docker compose configuration
S-furi 5d5be2d
chore: harden connection manager inFlight request avoidance logic
S-furi 099d5ab
fix: guard against possible null data (e.g. when in dumb mode)
S-furi c62ad8d
chore: se kotlin-lsp tagged version
S-furi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,3 +37,5 @@ out/ | |
|
|
||
| ### VS Code ### | ||
| .vscode/ | ||
|
|
||
| kotlin-lsp/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
buildSrc/src/main/kotlin/base-spring-boot-conventions.gradle.kts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import org.jetbrains.kotlin.gradle.tasks.KotlinCompile | ||
|
|
||
| plugins { | ||
| id("base-kotlin-jvm-conventions") | ||
|
|
||
| alias(libs.plugins.spring.boot) | ||
| alias(libs.plugins.spring.dependency.management) | ||
| alias(libs.plugins.kotlin.plugin.spring) | ||
| } | ||
|
|
||
| dependencies { | ||
| testImplementation(libs.spring.boot.starter.test) { | ||
| exclude(group = "org.junit.vintage", module = "junit-vintage-engine") | ||
| } | ||
| } | ||
|
|
||
| tasks.withType<KotlinCompile>().configureEach { | ||
| compilerOptions { freeCompilerArgs.addAll("-Xjsr305=strict") } | ||
| } | ||
|
|
||
| tasks.withType<Test>().configureEach { useJUnitPlatform() } |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| import org.springframework.boot.gradle.tasks.bundling.BootBuildImage | ||
|
|
||
| plugins { | ||
| id("base-spring-boot-conventions") | ||
| } | ||
|
|
||
| version = "${libs.versions.kotlin.get()}-SNAPSHOT" | ||
|
|
||
| dependencies { | ||
| implementation(libs.spring.boot.starter.webflux) | ||
| implementation(libs.spring.boot.docker.compose) | ||
| implementation(libs.springdoc.webflux) | ||
| implementation(libs.org.eclipse.lsp4j) | ||
| implementation(libs.kotlinx.coroutines.reactor) | ||
| testImplementation(libs.kotlin.test) | ||
| testImplementation(libs.bundles.testcontainers) | ||
| testImplementation(libs.rector.test) | ||
| } | ||
|
|
||
| tasks.named<BootBuildImage>("bootBuildImage") { | ||
| // TODO(KTL-3803):push docker image to JB registry | ||
| val baseImageName = "sfuri/kotlin-compiler-server-completions-lsp" | ||
| // publish = true | ||
| imageName = "$baseImageName:${project.version}" | ||
| tags = setOf("$baseImageName:latest") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| #!/bin/bash | ||
|
|
||
| export COMPLETIONS_SERVICE_PORT=8081 | ||
|
|
||
| # export LSP_LOCAL_WORKSPACE_ROOT=lsp-users-projects-root | ||
| export LSP_REMOTE_WORKSPACE_ROOT=lsp-users-projects-root-test | ||
|
|
||
| echo "building docker image for spring application" | ||
| yes n | ../gradlew bootBuildImage | ||
|
|
||
| if [[ " $* " == *" --run "* ]]; then | ||
| echo "requested starting completion service" | ||
| docker compose up -d | ||
| echo "completion service up and running" | ||
| fi | ||
|
|
||
| exit 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| services: | ||
| kotlin-lsp: | ||
dkrasnoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| image: sfuri/intellij-lsp | ||
| ports: | ||
| - "9999:9999" | ||
| networks: | ||
| - lsp-lsp-net | ||
|
|
||
| lsp-completions-service: | ||
| image: sfuri/kotlin-compiler-server-completions-lsp | ||
| ports: | ||
| - "${COMPLETIONS_SERVICE_PORT}:8082" | ||
| networks: | ||
| - lsp-lsp-net | ||
| environment: | ||
| - LSP_HOST=kotlin-lsp | ||
| - LSP_PORT=9999 | ||
| depends_on: | ||
| - kotlin-lsp | ||
|
|
||
| networks: | ||
| lsp-lsp-net: | ||
| driver: bridge | ||
14 changes: 14 additions & 0 deletions
14
completions/src/main/kotlin/completions/CompletionsApplication.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package completions | ||
|
|
||
| import completions.configuration.lsp.LspProperties | ||
| import org.springframework.boot.autoconfigure.SpringBootApplication | ||
| import org.springframework.boot.context.properties.EnableConfigurationProperties | ||
| import org.springframework.boot.runApplication | ||
|
|
||
| @SpringBootApplication | ||
| @EnableConfigurationProperties(value = [LspProperties::class]) | ||
| class CompletionsApplication | ||
|
|
||
| fun main(args: Array<String>) { | ||
| runApplication<CompletionsApplication>(*args) | ||
| } |
16 changes: 16 additions & 0 deletions
16
completions/src/main/kotlin/completions/configuration/CoroutinesConfig.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package completions.configuration | ||
|
|
||
| import kotlinx.coroutines.asCoroutineDispatcher | ||
| import org.springframework.context.annotation.Bean | ||
| import org.springframework.context.annotation.Configuration | ||
| import java.util.concurrent.Executors | ||
| import kotlin.coroutines.CoroutineContext | ||
|
|
||
| @Configuration | ||
| class CoroutinesConfig { | ||
| @Bean | ||
| fun lspCoroutineContext(): CoroutineContext { | ||
| val parallelism = (Runtime.getRuntime().availableProcessors() / 2).coerceAtLeast(4) | ||
| return Executors.newFixedThreadPool(parallelism).asCoroutineDispatcher() | ||
| } | ||
| } |
18 changes: 18 additions & 0 deletions
18
completions/src/main/kotlin/completions/configuration/CorsConfiguration.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package completions.configuration | ||
|
|
||
| import org.springframework.context.annotation.Bean | ||
| import org.springframework.context.annotation.Configuration | ||
| import org.springframework.web.cors.CorsConfiguration | ||
| import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource | ||
| import org.springframework.web.cors.reactive.CorsWebFilter | ||
|
|
||
| @Configuration | ||
| class CorsConfiguration { | ||
| @Bean | ||
| fun corsFilter(): CorsWebFilter { | ||
| val source = UrlBasedCorsConfigurationSource() | ||
| val config = CorsConfiguration().applyPermitDefaultValues() | ||
| source.registerCorsConfiguration("/**", config) | ||
| return CorsWebFilter(source) | ||
| } | ||
| } |
14 changes: 14 additions & 0 deletions
14
completions/src/main/kotlin/completions/configuration/JacksonConfig.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| package completions.configuration | ||
|
|
||
| import com.fasterxml.jackson.databind.ObjectMapper | ||
| import com.fasterxml.jackson.module.kotlin.kotlinModule | ||
| import org.springframework.context.annotation.Bean | ||
| import org.springframework.context.annotation.Configuration | ||
|
|
||
| @Configuration | ||
| class JacksonConfig { | ||
|
|
||
| @Bean | ||
| fun objectMapper(): ObjectMapper = | ||
| ObjectMapper().registerModule(kotlinModule()) | ||
| } |
22 changes: 22 additions & 0 deletions
22
completions/src/main/kotlin/completions/configuration/WebSocketConfiguration.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package completions.configuration | ||
|
|
||
| import completions.controllers.ws.LspCompletionWebSocketHandler | ||
| import org.springframework.context.annotation.Bean | ||
| import org.springframework.context.annotation.Configuration | ||
| import org.springframework.web.reactive.HandlerMapping | ||
| import org.springframework.web.reactive.handler.SimpleUrlHandlerMapping | ||
| import org.springframework.web.reactive.socket.server.support.WebSocketHandlerAdapter | ||
|
|
||
| @Configuration | ||
| class WebSocketConfiguration { | ||
| @Bean | ||
| fun webSocketHandlerAdapter(): WebSocketHandlerAdapter = WebSocketHandlerAdapter() | ||
|
|
||
| @Bean | ||
| fun webSocketMapping(handler: LspCompletionWebSocketHandler): HandlerMapping = | ||
| SimpleUrlHandlerMapping(mapOf(WEBSOCKET_COMPLETIONS_PATH to handler), 1) | ||
|
|
||
| companion object { | ||
| const val WEBSOCKET_COMPLETIONS_PATH = "/api/complete" | ||
| } | ||
| } |
16 changes: 16 additions & 0 deletions
16
completions/src/main/kotlin/completions/configuration/lsp/LspProperties.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package completions.configuration.lsp | ||
|
|
||
| import org.springframework.boot.context.properties.ConfigurationProperties | ||
|
|
||
| /** | ||
| * Simple LSP configuration properties which expose a way to be accessed | ||
| * even from non-spring managed components, i.e. [completions.lsp.client.LspConnectionManager]. | ||
| */ | ||
| @ConfigurationProperties(prefix = "lsp") | ||
| data class LspProperties( | ||
dkrasnoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| val host: String, | ||
| val port: Int, | ||
| val reconnectionRetries: Int, | ||
| val remoteWorkspaceRoot: String = "/lsp/workspaces/lsp-users-projects-root", | ||
dkrasnoff marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| val localWorkspaceRoot: String = "/lsp/workspaces/lsp-users-projects-root" | ||
| ) | ||
25 changes: 25 additions & 0 deletions
25
completions/src/main/kotlin/completions/controllers/rest/CompletionsRestController.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package completions.controllers.rest | ||
|
|
||
| import completions.dto.api.CompletionRequest | ||
| import completions.dto.api.CompletionResponse | ||
| import completions.service.lsp.LspCompletionQueue | ||
| import org.springframework.web.bind.annotation.PostMapping | ||
| import org.springframework.web.bind.annotation.RequestBody | ||
| import org.springframework.web.bind.annotation.RequestMapping | ||
| import org.springframework.web.bind.annotation.RequestParam | ||
| import org.springframework.web.bind.annotation.RestController | ||
|
|
||
| @RestController | ||
| @RequestMapping(value = ["/api/compiler"]) | ||
| class CompletionsRestController( | ||
| private val lspCompletionQueue: LspCompletionQueue, | ||
| ) { | ||
| @PostMapping("/complete") | ||
| suspend fun complete( | ||
| @RequestBody completionRequest: CompletionRequest, | ||
| @RequestParam line: Int, | ||
| @RequestParam ch: Int, | ||
| ): List<CompletionResponse> { | ||
| return lspCompletionQueue.complete(completionRequest, line, ch) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.