17#include <boost/asio/post.hpp>
19#include <llvm/Support/Error.h>
20#include <llvm/Support/JSON.h>
53 if (Parent && Parent->
kind() == Node::NK_AttrName)
54 return VLA.
toDef(*Parent);
64 if (
const Node *Up = PMA.
upTo(N, Node::NK_Inherit)) {
65 const Node *UpAn = PMA.
upTo(N, Node::NK_AttrName);
68 const auto &Inh =
static_cast<const Inherit &
>(*Up);
69 const auto &AN =
static_cast<const AttrName &
>(*UpAn);
83 Up = PMA.
upTo(Inh, Node::NK_ExprAttrs);
89 assert(Var->
kind() == Node::NK_ExprVar);
90 return static_cast<const ExprVar *
>(Var);
97 if (
const ExprVar *InVar = findInheritVar(N, PMA, VLA))
100 return static_cast<const ExprVar *
>(PMA.
upTo(N, Node::NK_ExprVar));
107 if (Result.
Kind == ResultKind::Undefined)
110 if (Result.
Kind == ResultKind::NoSuchVar)
125 .uri = std::move(
URI),
130struct NoLocationsFoundInNixpkgsException : std::exception {
131 [[nodiscard]]
const char *what()
const noexcept override {
132 return "no locations found in nixpkgs";
136class WorkerReportedException : std::exception {
140 WorkerReportedException(llvm::Error E) : E(std::move(E)) {};
142 llvm::Error takeError() {
return std::move(E); }
143 [[nodiscard]]
const char *what()
const noexcept override {
144 return "worker reported some error";
153class NixpkgsDefinitionProvider {
159 auto Pos =
Position.find_first_of(
':');
160 if (Pos == std::string_view::npos) {
163 .range = {{0, 0}, {0, 0}},
166 int PosL = std::stoi(std::string(
Position.substr(Pos + 1)));
177 : NixpkgsClient(NixpkgsClient) {}
180 std::binary_semaphore Ready(0);
181 Expected<AttrPathInfoResponse> Desc =
error(
"not replied");
182 auto OnReply = [&Ready, &Desc](llvm::Expected<AttrPathInfoResponse> Resp) {
186 Desc = Resp.takeError();
193 throw WorkerReportedException(Desc.takeError());
196 if (
const std::optional<std::string> &
Position = Desc->PackageDesc.
Position)
200 if (
const auto &Loc = Desc->Meta.Location)
203 throw NoLocationsFoundInNixpkgsException();
208class OptionsDefinitionProvider {
212 OptionsDefinitionProvider(
AttrSetClient &Client) : Client(Client) {}
213 void resolveLocations(
const std::vector<std::string> &Params,
215 std::binary_semaphore Ready(0);
216 Expected<OptionInfoResponse>
Info =
error(
"not replied");
218 auto OnReply = [&Ready, &
Info](llvm::Expected<OptionInfoResponse> Resp) {
219 Info = std::move(Resp);
224 Client.
optionInfo(Params, std::move(OnReply));
228 elog(
"getting locations: {0}",
Info.takeError());
232 for (
const auto &Decl :
Info->Declarations)
233 Locs.emplace_back(Decl);
241 const std::string &BasePath) {
243 if (!
Path.parts().isLiteral())
250 .range = {{0, 0}, {0, 0}},
260 std::mutex &OptionsLock,
263 std::vector<std::string> Scope;
266 if (R == PathResult::OK) {
267 std::lock_guard _(OptionsLock);
269 for (
const auto &[_, Client] : Options) {
271 OptionsDefinitionProvider ODP(*C);
272 ODP.resolveLocations(Scope, Locs);
284 NixpkgsDefinitionProvider NDP(NixpkgsClient);
285 return NDP.resolveSelector(Sel);
286 }
catch (NoLocationsFoundInNixpkgsException &E) {
287 elog(
"definition/idiom: {0}", E.what());
288 }
catch (WorkerReportedException &E) {
289 elog(
"definition/idiom/worker: {0}", E.takeError());
301 return defineNixpkgsSelector(
mkSelector(Sel, VLA, PM), NixpkgsClient);
303 elog(
"defintion/idiom/selector: {0}", E.what());
310 const Definition &Def = findVarDefinition(Var, VLA);
311 return {convertToLocation(Src, Def,
URI)};
315std::vector<T> mergeVec(std::vector<T> A,
const std::vector<T> &B) {
316 A.insert(A.end(), B.begin(), B.end());
320llvm::Expected<Locations>
325 Locations StaticLocs = defineVarStatic(Var, VLA,
URI, Src);
330 Locations NixpkgsLocs = defineNixpkgsSelector(Sel, NixpkgsClient);
331 return mergeVec(std::move(StaticLocs), NixpkgsLocs);
332 }
catch (std::exception &E) {
333 elog(
"definition/idiom/selector: {0}", E.what());
336 }
catch (std::exception &E) {
337 elog(
"definition/static: {0}", E.what());
340 return error(
"unreachable code! Please submit an issue");
344template <
class T> llvm::json::Value squash(std::vector<T> List) {
345 std::size_t Size = List.size();
350 return std::move(List.back());
354 return std::move(List);
358llvm::Expected<llvm::json::Value> squash(llvm::Expected<std::vector<T>> List) {
360 return List.takeError();
361 return squash(std::move(*List));
369 const ExprVar *Var = findVar(N, PMA, VLA);
370 if (!Var) [[unlikely]] {
371 if (
const Definition *Def = findSelfDefinition(N, PMA, VLA))
375 assert(Var->
kind() == Node::NK_ExprVar);
376 return findVarDefinition(*Var, VLA);
384 const auto File =
URI.file().str();
385 return Reply(squash([&]() -> llvm::Expected<Locations> {
388 const auto &VLA = *TU->variableLookup();
389 const auto &PM = *TU->parentMap();
390 const auto &N = *
CheckDefault(AST->descend({Pos, Pos}));
394 if (
const ExprVar *Var = findInheritVar(N, PM, VLA))
395 return defineVar(*Var, VLA, PM, *nixpkgsClient(),
URI, TU->src());
397 switch (UpExpr.kind()) {
398 case Node::NK_ExprVar: {
399 const auto &Var =
static_cast<const ExprVar &
>(UpExpr);
400 return defineVar(Var, VLA, PM, *nixpkgsClient(),
URI, TU->src());
402 case Node::NK_ExprSelect: {
403 const auto &Sel =
static_cast<const ExprSelect &
>(UpExpr);
404 return defineSelect(Sel, VLA, PM, *nixpkgsClient());
406 case Node::NK_ExprAttrs:
407 return defineAttrPath(N, PM, OptionsLock, Options);
408 case Node::NK_ExprPath: {
409 const auto &
Path =
static_cast<const ExprPath &
>(UpExpr);
410 if (
auto Loc = definePath(
Path,
File))
417 return error(
"unknown node type for definition");
420 boost::asio::post(Pool, std::move(Action));
This file declares some common analysis (tree walk) on the AST.
Types used in nixpkgs provider.
#define CheckDefault(x)
Variant of CheckReturn, but returns default constructed CheckTy.
Convert between LSP and nixf types.
std::vector< Location > Locations
VariableLookupAnalysis::LookupResult LookupResult
VariableLookupAnalysis::LookupResultKind ResultKind
Shared path resolution utilities for Nix path literals.
Lookup variable names, from it's parent scope.
void optionInfo(const AttrPathInfoParams &Params, lspserver::Callback< OptionInfoResponse > Reply)
void attrpathInfo(const AttrPathInfoParams &Params, lspserver::Callback< AttrPathInfoResponse > Reply)
std::map< std::string, std::unique_ptr< AttrSetClientProc > > OptionMapTy
const Node * syntax() const
const SemaAttrs & sema() const
LexerCursorRange range() const
const Node * upTo(const Node &N, Node::NodeKind Kind) const
Search up until some kind of node is found.
const Node * query(const Node &N) const
Attribute set after deduplication.
const std::map< std::string, Attribute > & staticAttrs() const
Static attributes, do not require evaluation to get the key.
const Definition * toDef(const Node &N) const
Get definition record for some name.
LookupResult query(const ExprVar &Var) const
Query the which name/with binds to specific varaible.
Whether current platform treats paths case insensitively.
llvm::unique_function< void(llvm::Expected< T >)> Callback
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&...Vals)
@ Info
An information message.
void elog(const char *Fmt, Ts &&...Vals)
Selector mkVarSelector(const nixf::ExprVar &Var, const nixf::VariableLookupAnalysis &VLA, const nixf::ParentMapAnalysis &PM)
Construct a nixd::Selector from Var.
Selector mkSelector(const nixf::AttrPath &AP, Selector BaseSelector)
Construct a nixd::Selector from AP.
std::optional< std::string > resolveExprPath(const std::string &BasePath, const std::string &ExprPath)
Resolve a Nix expression path to a real filesystem path.
std::vector< std::string > Selector
A list of strings that "select"s into a attribute set.
nixf::Position toNixfPosition(const lspserver::Position &P)
const nixf::Definition & findDefinition(const nixf::Node &N, const nixf::ParentMapAnalysis &PMA, const nixf::VariableLookupAnalysis &VLA)
Heuristically find definition on some node.
FindAttrPathResult findAttrPathForOptions(const nixf::Node &N, const nixf::ParentMapAnalysis &PM, std::vector< std::string > &Path)
Heuristically find attrpath suitable for "attrpath" completion. Strips "config." from the start to su...
lspserver::Range toLSPRange(llvm::StringRef Code, const nixf::LexerCursorRange &R)
std::vector< OptionField > OptionCompleteResponse
URIForFile uri
The text document's URI.
Position position
The position inside the text document.
TextDocumentIdentifier textDocument
The text document.
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Exceptions scoped in nixd::mkIdiomSelector.
std::shared_ptr< const Definition > Def