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 {
29   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   // PDLL View Output
87 
88   void onPDLLViewOutput(const PDLLViewOutputParams &params,
89                         Callback<Optional<PDLLViewOutputResult>> reply);
90 
91   //===--------------------------------------------------------------------===//
92   // Fields
93   //===--------------------------------------------------------------------===//
94 
95   PDLLServer &server;
96   JSONTransport &transport;
97 
98   /// An outgoing notification used to send diagnostics to the client when they
99   /// are ready to be processed.
100   OutgoingNotification<PublishDiagnosticsParams> publishDiagnostics;
101 
102   /// Used to indicate that the 'shutdown' request was received from the
103   /// Language Server client.
104   bool shutdownRequestReceived = false;
105 };
106 } // namespace
107 
108 //===----------------------------------------------------------------------===//
109 // Initialization
110 
111 void LSPServer::onInitialize(const InitializeParams &params,
112                              Callback<llvm::json::Value> reply) {
113   // Send a response with the capabilities of this server.
114   llvm::json::Object serverCaps{
115       {"textDocumentSync",
116        llvm::json::Object{
117            {"openClose", true},
118            {"change", (int)TextDocumentSyncKind::Full},
119            {"save", true},
120        }},
121       {"completionProvider",
122        llvm::json::Object{
123            {"allCommitCharacters",
124             {"\t", "(", ")", "[", "]", "{",  "}", "<", ">",
125              ":",  ";", ",", "+", "-", "/",  "*", "%", "^",
126              "&",  "#", "?", ".", "=", "\"", "'", "|"}},
127            {"resolveProvider", false},
128            {"triggerCharacters",
129             {".", ">", "(", "{", ",", "<", ":", "[", " ", "\"", "/"}},
130        }},
131       {"signatureHelpProvider",
132        llvm::json::Object{
133            {"triggerCharacters", {"(", ","}},
134        }},
135       {"definitionProvider", true},
136       {"referencesProvider", true},
137       {"documentLinkProvider",
138        llvm::json::Object{
139            {"resolveProvider", false},
140        }},
141       {"hoverProvider", true},
142       {"documentSymbolProvider", true},
143   };
144 
145   llvm::json::Object result{
146       {{"serverInfo", llvm::json::Object{{"name", "mlir-pdll-lsp-server"},
147                                          {"version", "0.0.1"}}},
148        {"capabilities", std::move(serverCaps)}}};
149   reply(std::move(result));
150 }
151 void LSPServer::onInitialized(const InitializedParams &) {}
152 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
153   shutdownRequestReceived = true;
154   reply(nullptr);
155 }
156 
157 //===----------------------------------------------------------------------===//
158 // Document Change
159 
160 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams &params) {
161   PublishDiagnosticsParams diagParams(params.textDocument.uri,
162                                       params.textDocument.version);
163   server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text,
164                              params.textDocument.version,
165                              diagParams.diagnostics);
166 
167   // Publish any recorded diagnostics.
168   publishDiagnostics(diagParams);
169 }
170 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams &params) {
171   Optional<int64_t> version = server.removeDocument(params.textDocument.uri);
172   if (!version)
173     return;
174 
175   // Empty out the diagnostics shown for this document. This will clear out
176   // anything currently displayed by the client for this document (e.g. in the
177   // "Problems" pane of VSCode).
178   publishDiagnostics(
179       PublishDiagnosticsParams(params.textDocument.uri, *version));
180 }
181 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
182   // TODO: We currently only support full document updates, we should refactor
183   // to avoid this.
184   if (params.contentChanges.size() != 1)
185     return;
186   PublishDiagnosticsParams diagParams(params.textDocument.uri,
187                                       params.textDocument.version);
188   server.addOrUpdateDocument(
189       params.textDocument.uri, params.contentChanges.front().text,
190       params.textDocument.version, diagParams.diagnostics);
191 
192   // Publish any recorded diagnostics.
193   publishDiagnostics(diagParams);
194 }
195 
196 //===----------------------------------------------------------------------===//
197 // Definitions and References
198 
199 void LSPServer::onGoToDefinition(const TextDocumentPositionParams &params,
200                                  Callback<std::vector<Location>> reply) {
201   std::vector<Location> locations;
202   server.getLocationsOf(params.textDocument.uri, params.position, locations);
203   reply(std::move(locations));
204 }
205 
206 void LSPServer::onReference(const ReferenceParams &params,
207                             Callback<std::vector<Location>> reply) {
208   std::vector<Location> locations;
209   server.findReferencesOf(params.textDocument.uri, params.position, locations);
210   reply(std::move(locations));
211 }
212 
213 //===----------------------------------------------------------------------===//
214 // DocumentLink
215 
216 void LSPServer::onDocumentLink(const DocumentLinkParams &params,
217                                Callback<std::vector<DocumentLink>> reply) {
218   std::vector<DocumentLink> links;
219   server.getDocumentLinks(params.textDocument.uri, links);
220   reply(std::move(links));
221 }
222 
223 //===----------------------------------------------------------------------===//
224 // Hover
225 
226 void LSPServer::onHover(const TextDocumentPositionParams &params,
227                         Callback<Optional<Hover>> reply) {
228   reply(server.findHover(params.textDocument.uri, params.position));
229 }
230 
231 //===----------------------------------------------------------------------===//
232 // Document Symbols
233 
234 void LSPServer::onDocumentSymbol(const DocumentSymbolParams &params,
235                                  Callback<std::vector<DocumentSymbol>> reply) {
236   std::vector<DocumentSymbol> symbols;
237   server.findDocumentSymbols(params.textDocument.uri, symbols);
238   reply(std::move(symbols));
239 }
240 
241 //===----------------------------------------------------------------------===//
242 // Code Completion
243 
244 void LSPServer::onCompletion(const CompletionParams &params,
245                              Callback<CompletionList> reply) {
246   reply(server.getCodeCompletion(params.textDocument.uri, params.position));
247 }
248 
249 //===----------------------------------------------------------------------===//
250 // Signature Help
251 
252 void LSPServer::onSignatureHelp(const TextDocumentPositionParams &params,
253                                 Callback<SignatureHelp> reply) {
254   reply(server.getSignatureHelp(params.textDocument.uri, params.position));
255 }
256 
257 //===----------------------------------------------------------------------===//
258 // PDLL ViewOutput
259 
260 void LSPServer::onPDLLViewOutput(
261     const PDLLViewOutputParams &params,
262     Callback<Optional<PDLLViewOutputResult>> reply) {
263   reply(server.getPDLLViewOutput(params.uri, params.kind));
264 }
265 
266 //===----------------------------------------------------------------------===//
267 // Entry Point
268 //===----------------------------------------------------------------------===//
269 
270 LogicalResult mlir::lsp::runPdllLSPServer(PDLLServer &server,
271                                           JSONTransport &transport) {
272   LSPServer lspServer(server, transport);
273   MessageHandler messageHandler(transport);
274 
275   // Initialization
276   messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize);
277   messageHandler.notification("initialized", &lspServer,
278                               &LSPServer::onInitialized);
279   messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown);
280 
281   // Document Changes
282   messageHandler.notification("textDocument/didOpen", &lspServer,
283                               &LSPServer::onDocumentDidOpen);
284   messageHandler.notification("textDocument/didClose", &lspServer,
285                               &LSPServer::onDocumentDidClose);
286   messageHandler.notification("textDocument/didChange", &lspServer,
287                               &LSPServer::onDocumentDidChange);
288 
289   // Definitions and References
290   messageHandler.method("textDocument/definition", &lspServer,
291                         &LSPServer::onGoToDefinition);
292   messageHandler.method("textDocument/references", &lspServer,
293                         &LSPServer::onReference);
294 
295   // Document Link
296   messageHandler.method("textDocument/documentLink", &lspServer,
297                         &LSPServer::onDocumentLink);
298 
299   // Hover
300   messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover);
301 
302   // Document Symbols
303   messageHandler.method("textDocument/documentSymbol", &lspServer,
304                         &LSPServer::onDocumentSymbol);
305 
306   // Code Completion
307   messageHandler.method("textDocument/completion", &lspServer,
308                         &LSPServer::onCompletion);
309 
310   // Signature Help
311   messageHandler.method("textDocument/signatureHelp", &lspServer,
312                         &LSPServer::onSignatureHelp);
313 
314   // PDLL ViewOutput
315   messageHandler.method("pdll/viewOutput", &lspServer,
316                         &LSPServer::onPDLLViewOutput);
317 
318   // Diagnostics
319   lspServer.publishDiagnostics =
320       messageHandler.outgoingNotification<PublishDiagnosticsParams>(
321           "textDocument/publishDiagnostics");
322 
323   // Run the main loop of the transport.
324   if (llvm::Error error = transport.run(messageHandler)) {
325     Logger::error("Transport error: {0}", error);
326     llvm::consumeError(std::move(error));
327     return failure();
328   }
329   return success(lspServer.shutdownRequestReceived);
330 }
331