@@ -5,12 +5,12 @@ import org.eclipse.lsp4j.services.LanguageClient
5
5
import org.eclipse.lsp4j.services.LanguageClientAware
6
6
import org.eclipse.lsp4j.services.TextDocumentService
7
7
import org.gradle.declarative.lsp.build.model.ResolvedDeclarativeResourcesModel
8
+ import org.gradle.declarative.lsp.modelutils.FoldingRangeVisitor
9
+ import org.gradle.declarative.lsp.modelutils.LocationMatchingVisitor
10
+ import org.gradle.declarative.lsp.modelutils.visit
8
11
import org.gradle.internal.declarativedsl.dom.DeclarativeDocument
9
- import org.gradle.internal.declarativedsl.dom.DeclarativeDocument.DocumentNode.ElementNode
10
- import org.gradle.internal.declarativedsl.dom.DeclarativeDocument.DocumentNode.PropertyNode
11
12
import org.gradle.internal.declarativedsl.evaluator.main.AnalysisDocumentUtils
12
13
import org.gradle.internal.declarativedsl.evaluator.main.SimpleAnalysisEvaluator
13
- import org.gradle.internal.declarativedsl.language.SourceData
14
14
import java.io.File
15
15
import java.net.URI
16
16
import java.util.concurrent.CompletableFuture
@@ -49,6 +49,7 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware
49
49
AnalysisDocumentUtils .documentWithConventions(settingsSchema, fileSchema)?.let {
50
50
domStore[uri] = it.document
51
51
}
52
+
52
53
System .err.println (" Stored declarative model for document: $uri " )
53
54
}
54
55
}
@@ -66,34 +67,59 @@ class DeclarativeTextDocumentService : TextDocumentService, LanguageClientAware
66
67
}
67
68
68
69
override fun hover (params : HoverParams ? ): CompletableFuture <Hover > {
69
- params?.textDocument?.uri?.let { uri ->
70
- val position = params.position
71
- System .err.println (" Hovering over document: $uri at line ${position.line} column ${position.character} " )
72
-
73
- domStore[uri]?.let {
74
- val closest = findBestFitting(it.content, position)
75
- System .err.println (" Closest node: $closest " )
70
+ val hover = params?.let { nonNullParams ->
71
+ withDom(nonNullParams.textDocument) { dom ->
72
+ val position = nonNullParams.position
73
+
74
+ // LSPs are supplying 0-based line and column numbers, while the DSL model is 1-based
75
+ val visitor = LocationMatchingVisitor (position.line + 1 , position.character + 1 )
76
+ dom.visit(visitor)
77
+
78
+ visitor.matchingNode?.let { node ->
79
+ when (node) {
80
+ is DeclarativeDocument .DocumentNode .PropertyNode -> node.name
81
+ is DeclarativeDocument .DocumentNode .ElementNode -> node.name
82
+ else -> null
83
+ }?.let { name ->
84
+ // We need to convert back the 1-based locations to 0-based ones
85
+ val startPosition = Position (
86
+ node.sourceData.lineRange.first - 1 ,
87
+ node.sourceData.startColumn - 1
88
+ )
89
+ // End position is tricky, as...
90
+ val endPosition = Position (
91
+ node.sourceData.lineRange.last - 1 ,
92
+ // ... the end column is exclusive, so we DON'T need to subtract 1
93
+ node.sourceData.endColumn
94
+ )
95
+
96
+ Hover (
97
+ MarkupContent (" plaintext" , name),
98
+ Range (startPosition, endPosition)
99
+ )
100
+ }
101
+ }
76
102
}
77
103
}
104
+ return CompletableFuture .completedFuture(hover)
105
+ }
78
106
79
- return CompletableFuture ()
107
+ override fun foldingRange (params : FoldingRangeRequestParams ? ): CompletableFuture <MutableList <FoldingRange >> {
108
+ System .err.println (" Asking for folding ranges" )
109
+ val foldingRanges = withDom(params?.textDocument) { dom ->
110
+ val visitor = FoldingRangeVisitor ()
111
+ dom.visit(visitor)
112
+ visitor.foldingRanges
113
+ }
114
+ return CompletableFuture .completedFuture(foldingRanges)
80
115
}
81
116
82
- companion object {
83
- fun findBestFitting (
84
- nodes : List <DeclarativeDocument .DocumentNode >, cursorPosition : Position
85
- ): DeclarativeDocument .DocumentNode ? {
86
- return nodes.firstNotNullOf { node ->
87
- when (node) {
88
- is ElementNode -> findBestFitting(node.content, cursorPosition)
89
- is PropertyNode -> if (cursorIsInside(node.sourceData, cursorPosition)) node else null
90
- else -> null
91
- }
117
+ private fun <T > withDom (textDocument : TextDocumentIdentifier ? , work : (DeclarativeDocument ) -> T ): T ? =
118
+ textDocument?.uri?.let {
119
+ val dom = domStore[it]
120
+ dom?.let {
121
+ work.invoke(dom)
92
122
}
93
123
}
94
124
95
- private fun cursorIsInside (candidatePosition : SourceData , cursorPosition : Position ): Boolean {
96
- return candidatePosition.lineRange.contains(cursorPosition.line) && candidatePosition.startColumn <= cursorPosition.character && candidatePosition.endColumn >= cursorPosition.character
97
- }
98
- }
99
125
}
0 commit comments