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::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 } 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.addDocument(params.textDocument.uri, params.textDocument.text, 123 params.textDocument.version, diagParams.diagnostics); 124 125 // Publish any recorded diagnostics. 126 publishDiagnostics(diagParams); 127 } 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 } 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 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 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 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 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 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