1 //===- LSPServer.cpp - TableGen 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 "TableGenServer.h"
12 #include "mlir/Tools/lsp-server-support/Logging.h"
13 #include "mlir/Tools/lsp-server-support/Protocol.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 using namespace mlir;
20 using namespace mlir::lsp;
21
22 //===----------------------------------------------------------------------===//
23 // LSPServer
24 //===----------------------------------------------------------------------===//
25
26 namespace {
27 struct LSPServer {
LSPServer__anonbf2586cd0111::LSPServer28 LSPServer(TableGenServer &server, JSONTransport &transport)
29 : server(server), transport(transport) {}
30
31 //===--------------------------------------------------------------------===//
32 // Initialization
33
34 void onInitialize(const InitializeParams ¶ms,
35 Callback<llvm::json::Value> reply);
36 void onInitialized(const InitializedParams ¶ms);
37 void onShutdown(const NoParams ¶ms, Callback<std::nullptr_t> reply);
38
39 //===--------------------------------------------------------------------===//
40 // Document Change
41
42 void onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms);
43 void onDocumentDidClose(const DidCloseTextDocumentParams ¶ms);
44 void onDocumentDidChange(const DidChangeTextDocumentParams ¶ms);
45
46 //===--------------------------------------------------------------------===//
47 // Definitions and References
48
49 void onGoToDefinition(const TextDocumentPositionParams ¶ms,
50 Callback<std::vector<Location>> reply);
51 void onReference(const ReferenceParams ¶ms,
52 Callback<std::vector<Location>> reply);
53
54 //===----------------------------------------------------------------------===//
55 // DocumentLink
56
57 void onDocumentLink(const DocumentLinkParams ¶ms,
58 Callback<std::vector<DocumentLink>> reply);
59
60 //===--------------------------------------------------------------------===//
61 // Hover
62
63 void onHover(const TextDocumentPositionParams ¶ms,
64 Callback<std::optional<Hover>> reply);
65
66 //===--------------------------------------------------------------------===//
67 // Fields
68 //===--------------------------------------------------------------------===//
69
70 TableGenServer &server;
71 JSONTransport &transport;
72
73 /// An outgoing notification used to send diagnostics to the client when they
74 /// are ready to be processed.
75 OutgoingNotification<PublishDiagnosticsParams> publishDiagnostics;
76
77 /// Used to indicate that the 'shutdown' request was received from the
78 /// Language Server client.
79 bool shutdownRequestReceived = false;
80 };
81 } // namespace
82
83 //===----------------------------------------------------------------------===//
84 // Initialization
85
onInitialize(const InitializeParams & params,Callback<llvm::json::Value> reply)86 void LSPServer::onInitialize(const InitializeParams ¶ms,
87 Callback<llvm::json::Value> reply) {
88 // Send a response with the capabilities of this server.
89 llvm::json::Object serverCaps{
90 {"textDocumentSync",
91 llvm::json::Object{
92 {"openClose", true},
93 {"change", (int)TextDocumentSyncKind::Incremental},
94 {"save", true},
95 }},
96 {"definitionProvider", true},
97 {"referencesProvider", true},
98 {"documentLinkProvider",
99 llvm::json::Object{
100 {"resolveProvider", false},
101 }},
102 {"hoverProvider", true},
103 };
104
105 llvm::json::Object result{
106 {{"serverInfo", llvm::json::Object{{"name", "tblgen-lsp-server"},
107 {"version", "0.0.1"}}},
108 {"capabilities", std::move(serverCaps)}}};
109 reply(std::move(result));
110 }
onInitialized(const InitializedParams &)111 void LSPServer::onInitialized(const InitializedParams &) {}
onShutdown(const NoParams &,Callback<std::nullptr_t> reply)112 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
113 shutdownRequestReceived = true;
114 reply(nullptr);
115 }
116
117 //===----------------------------------------------------------------------===//
118 // Document Change
119
onDocumentDidOpen(const DidOpenTextDocumentParams & params)120 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms) {
121 PublishDiagnosticsParams diagParams(params.textDocument.uri,
122 params.textDocument.version);
123 server.addDocument(params.textDocument.uri, params.textDocument.text,
124 params.textDocument.version, diagParams.diagnostics);
125
126 // Publish any recorded diagnostics.
127 publishDiagnostics(diagParams);
128 }
onDocumentDidClose(const DidCloseTextDocumentParams & params)129 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams ¶ms) {
130 std::optional<int64_t> version =
131 server.removeDocument(params.textDocument.uri);
132 if (!version)
133 return;
134
135 // Empty out the diagnostics shown for this document. This will clear out
136 // anything currently displayed by the client for this document (e.g. in the
137 // "Problems" pane of VSCode).
138 publishDiagnostics(
139 PublishDiagnosticsParams(params.textDocument.uri, *version));
140 }
onDocumentDidChange(const DidChangeTextDocumentParams & params)141 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams ¶ms) {
142 PublishDiagnosticsParams diagParams(params.textDocument.uri,
143 params.textDocument.version);
144 server.updateDocument(params.textDocument.uri, params.contentChanges,
145 params.textDocument.version, diagParams.diagnostics);
146
147 // Publish any recorded diagnostics.
148 publishDiagnostics(diagParams);
149 }
150
151 //===----------------------------------------------------------------------===//
152 // Definitions and References
153
onGoToDefinition(const TextDocumentPositionParams & params,Callback<std::vector<Location>> reply)154 void LSPServer::onGoToDefinition(const TextDocumentPositionParams ¶ms,
155 Callback<std::vector<Location>> reply) {
156 std::vector<Location> locations;
157 server.getLocationsOf(params.textDocument.uri, params.position, locations);
158 reply(std::move(locations));
159 }
160
onReference(const ReferenceParams & params,Callback<std::vector<Location>> reply)161 void LSPServer::onReference(const ReferenceParams ¶ms,
162 Callback<std::vector<Location>> reply) {
163 std::vector<Location> locations;
164 server.findReferencesOf(params.textDocument.uri, params.position, locations);
165 reply(std::move(locations));
166 }
167
168 //===----------------------------------------------------------------------===//
169 // DocumentLink
170
onDocumentLink(const DocumentLinkParams & params,Callback<std::vector<DocumentLink>> reply)171 void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms,
172 Callback<std::vector<DocumentLink>> reply) {
173 std::vector<DocumentLink> links;
174 server.getDocumentLinks(params.textDocument.uri, links);
175 reply(std::move(links));
176 }
177
178 //===----------------------------------------------------------------------===//
179 // Hover
180
onHover(const TextDocumentPositionParams & params,Callback<std::optional<Hover>> reply)181 void LSPServer::onHover(const TextDocumentPositionParams ¶ms,
182 Callback<std::optional<Hover>> reply) {
183 reply(server.findHover(params.textDocument.uri, params.position));
184 }
185
186 //===----------------------------------------------------------------------===//
187 // Entry Point
188 //===----------------------------------------------------------------------===//
189
runTableGenLSPServer(TableGenServer & server,JSONTransport & transport)190 LogicalResult mlir::lsp::runTableGenLSPServer(TableGenServer &server,
191 JSONTransport &transport) {
192 LSPServer lspServer(server, transport);
193 MessageHandler messageHandler(transport);
194
195 // Initialization
196 messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize);
197 messageHandler.notification("initialized", &lspServer,
198 &LSPServer::onInitialized);
199 messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown);
200
201 // Document Changes
202 messageHandler.notification("textDocument/didOpen", &lspServer,
203 &LSPServer::onDocumentDidOpen);
204 messageHandler.notification("textDocument/didClose", &lspServer,
205 &LSPServer::onDocumentDidClose);
206 messageHandler.notification("textDocument/didChange", &lspServer,
207 &LSPServer::onDocumentDidChange);
208
209 // Definitions and References
210 messageHandler.method("textDocument/definition", &lspServer,
211 &LSPServer::onGoToDefinition);
212 messageHandler.method("textDocument/references", &lspServer,
213 &LSPServer::onReference);
214
215 // Document Link
216 messageHandler.method("textDocument/documentLink", &lspServer,
217 &LSPServer::onDocumentLink);
218
219 // Hover
220 messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover);
221
222 // Diagnostics
223 lspServer.publishDiagnostics =
224 messageHandler.outgoingNotification<PublishDiagnosticsParams>(
225 "textDocument/publishDiagnostics");
226
227 // Run the main loop of the transport.
228 if (llvm::Error error = transport.run(messageHandler)) {
229 Logger::error("Transport error: {0}", error);
230 llvm::consumeError(std::move(error));
231 return failure();
232 }
233 return success(lspServer.shutdownRequestReceived);
234 }
235