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