@@ -15,6 +15,9 @@ import langoustine.lsp.runtime.uinteger
1515
1616import cats .syntax .all .*
1717import langoustine .lsp .app .LangoustineApp
18+ import langoustine .lsp .tools .SemanticTokensEncoder
19+ import langoustine .lsp .tools .SemanticToken
20+ import cats .effect .std .Semaphore
1821
1922object LSP extends LangoustineApp :
2023 import QuickmaffsLSP .{server , State }
@@ -85,10 +88,9 @@ object QuickmaffsLSP:
8588 processFile(Path (path))
8689
8790 def set (u : DocumentUri )(st : State ) =
88- state.update(_.updated(u, st)) <*
89- cats.effect.std
90- .Console [IO ]
91- .errorln(s " Setting $st for $u" )
91+ state.update(_.updated(u, st)) <* IO .consoleForIO.errorln(
92+ s " State update: $u is set to ${st.getClass}"
93+ )
9294
9395 def get (u : DocumentUri ) =
9496 state.get.map(_.get(u))
@@ -150,6 +152,15 @@ object QuickmaffsLSP:
150152 case _ => None
151153 }
152154
155+ val encoder = SemanticTokensEncoder (
156+ tokenTypes = Vector (
157+ SemanticTokenTypes .variable,
158+ SemanticTokenTypes .number,
159+ SemanticTokenTypes .operator
160+ ),
161+ modifiers = Vector .empty
162+ )
163+
153164 LSPBuilder
154165 .create[IO ]
155166 .handleRequest(initialize) { (in, back) =>
@@ -167,6 +178,12 @@ object QuickmaffsLSP:
167178 definitionProvider = Opt (true ),
168179 documentSymbolProvider = Opt (true ),
169180 renameProvider = Opt (true ),
181+ semanticTokensProvider = Opt (
182+ SemanticTokensOptions (
183+ legend = encoder.legend,
184+ full = Opt (true )
185+ )
186+ ),
170187 textDocumentSync = Opt (
171188 TextDocumentSyncOptions (
172189 openClose = Opt (true ),
@@ -187,6 +204,72 @@ object QuickmaffsLSP:
187204 .handleNotification(textDocument.didSave) { (in, back) =>
188205 recompile(in.textDocument.uri, back)
189206 }
207+ .handleRequest(textDocument.semanticTokens.full) { (in, back) =>
208+ get(in.textDocument.uri).flatMap {
209+ case Some (State .Ok (idx, values, program)) =>
210+ val tokens = Vector .newBuilder[SemanticToken ]
211+ program.statements.map(_.value).foreach { st =>
212+ st match
213+ case Statement .Ass (name, e) =>
214+ inline def nameToken (tok : Expr .Name [WithSpan ]) =
215+ tokenFromSpan(tok.value.span, SemanticTokenTypes .variable)
216+
217+ inline def tokenFromSpan (
218+ span : Span ,
219+ tpe : SemanticTokenTypes
220+ ) =
221+ SemanticToken .fromRange(
222+ span.toRange,
223+ tokenType = tpe
224+ )
225+
226+ tokens += nameToken(name)
227+
228+ def go (expr : Expr [WithSpan ]): Unit =
229+ expr match
230+ case Expr .Add (l, r, operator) =>
231+ go(l)
232+ go(r)
233+ tokens += tokenFromSpan(
234+ operator.span,
235+ SemanticTokenTypes .operator
236+ )
237+
238+ case Expr .Mul (l, r, operator) =>
239+ go(l)
240+ go(r)
241+ tokens += tokenFromSpan(
242+ operator.span,
243+ SemanticTokenTypes .operator
244+ )
245+
246+ case n @ Expr .Name (_) =>
247+ tokens += nameToken(n)
248+
249+ case Expr .Lit (value) =>
250+ tokens += tokenFromSpan(
251+ value.span,
252+ SemanticTokenTypes .number
253+ )
254+
255+ go(e)
256+ }
257+
258+ IO .consoleForIO
259+ .errorln(
260+ s " Sending over the following tokens: ${tokens.result().map(_.toString)}"
261+ ) *>
262+ IO .fromEither(encoder.encode(tokens.result())).map(Opt (_))
263+
264+ case other =>
265+ IO .consoleForIO
266+ .errorln(
267+ s " Got weird state for ${in.textDocument.uri}: $other"
268+ )
269+ .as(Opt .empty)
270+
271+ }
272+ }
190273 .handleRequest(textDocument.definition) { (in, back) =>
191274 variableUnderCursor(in.textDocument.uri, in.position).map {
192275 foundMaybe =>
0 commit comments