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