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