1 | //===- LSPServer.cpp - PDLL Language Server -------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "LSPServer.h" |
10 | |
11 | #include "PDLLServer.h" |
12 | #include "Protocol.h" |
13 | #include "mlir/Tools/lsp-server-support/Logging.h" |
14 | #include "mlir/Tools/lsp-server-support/Transport.h" |
15 | #include "llvm/ADT/FunctionExtras.h" |
16 | #include "llvm/ADT/StringMap.h" |
17 | #include <optional> |
18 | |
19 | #define DEBUG_TYPE "pdll-lsp-server" |
20 | |
21 | using namespace mlir; |
22 | using namespace mlir::lsp; |
23 | |
24 | //===----------------------------------------------------------------------===// |
25 | // LSPServer |
26 | //===----------------------------------------------------------------------===// |
27 | |
28 | namespace { |
29 | struct LSPServer { |
30 | LSPServer(PDLLServer &server, JSONTransport &transport) |
31 | : server(server), transport(transport) {} |
32 | |
33 | //===--------------------------------------------------------------------===// |
34 | // Initialization |
35 | |
36 | void onInitialize(const InitializeParams ¶ms, |
37 | Callback<llvm::json::Value> reply); |
38 | void onInitialized(const InitializedParams ¶ms); |
39 | void onShutdown(const NoParams ¶ms, Callback<std::nullptr_t> reply); |
40 | |
41 | //===--------------------------------------------------------------------===// |
42 | // Document Change |
43 | |
44 | void onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms); |
45 | void onDocumentDidClose(const DidCloseTextDocumentParams ¶ms); |
46 | void onDocumentDidChange(const DidChangeTextDocumentParams ¶ms); |
47 | |
48 | //===--------------------------------------------------------------------===// |
49 | // Definitions and References |
50 | |
51 | void onGoToDefinition(const TextDocumentPositionParams ¶ms, |
52 | Callback<std::vector<Location>> reply); |
53 | void onReference(const ReferenceParams ¶ms, |
54 | Callback<std::vector<Location>> reply); |
55 | |
56 | //===----------------------------------------------------------------------===// |
57 | // DocumentLink |
58 | |
59 | void onDocumentLink(const DocumentLinkParams ¶ms, |
60 | Callback<std::vector<DocumentLink>> reply); |
61 | |
62 | //===--------------------------------------------------------------------===// |
63 | // Hover |
64 | |
65 | void onHover(const TextDocumentPositionParams ¶ms, |
66 | Callback<std::optional<Hover>> reply); |
67 | |
68 | //===--------------------------------------------------------------------===// |
69 | // Document Symbols |
70 | |
71 | void onDocumentSymbol(const DocumentSymbolParams ¶ms, |
72 | Callback<std::vector<DocumentSymbol>> reply); |
73 | |
74 | //===--------------------------------------------------------------------===// |
75 | // Code Completion |
76 | |
77 | void onCompletion(const CompletionParams ¶ms, |
78 | Callback<CompletionList> reply); |
79 | |
80 | //===--------------------------------------------------------------------===// |
81 | // Signature Help |
82 | |
83 | void onSignatureHelp(const TextDocumentPositionParams ¶ms, |
84 | Callback<SignatureHelp> reply); |
85 | |
86 | //===--------------------------------------------------------------------===// |
87 | // Inlay Hints |
88 | |
89 | void onInlayHint(const InlayHintsParams ¶ms, |
90 | Callback<std::vector<InlayHint>> reply); |
91 | |
92 | //===--------------------------------------------------------------------===// |
93 | // PDLL View Output |
94 | |
95 | void onPDLLViewOutput(const PDLLViewOutputParams ¶ms, |
96 | Callback<std::optional<PDLLViewOutputResult>> reply); |
97 | |
98 | //===--------------------------------------------------------------------===// |
99 | // Fields |
100 | //===--------------------------------------------------------------------===// |
101 | |
102 | PDLLServer &server; |
103 | JSONTransport &transport; |
104 | |
105 | /// An outgoing notification used to send diagnostics to the client when they |
106 | /// are ready to be processed. |
107 | OutgoingNotification<PublishDiagnosticsParams> publishDiagnostics; |
108 | |
109 | /// Used to indicate that the 'shutdown' request was received from the |
110 | /// Language Server client. |
111 | bool shutdownRequestReceived = false; |
112 | }; |
113 | } // namespace |
114 | |
115 | //===----------------------------------------------------------------------===// |
116 | // Initialization |
117 | //===----------------------------------------------------------------------===// |
118 | |
119 | void LSPServer::onInitialize(const InitializeParams ¶ms, |
120 | Callback<llvm::json::Value> reply) { |
121 | // Send a response with the capabilities of this server. |
122 | llvm::json::Object serverCaps{ |
123 | {.K: "textDocumentSync" , |
124 | .V: llvm::json::Object{ |
125 | {.K: "openClose" , .V: true}, |
126 | {.K: "change" , .V: (int)TextDocumentSyncKind::Incremental}, |
127 | {.K: "save" , .V: true}, |
128 | }}, |
129 | {.K: "completionProvider" , |
130 | .V: llvm::json::Object{ |
131 | {.K: "allCommitCharacters" , |
132 | .V: {"\t" , "(" , ")" , "[" , "]" , "{" , "}" , "<" , ">" , |
133 | ":" , ";" , "," , "+" , "-" , "/" , "*" , "%" , "^" , |
134 | "&" , "#" , "?" , "." , "=" , "\"" , "'" , "|" }}, |
135 | {.K: "resolveProvider" , .V: false}, |
136 | {.K: "triggerCharacters" , |
137 | .V: {"." , ">" , "(" , "{" , "," , "<" , ":" , "[" , " " , "\"" , "/" }}, |
138 | }}, |
139 | {.K: "signatureHelpProvider" , |
140 | .V: llvm::json::Object{ |
141 | {.K: "triggerCharacters" , .V: {"(" , "," }}, |
142 | }}, |
143 | {.K: "definitionProvider" , .V: true}, |
144 | {.K: "referencesProvider" , .V: true}, |
145 | {.K: "documentLinkProvider" , |
146 | .V: llvm::json::Object{ |
147 | {.K: "resolveProvider" , .V: false}, |
148 | }}, |
149 | {.K: "hoverProvider" , .V: true}, |
150 | {.K: "documentSymbolProvider" , .V: true}, |
151 | {.K: "inlayHintProvider" , .V: true}, |
152 | }; |
153 | |
154 | llvm::json::Object result{ |
155 | {{.K: "serverInfo" , .V: llvm::json::Object{{.K: "name" , .V: "mlir-pdll-lsp-server" }, |
156 | {.K: "version" , .V: "0.0.1" }}}, |
157 | {.K: "capabilities" , .V: std::move(serverCaps)}}}; |
158 | reply(std::move(result)); |
159 | } |
160 | void LSPServer::onInitialized(const InitializedParams &) {} |
161 | void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) { |
162 | shutdownRequestReceived = true; |
163 | reply(nullptr); |
164 | } |
165 | |
166 | //===----------------------------------------------------------------------===// |
167 | // Document Change |
168 | //===----------------------------------------------------------------------===// |
169 | |
170 | void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms) { |
171 | PublishDiagnosticsParams diagParams(params.textDocument.uri, |
172 | params.textDocument.version); |
173 | server.addDocument(uri: params.textDocument.uri, contents: params.textDocument.text, |
174 | version: params.textDocument.version, diagnostics&: diagParams.diagnostics); |
175 | |
176 | // Publish any recorded diagnostics. |
177 | publishDiagnostics(diagParams); |
178 | } |
179 | void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams ¶ms) { |
180 | std::optional<int64_t> version = |
181 | server.removeDocument(uri: params.textDocument.uri); |
182 | if (!version) |
183 | return; |
184 | |
185 | // Empty out the diagnostics shown for this document. This will clear out |
186 | // anything currently displayed by the client for this document (e.g. in the |
187 | // "Problems" pane of VSCode). |
188 | publishDiagnostics( |
189 | PublishDiagnosticsParams(params.textDocument.uri, *version)); |
190 | } |
191 | void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams ¶ms) { |
192 | PublishDiagnosticsParams diagParams(params.textDocument.uri, |
193 | params.textDocument.version); |
194 | server.updateDocument(uri: params.textDocument.uri, changes: params.contentChanges, |
195 | version: params.textDocument.version, diagnostics&: diagParams.diagnostics); |
196 | |
197 | // Publish any recorded diagnostics. |
198 | publishDiagnostics(diagParams); |
199 | } |
200 | |
201 | //===----------------------------------------------------------------------===// |
202 | // Definitions and References |
203 | //===----------------------------------------------------------------------===// |
204 | |
205 | void LSPServer::onGoToDefinition(const TextDocumentPositionParams ¶ms, |
206 | Callback<std::vector<Location>> reply) { |
207 | std::vector<Location> locations; |
208 | server.getLocationsOf(uri: params.textDocument.uri, defPos: params.position, locations); |
209 | reply(std::move(locations)); |
210 | } |
211 | |
212 | void LSPServer::onReference(const ReferenceParams ¶ms, |
213 | Callback<std::vector<Location>> reply) { |
214 | std::vector<Location> locations; |
215 | server.findReferencesOf(uri: params.textDocument.uri, pos: params.position, references&: locations); |
216 | reply(std::move(locations)); |
217 | } |
218 | |
219 | //===----------------------------------------------------------------------===// |
220 | // DocumentLink |
221 | //===----------------------------------------------------------------------===// |
222 | |
223 | void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms, |
224 | Callback<std::vector<DocumentLink>> reply) { |
225 | std::vector<DocumentLink> links; |
226 | server.getDocumentLinks(uri: params.textDocument.uri, documentLinks&: links); |
227 | reply(std::move(links)); |
228 | } |
229 | |
230 | //===----------------------------------------------------------------------===// |
231 | // Hover |
232 | //===----------------------------------------------------------------------===// |
233 | |
234 | void LSPServer::onHover(const TextDocumentPositionParams ¶ms, |
235 | Callback<std::optional<Hover>> reply) { |
236 | reply(server.findHover(uri: params.textDocument.uri, hoverPos: params.position)); |
237 | } |
238 | |
239 | //===----------------------------------------------------------------------===// |
240 | // Document Symbols |
241 | //===----------------------------------------------------------------------===// |
242 | |
243 | void LSPServer::onDocumentSymbol(const DocumentSymbolParams ¶ms, |
244 | Callback<std::vector<DocumentSymbol>> reply) { |
245 | std::vector<DocumentSymbol> symbols; |
246 | server.findDocumentSymbols(uri: params.textDocument.uri, symbols); |
247 | reply(std::move(symbols)); |
248 | } |
249 | |
250 | //===----------------------------------------------------------------------===// |
251 | // Code Completion |
252 | //===----------------------------------------------------------------------===// |
253 | |
254 | void LSPServer::onCompletion(const CompletionParams ¶ms, |
255 | Callback<CompletionList> reply) { |
256 | reply(server.getCodeCompletion(uri: params.textDocument.uri, completePos: params.position)); |
257 | } |
258 | |
259 | //===----------------------------------------------------------------------===// |
260 | // Signature Help |
261 | //===----------------------------------------------------------------------===// |
262 | |
263 | void LSPServer::onSignatureHelp(const TextDocumentPositionParams ¶ms, |
264 | Callback<SignatureHelp> reply) { |
265 | reply(server.getSignatureHelp(uri: params.textDocument.uri, helpPos: params.position)); |
266 | } |
267 | |
268 | //===----------------------------------------------------------------------===// |
269 | // Inlay Hints |
270 | //===----------------------------------------------------------------------===// |
271 | |
272 | void LSPServer::onInlayHint(const InlayHintsParams ¶ms, |
273 | Callback<std::vector<InlayHint>> reply) { |
274 | std::vector<InlayHint> hints; |
275 | server.getInlayHints(uri: params.textDocument.uri, range: params.range, inlayHints&: hints); |
276 | reply(std::move(hints)); |
277 | } |
278 | |
279 | //===----------------------------------------------------------------------===// |
280 | // PDLL ViewOutput |
281 | //===----------------------------------------------------------------------===// |
282 | |
283 | void LSPServer::onPDLLViewOutput( |
284 | const PDLLViewOutputParams ¶ms, |
285 | Callback<std::optional<PDLLViewOutputResult>> reply) { |
286 | reply(server.getPDLLViewOutput(uri: params.uri, kind: params.kind)); |
287 | } |
288 | |
289 | //===----------------------------------------------------------------------===// |
290 | // Entry Point |
291 | //===----------------------------------------------------------------------===// |
292 | |
293 | LogicalResult mlir::lsp::runPdllLSPServer(PDLLServer &server, |
294 | JSONTransport &transport) { |
295 | LSPServer lspServer(server, transport); |
296 | MessageHandler messageHandler(transport); |
297 | |
298 | // Initialization |
299 | messageHandler.method(method: "initialize" , thisPtr: &lspServer, handler: &LSPServer::onInitialize); |
300 | messageHandler.notification(method: "initialized" , thisPtr: &lspServer, |
301 | handler: &LSPServer::onInitialized); |
302 | messageHandler.method(method: "shutdown" , thisPtr: &lspServer, handler: &LSPServer::onShutdown); |
303 | |
304 | // Document Changes |
305 | messageHandler.notification(method: "textDocument/didOpen" , thisPtr: &lspServer, |
306 | handler: &LSPServer::onDocumentDidOpen); |
307 | messageHandler.notification(method: "textDocument/didClose" , thisPtr: &lspServer, |
308 | handler: &LSPServer::onDocumentDidClose); |
309 | messageHandler.notification(method: "textDocument/didChange" , thisPtr: &lspServer, |
310 | handler: &LSPServer::onDocumentDidChange); |
311 | |
312 | // Definitions and References |
313 | messageHandler.method(method: "textDocument/definition" , thisPtr: &lspServer, |
314 | handler: &LSPServer::onGoToDefinition); |
315 | messageHandler.method(method: "textDocument/references" , thisPtr: &lspServer, |
316 | handler: &LSPServer::onReference); |
317 | |
318 | // Document Link |
319 | messageHandler.method(method: "textDocument/documentLink" , thisPtr: &lspServer, |
320 | handler: &LSPServer::onDocumentLink); |
321 | |
322 | // Hover |
323 | messageHandler.method(method: "textDocument/hover" , thisPtr: &lspServer, handler: &LSPServer::onHover); |
324 | |
325 | // Document Symbols |
326 | messageHandler.method(method: "textDocument/documentSymbol" , thisPtr: &lspServer, |
327 | handler: &LSPServer::onDocumentSymbol); |
328 | |
329 | // Code Completion |
330 | messageHandler.method(method: "textDocument/completion" , thisPtr: &lspServer, |
331 | handler: &LSPServer::onCompletion); |
332 | |
333 | // Signature Help |
334 | messageHandler.method(method: "textDocument/signatureHelp" , thisPtr: &lspServer, |
335 | handler: &LSPServer::onSignatureHelp); |
336 | |
337 | // Inlay Hints |
338 | messageHandler.method(method: "textDocument/inlayHint" , thisPtr: &lspServer, |
339 | handler: &LSPServer::onInlayHint); |
340 | |
341 | // PDLL ViewOutput |
342 | messageHandler.method(method: "pdll/viewOutput" , thisPtr: &lspServer, |
343 | handler: &LSPServer::onPDLLViewOutput); |
344 | |
345 | // Diagnostics |
346 | lspServer.publishDiagnostics = |
347 | messageHandler.outgoingNotification<PublishDiagnosticsParams>( |
348 | method: "textDocument/publishDiagnostics" ); |
349 | |
350 | // Run the main loop of the transport. |
351 | if (llvm::Error error = transport.run(handler&: messageHandler)) { |
352 | Logger::error(fmt: "Transport error: {0}" , vals&: error); |
353 | llvm::consumeError(Err: std::move(error)); |
354 | return failure(); |
355 | } |
356 | return success(IsSuccess: lspServer.shutdownRequestReceived); |
357 | } |
358 | |