//===- LSPServer.cpp - TableGen Language Server ---------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "LSPServer.h" #include "TableGenServer.h" #include "mlir/Tools/lsp-server-support/Logging.h" #include "mlir/Tools/lsp-server-support/Protocol.h" #include "mlir/Tools/lsp-server-support/Transport.h" #include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringMap.h" #include using namespace mlir; using namespace mlir::lsp; //===----------------------------------------------------------------------===// // LSPServer //===----------------------------------------------------------------------===// namespace { struct LSPServer { LSPServer(TableGenServer &server, JSONTransport &transport) : server(server), transport(transport) {} //===--------------------------------------------------------------------===// // Initialization void onInitialize(const InitializeParams ¶ms, Callback reply); void onInitialized(const InitializedParams ¶ms); void onShutdown(const NoParams ¶ms, Callback reply); //===--------------------------------------------------------------------===// // Document Change void onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms); void onDocumentDidClose(const DidCloseTextDocumentParams ¶ms); void onDocumentDidChange(const DidChangeTextDocumentParams ¶ms); //===--------------------------------------------------------------------===// // Definitions and References void onGoToDefinition(const TextDocumentPositionParams ¶ms, Callback> reply); void onReference(const ReferenceParams ¶ms, Callback> reply); //===----------------------------------------------------------------------===// // DocumentLink void onDocumentLink(const DocumentLinkParams ¶ms, Callback> reply); //===--------------------------------------------------------------------===// // Hover void onHover(const TextDocumentPositionParams ¶ms, Callback> reply); //===--------------------------------------------------------------------===// // Fields //===--------------------------------------------------------------------===// TableGenServer &server; JSONTransport &transport; /// An outgoing notification used to send diagnostics to the client when they /// are ready to be processed. OutgoingNotification publishDiagnostics; /// Used to indicate that the 'shutdown' request was received from the /// Language Server client. bool shutdownRequestReceived = false; }; } // namespace //===----------------------------------------------------------------------===// // Initialization void LSPServer::onInitialize(const InitializeParams ¶ms, Callback reply) { // Send a response with the capabilities of this server. llvm::json::Object serverCaps{ {"textDocumentSync", llvm::json::Object{ {"openClose", true}, {"change", (int)TextDocumentSyncKind::Incremental}, {"save", true}, }}, {"definitionProvider", true}, {"referencesProvider", true}, {"documentLinkProvider", llvm::json::Object{ {"resolveProvider", false}, }}, {"hoverProvider", true}, }; llvm::json::Object result{ {{"serverInfo", llvm::json::Object{{"name", "tblgen-lsp-server"}, {"version", "0.0.1"}}}, {"capabilities", std::move(serverCaps)}}}; reply(std::move(result)); } void LSPServer::onInitialized(const InitializedParams &) {} void LSPServer::onShutdown(const NoParams &, Callback reply) { shutdownRequestReceived = true; reply(nullptr); } //===----------------------------------------------------------------------===// // Document Change void LSPServer::onDocumentDidOpen(const DidOpenTextDocumentParams ¶ms) { PublishDiagnosticsParams diagParams(params.textDocument.uri, params.textDocument.version); server.addDocument(params.textDocument.uri, params.textDocument.text, params.textDocument.version, diagParams.diagnostics); // Publish any recorded diagnostics. publishDiagnostics(diagParams); } void LSPServer::onDocumentDidClose(const DidCloseTextDocumentParams ¶ms) { std::optional version = server.removeDocument(params.textDocument.uri); if (!version) return; // Empty out the diagnostics shown for this document. This will clear out // anything currently displayed by the client for this document (e.g. in the // "Problems" pane of VSCode). publishDiagnostics( PublishDiagnosticsParams(params.textDocument.uri, *version)); } void LSPServer::onDocumentDidChange(const DidChangeTextDocumentParams ¶ms) { PublishDiagnosticsParams diagParams(params.textDocument.uri, params.textDocument.version); server.updateDocument(params.textDocument.uri, params.contentChanges, params.textDocument.version, diagParams.diagnostics); // Publish any recorded diagnostics. publishDiagnostics(diagParams); } //===----------------------------------------------------------------------===// // Definitions and References void LSPServer::onGoToDefinition(const TextDocumentPositionParams ¶ms, Callback> reply) { std::vector locations; server.getLocationsOf(params.textDocument.uri, params.position, locations); reply(std::move(locations)); } void LSPServer::onReference(const ReferenceParams ¶ms, Callback> reply) { std::vector locations; server.findReferencesOf(params.textDocument.uri, params.position, locations); reply(std::move(locations)); } //===----------------------------------------------------------------------===// // DocumentLink void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms, Callback> reply) { std::vector links; server.getDocumentLinks(params.textDocument.uri, links); reply(std::move(links)); } //===----------------------------------------------------------------------===// // Hover void LSPServer::onHover(const TextDocumentPositionParams ¶ms, Callback> reply) { reply(server.findHover(params.textDocument.uri, params.position)); } //===----------------------------------------------------------------------===// // Entry Point //===----------------------------------------------------------------------===// LogicalResult mlir::lsp::runTableGenLSPServer(TableGenServer &server, JSONTransport &transport) { LSPServer lspServer(server, transport); MessageHandler messageHandler(transport); // Initialization messageHandler.method("initialize", &lspServer, &LSPServer::onInitialize); messageHandler.notification("initialized", &lspServer, &LSPServer::onInitialized); messageHandler.method("shutdown", &lspServer, &LSPServer::onShutdown); // Document Changes messageHandler.notification("textDocument/didOpen", &lspServer, &LSPServer::onDocumentDidOpen); messageHandler.notification("textDocument/didClose", &lspServer, &LSPServer::onDocumentDidClose); messageHandler.notification("textDocument/didChange", &lspServer, &LSPServer::onDocumentDidChange); // Definitions and References messageHandler.method("textDocument/definition", &lspServer, &LSPServer::onGoToDefinition); messageHandler.method("textDocument/references", &lspServer, &LSPServer::onReference); // Document Link messageHandler.method("textDocument/documentLink", &lspServer, &LSPServer::onDocumentLink); // Hover messageHandler.method("textDocument/hover", &lspServer, &LSPServer::onHover); // Diagnostics lspServer.publishDiagnostics = messageHandler.outgoingNotification( "textDocument/publishDiagnostics"); // Run the main loop of the transport. if (llvm::Error error = transport.run(messageHandler)) { Logger::error("Transport error: {0}", error); llvm::consumeError(std::move(error)); return failure(); } return success(lspServer.shutdownRequestReceived); }