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 { 27 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 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::Full}, 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 } 110 void LSPServer::onInitialized(const InitializedParams &) {} 111 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) { 112 shutdownRequestReceived = true; 113 reply(nullptr); 114 } 115 116 //===----------------------------------------------------------------------===// 117 // Document Change 118 119 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms) { 120 PublishDiagnosticsParams diagParams(params.textDocument.uri, 121 params.textDocument.version); 122 server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text, 123 params.textDocument.version, 124 diagParams.diagnostics); 125 126 // Publish any recorded diagnostics. 127 publishDiagnostics(diagParams); 128 } 129 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams ¶ms) { 130 Optional<int64_t> version = server.removeDocument(params.textDocument.uri); 131 if (!version) 132 return; 133 134 // Empty out the diagnostics shown for this document. This will clear out 135 // anything currently displayed by the client for this document (e.g. in the 136 // "Problems" pane of VSCode). 137 publishDiagnostics( 138 PublishDiagnosticsParams(params.textDocument.uri, *version)); 139 } 140 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams ¶ms) { 141 // TODO: We currently only support full document updates, we should refactor 142 // to avoid this. 143 if (params.contentChanges.size() != 1) 144 return; 145 PublishDiagnosticsParams diagParams(params.textDocument.uri, 146 params.textDocument.version); 147 server.addOrUpdateDocument( 148 params.textDocument.uri, params.contentChanges.front().text, 149 params.textDocument.version, diagParams.diagnostics); 150 151 // Publish any recorded diagnostics. 152 publishDiagnostics(diagParams); 153 } 154 155 //===----------------------------------------------------------------------===// 156 // Definitions and References 157 158 void LSPServer::onGoToDefinition(const TextDocumentPositionParams ¶ms, 159 Callback<std::vector<Location>> reply) { 160 std::vector<Location> locations; 161 server.getLocationsOf(params.textDocument.uri, params.position, locations); 162 reply(std::move(locations)); 163 } 164 165 void LSPServer::onReference(const ReferenceParams ¶ms, 166 Callback<std::vector<Location>> reply) { 167 std::vector<Location> locations; 168 server.findReferencesOf(params.textDocument.uri, params.position, locations); 169 reply(std::move(locations)); 170 } 171 172 //===----------------------------------------------------------------------===// 173 // DocumentLink 174 175 void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms, 176 Callback<std::vector<DocumentLink>> reply) { 177 std::vector<DocumentLink> links; 178 server.getDocumentLinks(params.textDocument.uri, links); 179 reply(std::move(links)); 180 } 181 182 //===----------------------------------------------------------------------===// 183 // Hover 184 185 void LSPServer::onHover(const TextDocumentPositionParams ¶ms, 186 Callback<Optional<Hover>> reply) { 187 reply(server.findHover(params.textDocument.uri, params.position)); 188 } 189 190 //===----------------------------------------------------------------------===// 191 // Entry Point 192 //===----------------------------------------------------------------------===// 193 194 LogicalResult mlir::lsp::runTableGenLSPServer(TableGenServer &server, 195 JSONTransport &transport) { 196 LSPServer lspServer(server, transport); 197 MessageHandler messageHandler(transport); 198 199 // Initialization 200 messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize); 201 messageHandler.notification("initialized", &lspServer, 202 &LSPServer::onInitialized); 203 messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown); 204 205 // Document Changes 206 messageHandler.notification("textDocument/didOpen", &lspServer, 207 &LSPServer::onDocumentDidOpen); 208 messageHandler.notification("textDocument/didClose", &lspServer, 209 &LSPServer::onDocumentDidClose); 210 messageHandler.notification("textDocument/didChange", &lspServer, 211 &LSPServer::onDocumentDidChange); 212 213 // Definitions and References 214 messageHandler.method("textDocument/definition", &lspServer, 215 &LSPServer::onGoToDefinition); 216 messageHandler.method("textDocument/references", &lspServer, 217 &LSPServer::onReference); 218 219 // Document Link 220 messageHandler.method("textDocument/documentLink", &lspServer, 221 &LSPServer::onDocumentLink); 222 223 // Hover 224 messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover); 225 226 // Diagnostics 227 lspServer.publishDiagnostics = 228 messageHandler.outgoingNotification<PublishDiagnosticsParams>( 229 "textDocument/publishDiagnostics"); 230 231 // Run the main loop of the transport. 232 if (llvm::Error error = transport.run(messageHandler)) { 233 Logger::error("Transport error: {0}", error); 234 llvm::consumeError(std::move(error)); 235 return failure(); 236 } 237 return success(lspServer.shutdownRequestReceived); 238 } 239