From 71194e70eb626fe556816df8961146939dda666e Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Thu, 25 May 2023 02:57:16 +0800 Subject: [PATCH] nixd: support hover --- lib/nixd/include/nixd/Server.h | 8 ++++++- lib/nixd/src/Server.cpp | 44 ++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/lib/nixd/include/nixd/Server.h b/lib/nixd/include/nixd/Server.h index f7321e856..ca34c97df 100644 --- a/lib/nixd/include/nixd/Server.h +++ b/lib/nixd/include/nixd/Server.h @@ -2,10 +2,12 @@ #include "lspserver/Connection.h" #include "lspserver/DraftStore.h" +#include "lspserver/Function.h" #include "lspserver/LSPServer.h" #include "lspserver/Logger.h" #include "lspserver/Protocol.h" #include "lspserver/SourceCode.h" +#include "nixd/EvalDraftStore.h" #include #include @@ -14,7 +16,8 @@ namespace nixd { /// The server instance, nix-related language features goes here class Server : public lspserver::LSPServer { - lspserver::DraftStore DraftMgr; + EvalDraftStore DraftMgr; + boost::asio::thread_pool Pool; std::shared_ptr getDraft(lspserver::PathRef File) const; @@ -37,6 +40,7 @@ class Server : public lspserver::LSPServer { std::unique_ptr Out) : LSPServer(std::move(In), std::move(Out)) { Registry.addMethod("initialize", this, &Server::onInitialize); + Registry.addMethod("textDocument/hover", this, &Server::onHover); Registry.addNotification("initialized", this, &Server::onInitialized); // Text Document Synchronization @@ -61,6 +65,8 @@ class Server : public lspserver::LSPServer { void publishStandaloneDiagnostic(lspserver::URIForFile Uri, std::string Content, std::optional LSPVersion); + void onHover(const lspserver::TextDocumentPositionParams &, + lspserver::Callback); }; }; // namespace nixd diff --git a/lib/nixd/src/Server.cpp b/lib/nixd/src/Server.cpp index 0c03acfd4..0bd82dfc4 100644 --- a/lib/nixd/src/Server.cpp +++ b/lib/nixd/src/Server.cpp @@ -1,9 +1,11 @@ #include "nixd/Server.h" +#include "lspserver/Logger.h" #include "nixd/Diagnostic.h" #include "lspserver/Path.h" #include "lspserver/Protocol.h" +#include #include #include #include @@ -13,6 +15,9 @@ #include #include +#include +#include +#include namespace fs = std::filesystem; namespace nixd { @@ -25,6 +30,7 @@ void Server::onInitialize(const lspserver::InitializeParams &InitializeParams, {"change", (int)lspserver::TextDocumentSyncKind::Incremental}, {"save", true}, }}, + {"hoverProvider", true}, }; llvm::json::Object Result{ @@ -89,8 +95,8 @@ void Server::publishStandaloneDiagnostic(lspserver::URIForFile Uri, auto NixState = std::make_unique(nix::Strings{}, NixStore); try { fs::path Path = Uri.file().str(); - auto *E = - NixState->parseExprFromString(std::move(Content), Path.remove_filename()); + auto *E = NixState->parseExprFromString(std::move(Content), + Path.remove_filename()); nix::Value V; NixState->eval(E, V); } catch (const nix::Error &PE) { @@ -104,4 +110,38 @@ void Server::publishStandaloneDiagnostic(lspserver::URIForFile Uri, .uri = Uri, .diagnostics = {}, .version = LSPVersion}); } +void Server::onHover(const lspserver::TextDocumentPositionParams &Paras, + lspserver::Callback Reply) { + std::string HoverFile = Paras.textDocument.uri.file().str(); + DraftMgr.withEvaluation( + Pool, {"--file", HoverFile}, "", + [=, Reply = std::move(Reply)]( + std::variant> + EvalResult) mutable { + nix::ref Result = + std::get<1>(EvalResult); + try { + std::get<1>(EvalResult); // w contains int, not float: will throw + } catch (const std::bad_variant_access &) { + std::exception *Excepts = std::get<0>(EvalResult); + lspserver::log(Excepts->what()); + } + auto Forest = Result->EvalASTForest; + auto AST = Forest.at(HoverFile); + auto *Node = AST->lookupPosition(Paras.position); + std::stringstream NodeOut; + Node->show(Result->State->symbols, NodeOut); + auto Value = AST->getValue(Node); + std::stringstream Res{}; + Value.print(Result->State->symbols, Res); + Reply(lspserver::Hover{ + .contents = + { + .value = Res.str(), + }, + }); + }); +} + } // namespace nixd