Also display suggestions for the commands using the eval cache
Make `nix build .#nix-armv8l-linux` work for example
This commit is contained in:
parent
2405bbbb5e
commit
98e361ad4c
|
@ -272,9 +272,9 @@ void completeFlakeRefWithFragment(
|
||||||
auto attr = root->findAlongAttrPath(attrPath);
|
auto attr = root->findAlongAttrPath(attrPath);
|
||||||
if (!attr) continue;
|
if (!attr) continue;
|
||||||
|
|
||||||
for (auto & attr2 : attr->getAttrs()) {
|
for (auto & attr2 : (*attr)->getAttrs()) {
|
||||||
if (hasPrefix(attr2, lastAttr)) {
|
if (hasPrefix(attr2, lastAttr)) {
|
||||||
auto attrPath2 = attr->getAttrPath(attr2);
|
auto attrPath2 = (*attr)->getAttrPath(attr2);
|
||||||
/* Strip the attrpath prefix. */
|
/* Strip the attrpath prefix. */
|
||||||
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
|
attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size());
|
||||||
completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2));
|
completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2));
|
||||||
|
@ -568,15 +568,22 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
||||||
auto cache = openEvalCache(*state, lockedFlake);
|
auto cache = openEvalCache(*state, lockedFlake);
|
||||||
auto root = cache->getRoot();
|
auto root = cache->getRoot();
|
||||||
|
|
||||||
|
Suggestions suggestions;
|
||||||
|
|
||||||
for (auto & attrPath : getActualAttrPaths()) {
|
for (auto & attrPath : getActualAttrPaths()) {
|
||||||
debug("trying flake output attribute '%s'", attrPath);
|
debug("trying flake output attribute '%s'", attrPath);
|
||||||
|
|
||||||
auto attr = root->findAlongAttrPath(
|
auto attrOrSuggestions = root->findAlongAttrPath(
|
||||||
parseAttrPath(*state, attrPath),
|
parseAttrPath(*state, attrPath),
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!attr) continue;
|
if (!attrOrSuggestions) {
|
||||||
|
suggestions += attrOrSuggestions.getSuggestions();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto attr = *attrOrSuggestions;
|
||||||
|
|
||||||
if (!attr->isDerivation())
|
if (!attr->isDerivation())
|
||||||
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
throw Error("flake output attribute '%s' is not a derivation", attrPath);
|
||||||
|
@ -591,7 +598,7 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF
|
||||||
return {attrPath, lockedFlake->flake.lockedRef, std::move(drvInfo)};
|
return {attrPath, lockedFlake->flake.lockedRef, std::move(drvInfo)};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error("flake '%s' does not provide attribute %s",
|
throw Error(suggestions, "flake '%s' does not provide attribute %s",
|
||||||
flakeRef, showAttrPaths(getActualAttrPaths()));
|
flakeRef, showAttrPaths(getActualAttrPaths()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,7 +649,7 @@ InstallableFlake::getCursors(EvalState & state)
|
||||||
|
|
||||||
for (auto & attrPath : getActualAttrPaths()) {
|
for (auto & attrPath : getActualAttrPaths()) {
|
||||||
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath));
|
||||||
if (attr) res.push_back({attr, attrPath});
|
if (attr) res.push_back({*attr, attrPath});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -406,6 +406,16 @@ Value & AttrCursor::forceValue()
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Suggestions AttrCursor::getSuggestionsForAttr(Symbol name)
|
||||||
|
{
|
||||||
|
auto attrNames = getAttrs();
|
||||||
|
std::set<std::string> strAttrNames;
|
||||||
|
for (auto & name : attrNames)
|
||||||
|
strAttrNames.insert(std::string(name));
|
||||||
|
|
||||||
|
return Suggestions::bestMatches(strAttrNames, name);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
|
std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErrors)
|
||||||
{
|
{
|
||||||
if (root->db) {
|
if (root->db) {
|
||||||
|
@ -446,6 +456,11 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
|
||||||
return nullptr;
|
return nullptr;
|
||||||
//throw TypeError("'%s' is not an attribute set", getAttrPathStr());
|
//throw TypeError("'%s' is not an attribute set", getAttrPathStr());
|
||||||
|
|
||||||
|
for (auto & attr : *v.attrs) {
|
||||||
|
if (root->db)
|
||||||
|
root->db->setPlaceholder({cachedValue->first, attr.name});
|
||||||
|
}
|
||||||
|
|
||||||
auto attr = v.attrs->get(name);
|
auto attr = v.attrs->get(name);
|
||||||
|
|
||||||
if (!attr) {
|
if (!attr) {
|
||||||
|
@ -464,7 +479,7 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(Symbol name, bool forceErro
|
||||||
cachedValue2 = {root->db->setPlaceholder({cachedValue->first, name}), placeholder_t()};
|
cachedValue2 = {root->db->setPlaceholder({cachedValue->first, name}), placeholder_t()};
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<AttrCursor>(
|
return make_ref<AttrCursor>(
|
||||||
root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2));
|
root, std::make_pair(shared_from_this(), name), attr->value, std::move(cachedValue2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,27 +488,31 @@ std::shared_ptr<AttrCursor> AttrCursor::maybeGetAttr(std::string_view name)
|
||||||
return maybeGetAttr(root->state.symbols.create(name));
|
return maybeGetAttr(root->state.symbols.create(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
|
ref<AttrCursor> AttrCursor::getAttr(Symbol name, bool forceErrors)
|
||||||
{
|
{
|
||||||
auto p = maybeGetAttr(name, forceErrors);
|
auto p = maybeGetAttr(name, forceErrors);
|
||||||
if (!p)
|
if (!p)
|
||||||
throw Error("attribute '%s' does not exist", getAttrPathStr(name));
|
throw Error("attribute '%s' does not exist", getAttrPathStr(name));
|
||||||
return p;
|
return ref(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> AttrCursor::getAttr(std::string_view name)
|
ref<AttrCursor> AttrCursor::getAttr(std::string_view name)
|
||||||
{
|
{
|
||||||
return getAttr(root->state.symbols.create(name));
|
return getAttr(root->state.symbols.create(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force)
|
OrSuggestions<ref<AttrCursor>> AttrCursor::findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force)
|
||||||
{
|
{
|
||||||
auto res = shared_from_this();
|
auto res = shared_from_this();
|
||||||
for (auto & attr : attrPath) {
|
for (auto & attr : attrPath) {
|
||||||
res = res->maybeGetAttr(attr, force);
|
auto child = res->maybeGetAttr(attr, force);
|
||||||
if (!res) return {};
|
if (!child) {
|
||||||
|
auto suggestions = res->getSuggestionsForAttr(attr);
|
||||||
|
return OrSuggestions<ref<AttrCursor>>::failed(suggestions);
|
||||||
}
|
}
|
||||||
return res;
|
res = child;
|
||||||
|
}
|
||||||
|
return ref(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AttrCursor::getString()
|
std::string AttrCursor::getString()
|
||||||
|
|
|
@ -94,15 +94,17 @@ public:
|
||||||
|
|
||||||
std::string getAttrPathStr(Symbol name) const;
|
std::string getAttrPathStr(Symbol name) const;
|
||||||
|
|
||||||
|
Suggestions getSuggestionsForAttr(Symbol name);
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name, bool forceErrors = false);
|
std::shared_ptr<AttrCursor> maybeGetAttr(Symbol name, bool forceErrors = false);
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);
|
std::shared_ptr<AttrCursor> maybeGetAttr(std::string_view name);
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
|
ref<AttrCursor> getAttr(Symbol name, bool forceErrors = false);
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> getAttr(std::string_view name);
|
ref<AttrCursor> getAttr(std::string_view name);
|
||||||
|
|
||||||
std::shared_ptr<AttrCursor> findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force = false);
|
OrSuggestions<ref<AttrCursor>> findAlongAttrPath(const std::vector<Symbol> & attrPath, bool force = false);
|
||||||
|
|
||||||
std::string getString();
|
std::string getString();
|
||||||
|
|
||||||
|
|
|
@ -40,4 +40,62 @@ public:
|
||||||
Suggestions& operator+=(const Suggestions & other);
|
Suggestions& operator+=(const Suggestions & other);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Either a value of type `T`, or some suggestions
|
||||||
|
template<typename T>
|
||||||
|
class OrSuggestions {
|
||||||
|
public:
|
||||||
|
using Raw = std::variant<T, Suggestions>;
|
||||||
|
|
||||||
|
Raw raw;
|
||||||
|
|
||||||
|
T* operator ->()
|
||||||
|
{
|
||||||
|
return &**this;
|
||||||
|
}
|
||||||
|
|
||||||
|
T& operator *()
|
||||||
|
{
|
||||||
|
if (auto elt = std::get_if<T>(&raw))
|
||||||
|
return *elt;
|
||||||
|
throw Error("Invalid access to a failed value");
|
||||||
|
}
|
||||||
|
|
||||||
|
operator bool() const noexcept
|
||||||
|
{
|
||||||
|
return std::holds_alternative<T>(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
OrSuggestions(T t)
|
||||||
|
: raw(t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
OrSuggestions()
|
||||||
|
: raw(Suggestions{})
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static OrSuggestions<T> failed(const Suggestions & s)
|
||||||
|
{
|
||||||
|
auto res = OrSuggestions<T>();
|
||||||
|
res.raw = s;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OrSuggestions<T> failed()
|
||||||
|
{
|
||||||
|
return OrSuggestions<T>::failed(Suggestions{});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Suggestions & get_suggestions()
|
||||||
|
{
|
||||||
|
static Suggestions noSuggestions;
|
||||||
|
if (const auto & suggestions = std::get_if<Suggestions>(&raw))
|
||||||
|
return *suggestions;
|
||||||
|
else
|
||||||
|
return noSuggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue