| //===- 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 "llvm/Support/LSP/Logging.h" |
| #include "llvm/Support/LSP/Protocol.h" |
| #include "llvm/Support/LSP/Transport.h" |
| #include <optional> |
| |
| using namespace mlir; |
| using namespace mlir::lsp; |
| |
| using llvm::lsp::Callback; |
| using llvm::lsp::DidChangeTextDocumentParams; |
| using llvm::lsp::DidCloseTextDocumentParams; |
| using llvm::lsp::DidOpenTextDocumentParams; |
| using llvm::lsp::DocumentLinkParams; |
| using llvm::lsp::Hover; |
| using llvm::lsp::InitializedParams; |
| using llvm::lsp::InitializeParams; |
| using llvm::lsp::JSONTransport; |
| using llvm::lsp::Location; |
| using llvm::lsp::Logger; |
| using llvm::lsp::MessageHandler; |
| using llvm::lsp::NoParams; |
| using llvm::lsp::OutgoingNotification; |
| using llvm::lsp::PublishDiagnosticsParams; |
| using llvm::lsp::ReferenceParams; |
| using llvm::lsp::TextDocumentPositionParams; |
| using llvm::lsp::TextDocumentSyncKind; |
| |
| //===----------------------------------------------------------------------===// |
| // LSPServer |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| struct LSPServer { |
| LSPServer(TableGenServer &server, JSONTransport &transport) |
| : server(server), transport(transport) {} |
| |
| //===--------------------------------------------------------------------===// |
| // Initialization |
| |
| void onInitialize(const InitializeParams ¶ms, |
| Callback<llvm::json::Value> reply); |
| void onInitialized(const InitializedParams ¶ms); |
| void onShutdown(const NoParams ¶ms, Callback<std::nullptr_t> 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<std::vector<Location>> reply); |
| void onReference(const ReferenceParams ¶ms, |
| Callback<std::vector<Location>> reply); |
| |
| //===----------------------------------------------------------------------===// |
| // DocumentLink |
| |
| void onDocumentLink(const DocumentLinkParams ¶ms, |
| Callback<std::vector<DocumentLink>> reply); |
| |
| //===--------------------------------------------------------------------===// |
| // Hover |
| |
| void onHover(const TextDocumentPositionParams ¶ms, |
| Callback<std::optional<Hover>> reply); |
| |
| //===--------------------------------------------------------------------===// |
| // Fields |
| //===--------------------------------------------------------------------===// |
| |
| TableGenServer &server; |
| JSONTransport &transport; |
| |
| /// An outgoing notification used to send diagnostics to the client when they |
| /// are ready to be processed. |
| OutgoingNotification<PublishDiagnosticsParams> 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<llvm::json::Value> 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<std::nullptr_t> 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<int64_t> 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<std::vector<Location>> reply) { |
| std::vector<Location> locations; |
| server.getLocationsOf(params.textDocument.uri, params.position, locations); |
| reply(std::move(locations)); |
| } |
| |
| void LSPServer::onReference(const ReferenceParams ¶ms, |
| Callback<std::vector<Location>> reply) { |
| std::vector<Location> locations; |
| server.findReferencesOf(params.textDocument.uri, params.position, locations); |
| reply(std::move(locations)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // DocumentLink |
| //===----------------------------------------------------------------------===// |
| |
| void LSPServer::onDocumentLink(const DocumentLinkParams ¶ms, |
| Callback<std::vector<DocumentLink>> reply) { |
| std::vector<DocumentLink> links; |
| server.getDocumentLinks(params.textDocument.uri, links); |
| reply(std::move(links)); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Hover |
| //===----------------------------------------------------------------------===// |
| |
| void LSPServer::onHover(const TextDocumentPositionParams ¶ms, |
| Callback<std::optional<Hover>> 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<PublishDiagnosticsParams>( |
| "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); |
| } |