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 ¶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
onInitialize(const InitializeParams & params,Callback<llvm::json::Value> reply)118 void LSPServer::onInitialize(const InitializeParams ¶ms,
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 ¶ms) {
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 ¶ms) {
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 ¶ms) {
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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 ¶ms,
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