xref: /llvm-project/mlir/lib/Tools/tblgen-lsp-server/LSPServer.cpp (revision a8c88de0dff865d1969b654bb5c0df181aa2df6a)
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 &params,
35                     Callback<llvm::json::Value> reply);
36   void onInitialized(const InitializedParams &params);
37   void onShutdown(const NoParams &params, Callback<std::nullptr_t> reply);
38 
39   //===--------------------------------------------------------------------===//
40   // Document Change
41 
42   void onDocumentDidOpen(const DidOpenTextDocumentParams &params);
43   void onDocumentDidClose(const DidCloseTextDocumentParams &params);
44   void onDocumentDidChange(const DidChangeTextDocumentParams &params);
45 
46   //===--------------------------------------------------------------------===//
47   // Definitions and References
48 
49   void onGoToDefinition(const TextDocumentPositionParams &params,
50                         Callback<std::vector<Location>> reply);
51   void onReference(const ReferenceParams &params,
52                    Callback<std::vector<Location>> reply);
53 
54   //===----------------------------------------------------------------------===//
55   // DocumentLink
56 
57   void onDocumentLink(const DocumentLinkParams &params,
58                       Callback<std::vector<DocumentLink>> reply);
59 
60   //===--------------------------------------------------------------------===//
61   // Hover
62 
63   void onHover(const TextDocumentPositionParams &params,
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 &params,
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 &params) {
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 &params) {
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 &params) {
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 &params,
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 &params,
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 &params,
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 &params,
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