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 ¶ms,
36 Callback<llvm::json::Value> reply);
37 void onInitialized(const InitializedParams ¶ms);
38 void onShutdown(const NoParams ¶ms, Callback<std::nullptr_t> reply);
39
40 //===--------------------------------------------------------------------===//
41 // Document Change
42
43 void onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms);
44 void onDocumentDidClose(const DidCloseTextDocumentParams ¶ms);
45 void onDocumentDidChange(const DidChangeTextDocumentParams ¶ms);
46
47 //===--------------------------------------------------------------------===//
48 // Definitions and References
49
50 void onGoToDefinition(const TextDocumentPositionParams ¶ms,
51 Callback<std::vector<Location>> reply);
52 void onReference(const ReferenceParams ¶ms,
53 Callback<std::vector<Location>> reply);
54
55 //===----------------------------------------------------------------------===//
56 // DocumentLink
57
58 void onDocumentLink(const DocumentLinkParams ¶ms,
59 Callback<std::vector<DocumentLink>> reply);
60
61 //===--------------------------------------------------------------------===//
62 // Hover
63
64 void onHover(const TextDocumentPositionParams ¶ms,
65 Callback<Optional<Hover>> reply);
66
67 //===--------------------------------------------------------------------===//
68 // Document Symbols
69
70 void onDocumentSymbol(const DocumentSymbolParams ¶ms,
71 Callback<std::vector<DocumentSymbol>> reply);
72
73 //===--------------------------------------------------------------------===//
74 // Code Completion
75
76 void onCompletion(const CompletionParams ¶ms,
77 Callback<CompletionList> reply);
78
79 //===--------------------------------------------------------------------===//
80 // Signature Help
81
82 void onSignatureHelp(const TextDocumentPositionParams ¶ms,
83 Callback<SignatureHelp> reply);
84
85 //===--------------------------------------------------------------------===//
86 // Inlay Hints
87
88 void onInlayHint(const InlayHintsParams ¶ms,
89 Callback<std::vector<InlayHint>> reply);
90
91 //===--------------------------------------------------------------------===//
92 // PDLL View Output
93
94 void onPDLLViewOutput(const PDLLViewOutputParams ¶ms,
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 ¶ms,
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 ¶ms) {
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 ¶ms) {
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 ¶ms) {
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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