1 //===- LSPServer.cpp - PDLL 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/Transport.h" 13 #include "PDLLServer.h" 14 #include "Protocol.h" 15 #include "llvm/ADT/FunctionExtras.h" 16 #include "llvm/ADT/StringMap.h" 17 18 #define DEBUG_TYPE "pdll-lsp-server" 19 20 using namespace mlir; 21 using namespace mlir::lsp; 22 23 //===----------------------------------------------------------------------===// 24 // LSPServer 25 //===----------------------------------------------------------------------===// 26 27 namespace { 28 struct LSPServer { 29 LSPServer(PDLLServer &server, JSONTransport &transport) 30 : server(server), transport(transport) {} 31 32 //===--------------------------------------------------------------------===// 33 // Initialization 34 35 void onInitialize(const InitializeParams ¶ms, 36 Callback<llvm::json::Value> reply); 37 void onInitialized(const InitializedParams ¶ms); 38 void onShutdown(const NoParams ¶ms, Callback<std::nullptr_t> reply); 39 40 //===--------------------------------------------------------------------===// 41 // Document Change 42 43 void onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms); 44 void onDocumentDidClose(const DidCloseTextDocumentParams ¶ms); 45 void onDocumentDidChange(const DidChangeTextDocumentParams ¶ms); 46 47 //===--------------------------------------------------------------------===// 48 // Definitions and References 49 50 void onGoToDefinition(const TextDocumentPositionParams ¶ms, 51 Callback<std::vector<Location>> reply); 52 void onReference(const ReferenceParams ¶ms, 53 Callback<std::vector<Location>> reply); 54 55 //===----------------------------------------------------------------------===// 56 // DocumentLink 57 58 void onDocumentLink(const DocumentLinkParams ¶ms, 59 Callback<std::vector<DocumentLink>> reply); 60 61 //===--------------------------------------------------------------------===// 62 // Hover 63 64 void onHover(const TextDocumentPositionParams ¶ms, 65 Callback<Optional<Hover>> reply); 66 67 //===--------------------------------------------------------------------===// 68 // Document Symbols 69 70 void onDocumentSymbol(const DocumentSymbolParams ¶ms, 71 Callback<std::vector<DocumentSymbol>> reply); 72 73 //===--------------------------------------------------------------------===// 74 // Code Completion 75 76 void onCompletion(const CompletionParams ¶ms, 77 Callback<CompletionList> reply); 78 79 //===--------------------------------------------------------------------===// 80 // Signature Help 81 82 void onSignatureHelp(const TextDocumentPositionParams ¶ms, 83 Callback<SignatureHelp> reply); 84 85 //===--------------------------------------------------------------------===// 86 // PDLL View Output 87 88 void onPDLLViewOutput(const PDLLViewOutputParams ¶ms, 89 Callback<Optional<PDLLViewOutputResult>> reply); 90 91 //===--------------------------------------------------------------------===// 92 // Fields 93 //===--------------------------------------------------------------------===// 94 95 PDLLServer &server; 96 JSONTransport &transport; 97 98 /// An outgoing notification used to send diagnostics to the client when they 99 /// are ready to be processed. 100 OutgoingNotification<PublishDiagnosticsParams> publishDiagnostics; 101 102 /// Used to indicate that the 'shutdown' request was received from the 103 /// Language Server client. 104 bool shutdownRequestReceived = false; 105 }; 106 } // namespace 107 108 //===----------------------------------------------------------------------===// 109 // Initialization 110 111 void LSPServer::onInitialize(const InitializeParams ¶ms, 112 Callback<llvm::json::Value> reply) { 113 // Send a response with the capabilities of this server. 114 llvm::json::Object serverCaps{ 115 {"textDocumentSync", 116 llvm::json::Object{ 117 {"openClose", true}, 118 {"change", (int)TextDocumentSyncKind::Full}, 119 {"save", true}, 120 }}, 121 {"completionProvider", 122 llvm::json::Object{ 123 {"allCommitCharacters", 124 {"\t", "(", ")", "[", "]", "{", "}", "<", ">", 125 ":", ";", ",", "+", "-", "/", "*", "%", "^", 126 "&", "#", "?", ".", "=", "\"", "'", "|"}}, 127 {"resolveProvider", false}, 128 {"triggerCharacters", 129 {".", ">", "(", "{", ",", "<", ":", "[", " ", "\"", "/"}}, 130 }}, 131 {"signatureHelpProvider", 132 llvm::json::Object{ 133 {"triggerCharacters", {"(", ","}}, 134 }}, 135 {"definitionProvider", true}, 136 {"referencesProvider", true}, 137 {"documentLinkProvider", 138 llvm::json::Object{ 139 {"resolveProvider", false}, 140 }}, 141 {"hoverProvider", true}, 142 {"documentSymbolProvider", true}, 143 }; 144 145 llvm::json::Object result{ 146 {{"serverInfo", llvm::json::Object{{"name", "mlir-pdll-lsp-server"}, 147 {"version", "0.0.1"}}}, 148 {"capabilities", std::move(serverCaps)}}}; 149 reply(std::move(result)); 150 } 151 void LSPServer::onInitialized(const InitializedParams &) {} 152 void LSPServer::onShutdown(const NoParams &, Callback<std::nullptr_t> reply) { 153 shutdownRequestReceived = true; 154 reply(nullptr); 155 } 156 157 //===----------------------------------------------------------------------===// 158 // Document Change 159 160 void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms) { 161 PublishDiagnosticsParams diagParams(params.textDocument.uri, 162 params.textDocument.version); 163 server.addOrUpdateDocument(params.textDocument.uri, params.textDocument.text, 164 params.textDocument.version, 165 diagParams.diagnostics); 166 167 // Publish any recorded diagnostics. 168 publishDiagnostics(diagParams); 169 } 170 void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams ¶ms) { 171 Optional<int64_t> version = server.removeDocument(params.textDocument.uri); 172 if (!version) 173 return; 174 175 // Empty out the diagnostics shown for this document. This will clear out 176 // anything currently displayed by the client for this document (e.g. in the 177 // "Problems" pane of VSCode). 178 publishDiagnostics( 179 PublishDiagnosticsParams(params.textDocument.uri, *version)); 180 } 181 void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams ¶ms) { 182 // TODO: We currently only support full document updates, we should refactor 183 // to avoid this. 184 if (params.contentChanges.size() != 1) 185 return; 186 PublishDiagnosticsParams diagParams(params.textDocument.uri, 187 params.textDocument.version); 188 server.addOrUpdateDocument( 189 params.textDocument.uri, params.contentChanges.front().text, 190 params.textDocument.version, diagParams.diagnostics); 191 192 // Publish any recorded diagnostics. 193 publishDiagnostics(diagParams); 194 } 195 196 //===----------------------------------------------------------------------===// 197 // Definitions and References 198 199 void LSPServer::onGoToDefinition(const TextDocumentPositionParams ¶ms, 200 Callback<std::vector<Location>> reply) { 201 std::vector<Location> locations; 202 server.getLocationsOf(params.textDocument.uri, params.position, locations); 203 reply(std::move(locations)); 204 } 205 206 void LSPServer::onReference(const ReferenceParams ¶ms, 207 Callback<std::vector<Location>> reply) { 208 std::vector<Location> locations; 209 server.findReferencesOf(params.textDocument.uri, params.position, locations); 210 reply(std::move(locations)); 211 } 212 213 //===----------------------------------------------------------------------===// 214 // DocumentLink 215 216 void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms, 217 Callback<std::vector<DocumentLink>> reply) { 218 std::vector<DocumentLink> links; 219 server.getDocumentLinks(params.textDocument.uri, links); 220 reply(std::move(links)); 221 } 222 223 //===----------------------------------------------------------------------===// 224 // Hover 225 226 void LSPServer::onHover(const TextDocumentPositionParams ¶ms, 227 Callback<Optional<Hover>> reply) { 228 reply(server.findHover(params.textDocument.uri, params.position)); 229 } 230 231 //===----------------------------------------------------------------------===// 232 // Document Symbols 233 234 void LSPServer::onDocumentSymbol(const DocumentSymbolParams ¶ms, 235 Callback<std::vector<DocumentSymbol>> reply) { 236 std::vector<DocumentSymbol> symbols; 237 server.findDocumentSymbols(params.textDocument.uri, symbols); 238 reply(std::move(symbols)); 239 } 240 241 //===----------------------------------------------------------------------===// 242 // Code Completion 243 244 void LSPServer::onCompletion(const CompletionParams ¶ms, 245 Callback<CompletionList> reply) { 246 reply(server.getCodeCompletion(params.textDocument.uri, params.position)); 247 } 248 249 //===----------------------------------------------------------------------===// 250 // Signature Help 251 252 void LSPServer::onSignatureHelp(const TextDocumentPositionParams ¶ms, 253 Callback<SignatureHelp> reply) { 254 reply(server.getSignatureHelp(params.textDocument.uri, params.position)); 255 } 256 257 //===----------------------------------------------------------------------===// 258 // PDLL ViewOutput 259 260 void LSPServer::onPDLLViewOutput( 261 const PDLLViewOutputParams ¶ms, 262 Callback<Optional<PDLLViewOutputResult>> reply) { 263 reply(server.getPDLLViewOutput(params.uri, params.kind)); 264 } 265 266 //===----------------------------------------------------------------------===// 267 // Entry Point 268 //===----------------------------------------------------------------------===// 269 270 LogicalResult mlir::lsp::runPdllLSPServer(PDLLServer &server, 271 JSONTransport &transport) { 272 LSPServer lspServer(server, transport); 273 MessageHandler messageHandler(transport); 274 275 // Initialization 276 messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize); 277 messageHandler.notification("initialized", &lspServer, 278 &LSPServer::onInitialized); 279 messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown); 280 281 // Document Changes 282 messageHandler.notification("textDocument/didOpen", &lspServer, 283 &LSPServer::onDocumentDidOpen); 284 messageHandler.notification("textDocument/didClose", &lspServer, 285 &LSPServer::onDocumentDidClose); 286 messageHandler.notification("textDocument/didChange", &lspServer, 287 &LSPServer::onDocumentDidChange); 288 289 // Definitions and References 290 messageHandler.method("textDocument/definition", &lspServer, 291 &LSPServer::onGoToDefinition); 292 messageHandler.method("textDocument/references", &lspServer, 293 &LSPServer::onReference); 294 295 // Document Link 296 messageHandler.method("textDocument/documentLink", &lspServer, 297 &LSPServer::onDocumentLink); 298 299 // Hover 300 messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover); 301 302 // Document Symbols 303 messageHandler.method("textDocument/documentSymbol", &lspServer, 304 &LSPServer::onDocumentSymbol); 305 306 // Code Completion 307 messageHandler.method("textDocument/completion", &lspServer, 308 &LSPServer::onCompletion); 309 310 // Signature Help 311 messageHandler.method("textDocument/signatureHelp", &lspServer, 312 &LSPServer::onSignatureHelp); 313 314 // PDLL ViewOutput 315 messageHandler.method("pdll/viewOutput", &lspServer, 316 &LSPServer::onPDLLViewOutput); 317 318 // Diagnostics 319 lspServer.publishDiagnostics = 320 messageHandler.outgoingNotification<PublishDiagnosticsParams>( 321 "textDocument/publishDiagnostics"); 322 323 // Run the main loop of the transport. 324 if (llvm::Error error = transport.run(messageHandler)) { 325 Logger::error("Transport error: {0}", error); 326 llvm::consumeError(std::move(error)); 327 return failure(); 328 } 329 return success(lspServer.shutdownRequestReceived); 330 } 331