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
19using namespace mlir;
20using namespace mlir::lsp;
21
22//===----------------------------------------------------------------------===//
23// LSPServer
24//===----------------------------------------------------------------------===//
25
26namespace {
27struct LSPServer {
28 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//===----------------------------------------------------------------------===//
86
87void LSPServer::onInitialize(const InitializeParams &params,
88 Callback<llvm::json::Value> reply) {
89 // Send a response with the capabilities of this server.
90 llvm::json::Object serverCaps{
91 {.K: "textDocumentSync",
92 .V: llvm::json::Object{
93 {.K: "openClose", .V: true},
94 {.K: "change", .V: (int)TextDocumentSyncKind::Incremental},
95 {.K: "save", .V: true},
96 }},
97 {.K: "definitionProvider", .V: true},
98 {.K: "referencesProvider", .V: true},
99 {.K: "documentLinkProvider",
100 .V: llvm::json::Object{
101 {.K: "resolveProvider", .V: false},
102 }},
103 {.K: "hoverProvider", .V: true},
104 };
105
106 llvm::json::Object result{
107 {{.K: "serverInfo", .V: llvm::json::Object{{.K: "name", .V: "tblgen-lsp-server"},
108 {.K: "version", .V: "0.0.1"}}},
109 {.K: "capabilities", .V: std::move(serverCaps)}}};
110 reply(std::move(result));
111}
112void LSPServer::onInitialized(const InitializedParams &) {}
113void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) {
114 shutdownRequestReceived = true;
115 reply(nullptr);
116}
117
118//===----------------------------------------------------------------------===//
119// Document Change
120//===----------------------------------------------------------------------===//
121
122void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams &params) {
123 PublishDiagnosticsParams diagParams(params.textDocument.uri,
124 params.textDocument.version);
125 server.addDocument(uri: params.textDocument.uri, contents: params.textDocument.text,
126 version: params.textDocument.version, diagnostics&: diagParams.diagnostics);
127
128 // Publish any recorded diagnostics.
129 publishDiagnostics(diagParams);
130}
131void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams &params) {
132 std::optional<int64_t> version =
133 server.removeDocument(uri: params.textDocument.uri);
134 if (!version)
135 return;
136
137 // Empty out the diagnostics shown for this document. This will clear out
138 // anything currently displayed by the client for this document (e.g. in the
139 // "Problems" pane of VSCode).
140 publishDiagnostics(
141 PublishDiagnosticsParams(params.textDocument.uri, *version));
142}
143void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams &params) {
144 PublishDiagnosticsParams diagParams(params.textDocument.uri,
145 params.textDocument.version);
146 server.updateDocument(uri: params.textDocument.uri, changes: params.contentChanges,
147 version: params.textDocument.version, diagnostics&: diagParams.diagnostics);
148
149 // Publish any recorded diagnostics.
150 publishDiagnostics(diagParams);
151}
152
153//===----------------------------------------------------------------------===//
154// Definitions and References
155//===----------------------------------------------------------------------===//
156
157void LSPServer::onGoToDefinition(const TextDocumentPositionParams &params,
158 Callback<std::vector<Location>> reply) {
159 std::vector<Location> locations;
160 server.getLocationsOf(uri: params.textDocument.uri, defPos: params.position, locations);
161 reply(std::move(locations));
162}
163
164void LSPServer::onReference(const ReferenceParams &params,
165 Callback<std::vector<Location>> reply) {
166 std::vector<Location> locations;
167 server.findReferencesOf(uri: params.textDocument.uri, pos: params.position, references&: locations);
168 reply(std::move(locations));
169}
170
171//===----------------------------------------------------------------------===//
172// DocumentLink
173//===----------------------------------------------------------------------===//
174
175void LSPServer::onDocumentLink(const DocumentLinkParams &params,
176 Callback<std::vector<DocumentLink>> reply) {
177 std::vector<DocumentLink> links;
178 server.getDocumentLinks(uri: params.textDocument.uri, documentLinks&: links);
179 reply(std::move(links));
180}
181
182//===----------------------------------------------------------------------===//
183// Hover
184//===----------------------------------------------------------------------===//
185
186void LSPServer::onHover(const TextDocumentPositionParams &params,
187 Callback<std::optional<Hover>> reply) {
188 reply(server.findHover(uri: params.textDocument.uri, hoverPos: params.position));
189}
190
191//===----------------------------------------------------------------------===//
192// Entry Point
193//===----------------------------------------------------------------------===//
194
195LogicalResult mlir::lsp::runTableGenLSPServer(TableGenServer &server,
196 JSONTransport &transport) {
197 LSPServer lspServer(server, transport);
198 MessageHandler messageHandler(transport);
199
200 // Initialization
201 messageHandler.method(method: "initialize", thisPtr: &lspServer, handler: &LSPServer::onInitialize);
202 messageHandler.notification(method: "initialized", thisPtr: &lspServer,
203 handler: &LSPServer::onInitialized);
204 messageHandler.method(method: "shutdown", thisPtr: &lspServer, handler: &LSPServer::onShutdown);
205
206 // Document Changes
207 messageHandler.notification(method: "textDocument/didOpen", thisPtr: &lspServer,
208 handler: &LSPServer::onDocumentDidOpen);
209 messageHandler.notification(method: "textDocument/didClose", thisPtr: &lspServer,
210 handler: &LSPServer::onDocumentDidClose);
211 messageHandler.notification(method: "textDocument/didChange", thisPtr: &lspServer,
212 handler: &LSPServer::onDocumentDidChange);
213
214 // Definitions and References
215 messageHandler.method(method: "textDocument/definition", thisPtr: &lspServer,
216 handler: &LSPServer::onGoToDefinition);
217 messageHandler.method(method: "textDocument/references", thisPtr: &lspServer,
218 handler: &LSPServer::onReference);
219
220 // Document Link
221 messageHandler.method(method: "textDocument/documentLink", thisPtr: &lspServer,
222 handler: &LSPServer::onDocumentLink);
223
224 // Hover
225 messageHandler.method(method: "textDocument/hover", thisPtr: &lspServer, handler: &LSPServer::onHover);
226
227 // Diagnostics
228 lspServer.publishDiagnostics =
229 messageHandler.outgoingNotification<PublishDiagnosticsParams>(
230 method: "textDocument/publishDiagnostics");
231
232 // Run the main loop of the transport.
233 if (llvm::Error error = transport.run(handler&: messageHandler)) {
234 Logger::error(fmt: "Transport error: {0}", vals&: error);
235 llvm::consumeError(Err: std::move(error));
236 return failure();
237 }
238 return success(IsSuccess: lspServer.shutdownRequestReceived);
239}
240

source code of mlir/lib/Tools/tblgen-lsp-server/LSPServer.cpp