diff --git a/nixd/include/nixd/Controller/Controller.h b/nixd/include/nixd/Controller/Controller.h index 354aca6ed..b33469283 100644 --- a/nixd/include/nixd/Controller/Controller.h +++ b/nixd/include/nixd/Controller/Controller.h @@ -106,34 +106,33 @@ class Controller : public lspserver::LSPServer { EndWorkDoneProgress(Params); } - std::mutex TUsLock; + mutable std::mutex TUsLock; llvm::StringMap> TUs; - template - std::shared_ptr getTU(std::string File, - lspserver::Callback &Reply) { + std::shared_ptr getTU(std::string_view File) const { using lspserver::error; std::lock_guard G(TUsLock); if (!TUs.count(File)) [[unlikely]] { - Reply(T{}); // Reply a default constructed response. lspserver::elog("cannot get translation unit: {0}", File); return nullptr; } - return TUs[File]; + return TUs.lookup(File); } - template - std::shared_ptr getAST(const NixTU &TU, - lspserver::Callback &Reply) { + static std::shared_ptr getAST(const NixTU &TU) { using lspserver::error; if (!TU.ast()) { - Reply(T{}); lspserver::elog("AST is null on this unit"); return nullptr; } return TU.ast(); } + std::shared_ptr getAST(std::string_view File) const { + auto TU = getTU(File); + return TU ? getAST(*TU) : nullptr; + } + boost::asio::thread_pool Pool; /// Action right after a document is added (including updates). @@ -217,8 +216,9 @@ class Controller : public lspserver::LSPServer { void onRename(const lspserver::RenameParams &Params, lspserver::Callback Reply); - void onPrepareRename(const lspserver::TextDocumentPositionParams &Params, - lspserver::Callback Reply); + void + onPrepareRename(const lspserver::TextDocumentPositionParams &Params, + lspserver::Callback> Reply); void onFormat(const lspserver::DocumentFormattingParams &Params, lspserver::Callback> Reply); diff --git a/nixd/lib/Controller/CheckReturn.h b/nixd/lib/Controller/CheckReturn.h new file mode 100644 index 000000000..011eefc51 --- /dev/null +++ b/nixd/lib/Controller/CheckReturn.h @@ -0,0 +1,16 @@ +#pragma once + +/// \brief Used for simplify early-returns. +/// +/// const auto *foo = checkReturn(get(), nullptr) +#define CheckReturn(x, Ret) \ + ({ \ + decltype(x) temp = (x); \ + if (!temp) { \ + return Ret; \ + } \ + temp; \ + }) + +/// \brief Variant of `CheckReturn`, but returns default constructed `CheckTy` +#define CheckDefault(x) CheckReturn(x, CheckTy{}) diff --git a/nixd/lib/Controller/CodeAction.cpp b/nixd/lib/Controller/CodeAction.cpp index 7b02fdc7e..ef4baa75c 100644 --- a/nixd/lib/Controller/CodeAction.cpp +++ b/nixd/lib/Controller/CodeAction.cpp @@ -3,6 +3,7 @@ /// [Code Action]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_codeAction +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -16,12 +17,15 @@ using namespace lspserver; void Controller::onCodeAction(const lspserver::CodeActionParams &Params, Callback> Reply) { + using CheckTy = std::vector; std::string File(Params.textDocument.uri.file()); Range Range = Params.range; auto Action = [Reply = std::move(Reply), File, Range, this]() mutable { - if (auto TU = getTU(File, Reply)) { - std::vector Diagnostics = TU->diagnostics(); - std::vector Actions; + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + + const auto &Diagnostics = TU->diagnostics(); + auto Actions = std::vector(); Actions.reserve(Diagnostics.size()); for (const nixf::Diagnostic &D : Diagnostics) { auto DRange = toLSPRange(TU->src(), D.range()); @@ -50,8 +54,8 @@ void Controller::onCodeAction(const lspserver::CodeActionParams &Params, }); } } - Reply(std::move(Actions)); - } + return Actions; + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/Completion.cpp b/nixd/lib/Controller/Completion.cpp index 93dc2343c..f407cb44d 100644 --- a/nixd/lib/Controller/Completion.cpp +++ b/nixd/lib/Controller/Completion.cpp @@ -4,6 +4,7 @@ /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion #include "AST.h" +#include "CheckReturn.h" #include "Convert.h" #include "lspserver/Protocol.h" @@ -376,72 +377,60 @@ void completeSelect(const nixf::ExprSelect &Select, AttrSetClient &Client, void Controller::onCompletion(const CompletionParams &Params, Callback Reply) { + using CheckTy = CompletionList; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), this]() mutable { - std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const nixf::Node *Desc = AST->descend({Pos, Pos}); - if (!Desc) { - Reply(error("cannot find corresponding node on given position")); - return; - } - if (!Desc->children().empty()) { - Reply(CompletionList{}); - return; - } - const nixf::Node &N = *Desc; - const ParentMapAnalysis &PM = *TU->parentMap(); - const Node *MaybeUpExpr = PM.upExpr(N); - if (!MaybeUpExpr) { - // If there is no concrete expression containing the cursor - // Reply an empty list. - Reply(CompletionList{}); - return; - } - // Otherwise, construct the completion list from a set of providers. - const Node &UpExpr = *MaybeUpExpr; - Reply([&]() -> CompletionList { - CompletionList List; - const VariableLookupAnalysis &VLA = *TU->variableLookup(); - try { - switch (UpExpr.kind()) { - // In these cases, assume the cursor have "variable" scoping. - case Node::NK_ExprVar: { - completeVarName(VLA, PM, - static_cast(UpExpr), - *nixpkgsClient(), List.items); - break; - } - // A "select" expression. e.g. - // foo.a| - // foo.| - // foo.a.bar| - case Node::NK_ExprSelect: { - const auto &Select = - static_cast(UpExpr); - completeSelect(Select, *nixpkgsClient(), VLA, PM, - N.kind() == Node::NK_Dot, List.items); - break; - } - case Node::NK_ExprAttrs: { - completeAttrPath(N, PM, OptionsLock, Options, - ClientCaps.CompletionSnippets, List.items); - break; - } - default: - break; - } - } catch (ExceedSizeError &Err) { - List.isIncomplete = true; + const auto File = URI.file().str(); + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + + const auto *Desc = AST->descend({Pos, Pos}); + CheckDefault(Desc && Desc->children().empty()); + + const auto &N = *Desc; + const auto &PM = *TU->parentMap(); + const auto &UpExpr = *CheckDefault(PM.upExpr(N)); + + return [&]() { + CompletionList List; + const VariableLookupAnalysis &VLA = *TU->variableLookup(); + try { + switch (UpExpr.kind()) { + // In these cases, assume the cursor have "variable" scoping. + case Node::NK_ExprVar: { + completeVarName(VLA, PM, static_cast(UpExpr), + *nixpkgsClient(), List.items); + return List; + } + // A "select" expression. e.g. + // foo.a| + // foo.| + // foo.a.bar| + case Node::NK_ExprSelect: { + const auto &Select = static_cast(UpExpr); + completeSelect(Select, *nixpkgsClient(), VLA, PM, + N.kind() == Node::NK_Dot, List.items); + return List; + } + case Node::NK_ExprAttrs: { + completeAttrPath(N, PM, OptionsLock, Options, + ClientCaps.CompletionSnippets, List.items); + return List; } + default: + return List; + } + } catch (ExceedSizeError &Err) { + List.isIncomplete = true; return List; - }()); - } - } + } + }(); + }()); }; boost::asio::post(Pool, std::move(Action)); } +#undef check void Controller::onCompletionItemResolve(const CompletionItem &Params, Callback Reply) { diff --git a/nixd/lib/Controller/Definition.cpp b/nixd/lib/Controller/Definition.cpp index 8e2394812..9d54f8668 100644 --- a/nixd/lib/Controller/Definition.cpp +++ b/nixd/lib/Controller/Definition.cpp @@ -5,6 +5,7 @@ #include "Definition.h" #include "AST.h" +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -354,52 +355,43 @@ const Definition &nixd::findDefinition(const Node &N, return findVarDefinition(*Var, VLA); } +#define Check(x) CheckReturn(x, nullptr) void Controller::onDefinition(const TextDocumentPositionParams &Params, Callback Reply) { auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), this]() mutable { - std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const VariableLookupAnalysis &VLA = *TU->variableLookup(); - const ParentMapAnalysis &PM = *TU->parentMap(); - const Node *MaybeN = AST->descend({Pos, Pos}); - if (!MaybeN) [[unlikely]] { - Reply(error("cannot find AST node on given position")); - return; + const auto File = URI.file().str(); + return Reply([&]() -> llvm::Expected { + const auto TU = Check(getTU(File)); + const auto AST = Check(getAST(*TU)); + const auto &VLA = *TU->variableLookup(); + const auto &PM = *TU->parentMap(); + const auto &N = *Check(AST->descend({Pos, Pos})); + const auto &UpExpr = *Check(PM.upExpr(N)); + + return squash([&]() -> llvm::Expected { + // Special case for inherited names. + if (const ExprVar *Var = findInheritVar(N, PM, VLA)) + return defineVar(*Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); + + switch (UpExpr.kind()) { + case Node::NK_ExprVar: { + const auto &Var = static_cast(UpExpr); + return defineVar(Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); } - const Node &N = *MaybeN; - const Node *MaybeUpExpr = PM.upExpr(N); - if (!MaybeUpExpr) { - Reply(nullptr); - return; + case Node::NK_ExprSelect: { + const auto &Sel = static_cast(UpExpr); + return defineSelect(Sel, VLA, PM, *nixpkgsClient()); } - - const Node &UpExpr = *MaybeUpExpr; - - return Reply(squash([&]() -> llvm::Expected { - // Special case for inherited names. - if (const ExprVar *Var = findInheritVar(N, PM, VLA)) - return defineVar(*Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); - - switch (UpExpr.kind()) { - case Node::NK_ExprVar: { - const auto &Var = static_cast(UpExpr); - return defineVar(Var, VLA, PM, *nixpkgsClient(), URI, TU->src()); - } - case Node::NK_ExprSelect: { - const auto &Sel = static_cast(UpExpr); - return defineSelect(Sel, VLA, PM, *nixpkgsClient()); - } - case Node::NK_ExprAttrs: - return defineAttrPath(N, PM, OptionsLock, Options); - default: - break; - } - return error("unknown node type for definition"); - }())); - } - } + case Node::NK_ExprAttrs: + return defineAttrPath(N, PM, OptionsLock, Options); + default: + break; + } + return error("unknown node type for definition"); + }()); + }()); }; boost::asio::post(Pool, std::move(Action)); } +#undef Check diff --git a/nixd/lib/Controller/DocumentHighlight.cpp b/nixd/lib/Controller/DocumentHighlight.cpp index 7587faaf0..e7fcdb99d 100644 --- a/nixd/lib/Controller/DocumentHighlight.cpp +++ b/nixd/lib/Controller/DocumentHighlight.cpp @@ -3,6 +3,7 @@ /// [Document Highlight]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentHighlight +#include "CheckReturn.h" #include "Convert.h" #include "Definition.h" @@ -55,26 +56,24 @@ std::vector highlight(const nixf::Node &Desc, void Controller::onDocumentHighlight( const TextDocumentPositionParams &Params, Callback> Reply) { + using CheckTy = std::vector; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), this]() mutable { std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const nixf::Node *Desc = AST->descend({Pos, Pos}); - if (!Desc) { - Reply(error("cannot find corresponding node on given position")); - return; - } - try { - const auto &PM = *TU->parentMap(); - const auto &VLA = *TU->variableLookup(); - return Reply(highlight(*Desc, PM, VLA, URI, TU->src())); - } catch (std::exception &E) { - elog("textDocument/documentHighlight failed: {0}", E.what()); - return Reply(std::vector{}); - } + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + + const auto &Desc = *CheckDefault(AST->descend({Pos, Pos})); + try { + const auto &PM = *TU->parentMap(); + const auto &VLA = *TU->variableLookup(); + return highlight(Desc, PM, VLA, URI, TU->src()); + } catch (std::exception &E) { + elog("textDocument/documentHighlight failed: {0}", E.what()); + return CheckTy{}; } - } + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/DocumentLink.cpp b/nixd/lib/Controller/DocumentLink.cpp index 43fa3511e..e1a9404ab 100644 --- a/nixd/lib/Controller/DocumentLink.cpp +++ b/nixd/lib/Controller/DocumentLink.cpp @@ -15,6 +15,7 @@ /// FIXME: support flake ref /// +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -80,16 +81,18 @@ void dfs(const Node *N, const std::string &BasePath, void Controller::onDocumentLink( const DocumentLinkParams &Params, lspserver::Callback> Reply) { + using CheckTy = std::vector; auto Action = [File = Params.textDocument.uri.file().str(), Reply = std::move(Reply), this]() mutable { - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - // Traverse the AST, provide the links - std::vector Links; - dfs(AST.get(), File, Links, TU->src()); - Reply(std::move(Links)); - } - } + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + + // Traverse the AST, provide the links + std::vector Links; + dfs(AST.get(), File, Links, TU->src()); + return Links; + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/DocumentSymbol.cpp b/nixd/lib/Controller/DocumentSymbol.cpp index e0dbd21ad..da23f25fa 100644 --- a/nixd/lib/Controller/DocumentSymbol.cpp +++ b/nixd/lib/Controller/DocumentSymbol.cpp @@ -3,6 +3,7 @@ /// [Document Symbol]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_documentSymbol +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -236,15 +237,16 @@ void collect(const Node *AST, std::vector &Symbols, void Controller::onDocumentSymbol(const DocumentSymbolParams &Params, Callback> Reply) { + using CheckTy = std::vector; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, this]() mutable { - if (std::shared_ptr TU = getTU(URI.file().str(), Reply)) { - if (std::shared_ptr AST = getAST(*TU, Reply)) { - std::vector Symbols; - collect(AST.get(), Symbols, *TU->variableLookup(), TU->src()); - Reply(std::move(Symbols)); - } - } + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(URI.file().str())); + const auto AST = CheckDefault(getAST(*TU)); + auto Symbols = std::vector(); + collect(AST.get(), Symbols, *TU->variableLookup(), TU->src()); + return Symbols; + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/FindReferences.cpp b/nixd/lib/Controller/FindReferences.cpp index f64f4ded2..041388b15 100644 --- a/nixd/lib/Controller/FindReferences.cpp +++ b/nixd/lib/Controller/FindReferences.cpp @@ -3,6 +3,7 @@ /// [Find References]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_references +#include "CheckReturn.h" #include "Convert.h" #include "Definition.h" @@ -48,25 +49,22 @@ std::vector findReferences(const nixf::Node &Desc, void Controller::onReferences(const TextDocumentPositionParams &Params, Callback> Reply) { + using CheckTy = std::vector; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), this]() mutable { std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const nixf::Node *Desc = AST->descend({Pos, Pos}); - if (!Desc) { - return Reply( - error("cannot find corresponding node on given position")); - } - const auto &PM = *TU->parentMap(); - const auto &VLA = *TU->variableLookup(); - try { - return Reply(findReferences(*Desc, PM, VLA, URI, TU->src())); - } catch (std::exception &E) { - return Reply(error("references: {0}", E.what())); - } + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + const auto &Desc = CheckDefault(AST->descend({Pos, Pos})); + const auto &PM = *TU->parentMap(); + const auto &VLA = *TU->variableLookup(); + try { + return findReferences(*Desc, PM, VLA, URI, TU->src()); + } catch (std::exception &E) { + return error("references: {0}", E.what()); } - } + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/Hover.cpp b/nixd/lib/Controller/Hover.cpp index 0ffe10f9d..87015d5b0 100644 --- a/nixd/lib/Controller/Hover.cpp +++ b/nixd/lib/Controller/Hover.cpp @@ -4,6 +4,7 @@ /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_hover #include "AST.h" +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -116,84 +117,79 @@ class NixpkgsHoverProvider { void Controller::onHover(const TextDocumentPositionParams &Params, Callback> Reply) { + using CheckTy = std::optional; auto Action = [Reply = std::move(Reply), File = std::string(Params.textDocument.uri.file()), RawPos = Params.position, this]() mutable { - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - nixf::Position Pos{RawPos.line, RawPos.character}; - const nixf::Node *N = AST->descend({Pos, Pos}); - if (!N) { - Reply(std::nullopt); - return; - } - std::string Name = N->name(); - const VariableLookupAnalysis &VLA = *TU->variableLookup(); - const ParentMapAnalysis &PM = *TU->parentMap(); - if (havePackageScope(*N, VLA, PM) && nixpkgsClient()) { - // Ask nixpkgs client what's current package documentation. - NixpkgsHoverProvider NHP(*nixpkgsClient()); - auto [Scope, Name] = getScopeAndPrefix(*N, PM); - if (std::optional Doc = - NHP.resolvePackage(Scope, Name)) { - Reply(Hover{ - .contents = - MarkupContent{ - .kind = MarkupKind::Markdown, - .value = std::move(*Doc), - }, - .range = toLSPRange(TU->src(), N->range()), - }); - return; - } + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + const auto Pos = nixf::Position{RawPos.line, RawPos.character}; + const auto &N = *CheckDefault(AST->descend({Pos, Pos})); + + const auto Name = std::string(N.name()); + const auto &VLA = *TU->variableLookup(); + const auto &PM = *TU->parentMap(); + if (havePackageScope(N, VLA, PM) && nixpkgsClient()) { + // Ask nixpkgs client what's current package documentation. + auto NHP = NixpkgsHoverProvider(*nixpkgsClient()); + const auto [Scope, Name] = getScopeAndPrefix(N, PM); + if (std::optional Doc = NHP.resolvePackage(Scope, Name)) { + return Hover{ + .contents = + MarkupContent{ + .kind = MarkupKind::Markdown, + .value = std::move(*Doc), + }, + .range = toLSPRange(TU->src(), N.range()), + }; } + } - std::vector Scope; - auto R = findAttrPath(*N, PM, Scope); - if (R == FindAttrPathResult::OK) { - std::lock_guard _(OptionsLock); - for (const auto &[_, Client] : Options) { - if (AttrSetClient *C = Client->client()) { - OptionsHoverProvider OHP(*C); - std::optional Desc = OHP.resolveHover(Scope); - std::string Docs; - if (Desc) { - if (Desc->Type) { - std::string TypeName = Desc->Type->Name.value_or(""); - std::string TypeDesc = Desc->Type->Description.value_or(""); - Docs += llvm::formatv("{0} ({1})", TypeName, TypeDesc); - } else { - Docs += "? (missing type)"; - } - if (Desc->Description) { - Docs += "\n\n" + Desc->Description.value_or(""); - } - Reply(Hover{ - .contents = - MarkupContent{ - .kind = MarkupKind::Markdown, - .value = std::move(Docs), - }, - .range = toLSPRange(TU->src(), N->range()), - }); - return; + auto Scope = std::vector(); + const auto R = findAttrPath(N, PM, Scope); + if (R == FindAttrPathResult::OK) { + std::lock_guard _(OptionsLock); + for (const auto &[_, Client] : Options) { + if (AttrSetClient *C = Client->client()) { + OptionsHoverProvider OHP(*C); + std::optional Desc = OHP.resolveHover(Scope); + std::string Docs; + if (Desc) { + if (Desc->Type) { + std::string TypeName = Desc->Type->Name.value_or(""); + std::string TypeDesc = Desc->Type->Description.value_or(""); + Docs += llvm::formatv("{0} ({1})", TypeName, TypeDesc); + } else { + Docs += "? (missing type)"; + } + if (Desc->Description) { + Docs += "\n\n" + Desc->Description.value_or(""); } + return Hover{ + .contents = + MarkupContent{ + .kind = MarkupKind::Markdown, + .value = std::move(Docs), + }, + .range = toLSPRange(TU->src(), N.range()), + }; } } } - - // Reply it's kind by static analysis - // FIXME: support more. - Reply(Hover{ - .contents = - MarkupContent{ - .kind = MarkupKind::Markdown, - .value = "`" + Name + "`", - }, - .range = toLSPRange(TU->src(), N->range()), - }); } - } + + // Reply it's kind by static analysis + // FIXME: support more. + return Hover{ + .contents = + MarkupContent{ + .kind = MarkupKind::Markdown, + .value = "`" + Name + "`", + }, + .range = toLSPRange(TU->src(), N.range()), + }; + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/InlayHints.cpp b/nixd/lib/Controller/InlayHints.cpp index bd9d36d47..2938e0af3 100644 --- a/nixd/lib/Controller/InlayHints.cpp +++ b/nixd/lib/Controller/InlayHints.cpp @@ -12,7 +12,9 @@ /// nix[: 2.19.3] /// /// + #include "AST.h" +#include "CheckReturn.h" #include "Convert.h" #include "nixd/CommandLine/Options.h" @@ -112,24 +114,27 @@ class NixpkgsInlayHintsProvider { void Controller::onInlayHint(const InlayHintsParams &Params, Callback> Reply) { + + using CheckTy = std::vector; + // If not enabled, exit early. if (!EnableInlayHints) return Reply(std::vector{}); auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Range = Params.range, this]() mutable { - std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - // Perform inlay hints computation on the range. - std::vector Response; - NixpkgsInlayHintsProvider NP(*nixpkgsClient(), *TU->variableLookup(), - *TU->parentMap(), Range, Response, - TU->src()); - NP.dfs(AST.get()); - Reply(std::move(Response)); - } - } + const auto File = URI.file(); + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + // Perform inlay hints computation on the range. + std::vector Response; + NixpkgsInlayHintsProvider NP(*nixpkgsClient(), *TU->variableLookup(), + *TU->parentMap(), Range, Response, + TU->src()); + NP.dfs(AST.get()); + return Response; + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/Rename.cpp b/nixd/lib/Controller/Rename.cpp index 41ba232b8..973c9e798 100644 --- a/nixd/lib/Controller/Rename.cpp +++ b/nixd/lib/Controller/Rename.cpp @@ -3,6 +3,7 @@ /// [Rename]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_rename +#include "CheckReturn.h" #include "Convert.h" #include "Definition.h" @@ -70,53 +71,52 @@ WorkspaceEdit rename(const nixf::Node &Desc, const std::string &NewText, void Controller::onRename(const RenameParams &Params, Callback Reply) { + using CheckTy = WorkspaceEdit; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), NewText = Params.newName, this]() mutable { - std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const nixf::Node *Desc = AST->descend({Pos, Pos}); - if (!Desc) { - Reply(error("cannot find corresponding node on given position")); - return; - } - const auto &PM = *TU->parentMap(); - const auto &VLA = *TU->variableLookup(); - try { - return Reply(rename(*Desc, NewText, PM, VLA, URI, TU->src())); - } catch (std::exception &E) { - return Reply(error(E.what())); - } + const auto File = URI.file(); + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + const auto &Desc = *CheckReturn( + AST->descend({Pos, Pos}), + error("cannot find corresponding node on given position")); + + const auto &PM = *TU->parentMap(); + const auto &VLA = *TU->variableLookup(); + try { + return rename(Desc, NewText, PM, VLA, URI, TU->src()); + } catch (std::exception &E) { + return error(E.what()); } - } + }()); }; boost::asio::post(Pool, std::move(Action)); } void Controller::onPrepareRename( const lspserver::TextDocumentPositionParams &Params, - Callback Reply) { + Callback> Reply) { + using CheckTy = std::optional; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, Pos = toNixfPosition(Params.position), this]() mutable { - std::string File(URI.file()); - if (std::shared_ptr TU = getTU(File, Reply)) [[likely]] { - if (std::shared_ptr AST = getAST(*TU, Reply)) [[likely]] { - const nixf::Node *Desc = AST->descend({Pos, Pos}); - if (!Desc) { - return Reply( - error("cannot find corresponding node on given position")); - } - const auto &PM = *TU->parentMap(); - const auto &VLA = *TU->variableLookup(); - try { - WorkspaceEdit WE = rename(*Desc, "", PM, VLA, URI, TU->src()); - return Reply(toLSPRange(TU->src(), Desc->range())); - } catch (std::exception &E) { - return Reply(error(E.what())); - } + const auto File = URI.file(); + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + + const auto &Desc = *CheckDefault(AST->descend({Pos, Pos})); + + const auto &PM = *TU->parentMap(); + const auto &VLA = *TU->variableLookup(); + try { + WorkspaceEdit WE = rename(Desc, "", PM, VLA, URI, TU->src()); + return toLSPRange(TU->src(), Desc.range()); + } catch (std::exception &E) { + return error(E.what()); } - } + }()); }; boost::asio::post(Pool, std::move(Action)); } diff --git a/nixd/lib/Controller/SemanticTokens.cpp b/nixd/lib/Controller/SemanticTokens.cpp index a8a090d4c..42716d90e 100644 --- a/nixd/lib/Controller/SemanticTokens.cpp +++ b/nixd/lib/Controller/SemanticTokens.cpp @@ -3,6 +3,7 @@ /// [Semantic Tokens]: /// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_semanticTokens +#include "CheckReturn.h" #include "Convert.h" #include "nixd/Controller/Controller.h" @@ -235,15 +236,17 @@ class SemanticTokenBuilder { void Controller::onSemanticTokens(const SemanticTokensParams &Params, Callback Reply) { + using CheckTy = SemanticTokens; auto Action = [Reply = std::move(Reply), URI = Params.textDocument.uri, this]() mutable { - if (std::shared_ptr TU = getTU(URI.file().str(), Reply)) { - if (std::shared_ptr AST = getAST(*TU, Reply)) { - SemanticTokenBuilder Builder(*TU->variableLookup(), TU->src()); - Builder.dfs(AST.get()); - Reply(SemanticTokens{.tokens = Builder.finish()}); - } - } + const auto File = URI.file(); + return Reply([&]() -> llvm::Expected { + const auto TU = CheckDefault(getTU(File)); + const auto AST = CheckDefault(getAST(*TU)); + SemanticTokenBuilder Builder(*TU->variableLookup(), TU->src()); + Builder.dfs(AST.get()); + return SemanticTokens{.tokens = Builder.finish()}; + }()); }; boost::asio::post(Pool, std::move(Action)); }