Skip to content

Commit

Permalink
Implement folding ranges, starting work on the logger, general improv…
Browse files Browse the repository at this point in the history
…ements
  • Loading branch information
hegyibalint committed Jul 26, 2024
1 parent e1e0b5b commit 4e8982e
Show file tree
Hide file tree
Showing 13 changed files with 170 additions and 47 deletions.
5 changes: 3 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

[versions]
lsp4j = "0.23.1"
logback-classic = "1.5.6"
logback = "1.5.6"
kotlin = "2.0.0"
kotlinx-coroutines = "1.8.1"
gradle-tooling = "+"
Expand All @@ -13,7 +13,8 @@ declarative-dsl = "+"
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-core-jvm = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core-jvm", version.ref = "kotlinx-coroutines" }
lsp4j = { group = "org.eclipse.lsp4j", name = "org.eclipse.lsp4j", version.ref = "lsp4j" }
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback-classic" }
logback-core = { group = "ch.qos.logback", name = "logback-core", version.ref = "logback" }
logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
gradle-tooling-api = { module = "org.gradle:gradle-tooling-api", version.ref = "gradle-tooling" }
gradle-declarative-dsl-core = { module = "org.gradle:gradle-declarative-dsl-core", version.ref = "declarative-dsl" }
gradle-declarative-dsl-evaluator = { module = "org.gradle:gradle-declarative-dsl-evaluator", version.ref = "declarative-dsl" }
Expand Down
2 changes: 2 additions & 0 deletions lsp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ plugins {

dependencies {
implementation(project(":model"))

implementation(libs.kotlinx.coroutines.core)
implementation(libs.kotlinx.coroutines.core.jvm)
implementation(libs.lsp4j)
implementation(libs.logback.classic)
implementation(libs.gradle.tooling.api)
implementation(libs.gradle.declarative.dsl.core)
implementation(libs.gradle.declarative.dsl.evaluator)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.gradle.declarative.lsp.server
package org.gradle.declarative.lsp

import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.services.*
import org.gradle.declarative.lsp.tooling.ConnectionHandler
import org.gradle.declarative.lsp.tapi.ConnectionHandler
import java.io.File
import java.net.URI
import java.util.concurrent.CompletableFuture
Expand Down Expand Up @@ -33,7 +33,7 @@ class DeclarativeLanguageServer : LanguageServer, LanguageClientAware {
val serverCapabilities = ServerCapabilities()
serverCapabilities.setTextDocumentSync(TextDocumentSyncKind.Full)
serverCapabilities.setHoverProvider(true)
serverCapabilities.setFoldingRangeProvider(true)
// serverCapabilities.setFoldingRangeProvider(true)

val workspaceFolder = params!!.workspaceFolders[0]
val workspaceFolderFile = File(URI.create(workspaceFolder.uri))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.gradle.declarative.lsp.server
package org.gradle.declarative.lsp

import org.eclipse.lsp4j.*
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.LanguageClientAware
import org.eclipse.lsp4j.services.TextDocumentService
import org.gradle.declarative.lsp.build.model.ResolvedDeclarativeResourcesModel
import org.gradle.declarative.lsp.modelutils.FoldingRangeVisitor
import org.gradle.declarative.lsp.modelutils.LocationMatchingVisitor
import org.gradle.declarative.lsp.modelutils.visit
import org.gradle.declarative.lsp.visitor.FoldingRangeVisitor
import org.gradle.declarative.lsp.visitor.LocationMatchingVisitor
import org.gradle.declarative.lsp.visitor.visit
import org.gradle.declarative.lsp.storage.VersionedDocumentStore
import org.gradle.internal.declarativedsl.dom.DeclarativeDocument
import org.gradle.internal.declarativedsl.evaluator.main.AnalysisDocumentUtils
import org.gradle.internal.declarativedsl.evaluator.main.SimpleAnalysisEvaluator
Expand All @@ -17,7 +18,7 @@ import java.util.concurrent.CompletableFuture

class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware {

private val domStore = mutableMapOf<String, DeclarativeDocument>()
private val documentStore = VersionedDocumentStore()

private lateinit var client: LanguageClient
private lateinit var resources: ResolvedDeclarativeResourcesModel
Expand All @@ -27,6 +28,8 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware
this.client = client!!
}

// LSP Functions ----------------------------------------------------------

fun setResources(resources: ResolvedDeclarativeResourcesModel) {
this.resources = resources
schemaEvaluator = SimpleAnalysisEvaluator.withSchema(
Expand All @@ -36,26 +39,27 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware

override fun didOpen(params: DidOpenTextDocumentParams?) {
params?.textDocument?.uri?.let { uri ->
URI(uri)
}?.let { uri ->
System.err.println("Opened document: $uri")
System.err.println("Parsing declarative model for document: $uri")

val file = File(URI.create(uri))
val fileSchema = schemaEvaluator.evaluate(file.name, file.readText())
val settingsSchema = schemaEvaluator.evaluate(
resources.settingsFile.name, resources.settingsFile.readText()
)

System.err.println("Parsed declarative model for document: $uri")
AnalysisDocumentUtils.documentWithConventions(settingsSchema, fileSchema)?.let {
domStore[uri] = it.document
}

val text = File(uri).readText()
documentStore.storeInitial(uri, parse(uri, text))
System.err.println("Stored declarative model for document: $uri")
}
}

override fun didChange(params: DidChangeTextDocumentParams?) {
System.err.println("Changed document: ${params?.textDocument?.uri}")
params?.let { nonNullParams ->
val uri = URI(nonNullParams.textDocument.uri)
nonNullParams.contentChanges.forEach { change ->
documentStore.storeVersioned(
uri,
nonNullParams.textDocument.version,
parse(uri, change.text)
)
}
System.err.println("Changed document: ${params.textDocument?.uri}")
}
}

override fun didClose(params: DidCloseTextDocumentParams?) {
Expand All @@ -68,7 +72,8 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware

override fun hover(params: HoverParams?): CompletableFuture<Hover> {
val hover = params?.let { nonNullParams ->
withDom(nonNullParams.textDocument) { dom ->
val uri = URI(nonNullParams.textDocument.uri)
withDom(uri) { dom ->
val position = nonNullParams.position

// LSPs are supplying 0-based line and column numbers, while the DSL model is 1-based
Expand Down Expand Up @@ -106,20 +111,34 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware

override fun foldingRange(params: FoldingRangeRequestParams?): CompletableFuture<MutableList<FoldingRange>> {
System.err.println("Asking for folding ranges")
val foldingRanges = withDom(params?.textDocument) { dom ->
val visitor = FoldingRangeVisitor()
dom.visit(visitor)
visitor.foldingRanges
params?.let { nonNullParams ->
val uri = URI(nonNullParams.textDocument.uri)
val foldingRanges = withDom(uri) { dom ->
val visitor = FoldingRangeVisitor()
dom.visit(visitor)
visitor.foldingRanges
}
return CompletableFuture.completedFuture(foldingRanges)
}
return CompletableFuture.completedFuture(foldingRanges)
return CompletableFuture.completedFuture(mutableListOf())
}

private fun <T> withDom(textDocument: TextDocumentIdentifier?, work: (DeclarativeDocument) -> T): T? =
textDocument?.uri?.let {
val dom = domStore[it]
dom?.let {
work.invoke(dom)
}
}
// Utility and other member functions -------------------------------------

private fun parse(uri: URI, text: String): DeclarativeDocument {
val fileName = uri.path.substringAfterLast('/')
val fileSchema = schemaEvaluator.evaluate(fileName, text)
val settingsSchema = schemaEvaluator.evaluate(
resources.settingsFile.name, resources.settingsFile.readText()
)

System.err.println("Parsed declarative model for document: $uri")
return AnalysisDocumentUtils.documentWithConventions(settingsSchema, fileSchema)!!.document
}

private fun <T> withDom(uri: URI, work: (DeclarativeDocument) -> T): T? {
return documentStore[uri]?.let { document ->
work(document)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.gradle.declarative.lsp.server
package org.gradle.declarative.lsp

import org.eclipse.lsp4j.DidChangeConfigurationParams
import org.eclipse.lsp4j.DidChangeWatchedFilesParams
import org.eclipse.lsp4j.services.LanguageClient
import org.eclipse.lsp4j.services.LanguageClientAware
import org.eclipse.lsp4j.services.WorkspaceService
import org.gradle.declarative.dsl.tooling.models.DeclarativeSchemaModel

class DeclarativeWorkspaceService(): WorkspaceService, LanguageClientAware {

Expand Down
1 change: 0 additions & 1 deletion lsp/src/main/kotlin/org/gradle/declarative/lsp/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package org.gradle.declarative.lsp

import org.eclipse.lsp4j.launch.LSPLauncher
import org.gradle.declarative.lsp.server.DeclarativeLanguageServer

fun main() {
val languageServer = DeclarativeLanguageServer()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.gradle.declarative.lsp.logging

import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.AppenderBase
import org.eclipse.lsp4j.MessageParams
import org.eclipse.lsp4j.MessageType
import org.eclipse.lsp4j.services.LanguageClient

class LspAppender(private val client: LanguageClient): AppenderBase<ILoggingEvent>() {

override fun append(eventObject: ILoggingEvent?) {
eventObject?.let {
val message = it.formattedMessage
val type = when(it.level.toInt()) {
10000 -> MessageType.Error
20000 -> MessageType.Warning
30000 -> MessageType.Info
else -> MessageType.Log
}

val messageParams = MessageParams(type, message)
client.logMessage(messageParams)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.gradle.declarative.lsp.storage

import org.gradle.internal.declarativedsl.dom.DeclarativeDocument
import java.net.URI

class VersionedDocumentStore {

private val store = mutableMapOf<URI, DocumentStoreEntry>()

operator fun get(uri: URI): DeclarativeDocument? {
return store[uri]?.document
}

fun storeInitial(uri: URI, document: DeclarativeDocument) {
store(uri, DocumentStoreEntry.Initial(document))
}

fun storeVersioned(uri: URI, version: Int, document: DeclarativeDocument) {
store(uri, DocumentStoreEntry.Versioned(version, document))
}

/**
* Stores a versioned document.
* If the document is already stored, the version must be greater than the stored version.
*
* @return `true` if the document was stored, `false` otherwise.
*/
private fun store(uri: URI, entry: DocumentStoreEntry) {
return when (val storedEntry = store[uri]) {
null -> store[uri] = entry
is DocumentStoreEntry.Initial -> {
when (entry) {
is DocumentStoreEntry.Initial -> throw IllegalArgumentException("Cannot store an initial document when an initial document is already stored.")
is DocumentStoreEntry.Versioned -> store[uri] = entry
}
}

is DocumentStoreEntry.Versioned -> {
when (entry) {
is DocumentStoreEntry.Initial -> throw IllegalArgumentException("Cannot store an initial document when a versioned document is already stored.")
is DocumentStoreEntry.Versioned -> {
if (storedEntry.version >= entry.version) {
store[uri] = entry
} else {
throw IllegalArgumentException("Cannot store a versioned document with a version less than the stored version.")
}
}
}
}
}
}
}

sealed class DocumentStoreEntry {
abstract val document: DeclarativeDocument

data class Initial(override val document: DeclarativeDocument) : DocumentStoreEntry()
data class Versioned(val version: Int, override val document: DeclarativeDocument) : DocumentStoreEntry()
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.gradle.declarative.lsp.tooling
package org.gradle.declarative.lsp.tapi

import org.gradle.declarative.lsp.build.action.GetDeclarativeResourcesModel
import org.gradle.declarative.lsp.build.model.ResolvedDeclarativeResourcesModel
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.gradle.declarative.lsp.modelutils
package org.gradle.declarative.lsp.visitor

import org.gradle.internal.declarativedsl.dom.DeclarativeDocument
import org.gradle.internal.declarativedsl.dom.DocumentNodeContainer


/**
* Classic visitor for visiting nodes in a DeclarativeDocument.
*/
open class DocumentNodeVisitor {

open fun visitNode(node: DeclarativeDocument.Node) {}
Expand All @@ -23,7 +25,10 @@ open class DocumentNodeVisitor {
open fun visitValueFactoryNode(node: DeclarativeDocument.ValueNode.ValueFactoryNode) {}
}

// Extend the DocumentNode with a visitor pattern
/**
* Extension function to visit all nodes in a DeclarativeDocument.
* In order to use this, implement a subclass of [DocumentNodeVisitor] and override the methods you need to do the analysis.
*/
fun DeclarativeDocument.visit(visitor: DocumentNodeVisitor) {
// Initialize the list of nodes to visit with the root nodes of the forest
val nodesToVisit = this.content.toMutableList()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.gradle.declarative.lsp.modelutils
package org.gradle.declarative.lsp.visitor

import org.eclipse.lsp4j.FoldingRange
import org.eclipse.lsp4j.FoldingRangeKind
Expand All @@ -12,7 +12,7 @@ class FoldingRangeVisitor: DocumentNodeVisitor() {
val range = FoldingRange(
// 1-based to 0-based
node.sourceData.lineRange.first - 1,
// 1-based to 0-based, but DCL is inclusive and LSP is exclusive (hence nothing)
// 1-based to 0-based, but DCL is inclusive and LSP is exclusive (hence we subtract 0)
node.sourceData.lineRange.last,
).apply {
kind = FoldingRangeKind.Region
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.gradle.declarative.lsp.modelutils
package org.gradle.declarative.lsp.visitor

import org.gradle.internal.declarativedsl.dom.DeclarativeDocument

Expand Down
13 changes: 13 additions & 0 deletions lsp/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
<target>System.err</target>
<encoder>
<pattern>%date [%thread] - 5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<logger name="org.apache" level="INFO ">
<appender-ref ref="STDERR"/>
</logger>
</configuration>

0 comments on commit 4e8982e

Please sign in to comment.