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

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