forked from lix-project/lix
Fix flake input completion for InstallablesCommand
s
Defers completion of flake inputs until the whole command line is parsed so that we know what flakes we need to complete the inputs of. Previously, `nix build flake --update-input <Tab>` always behaved like `nix build . --update-input <Tab>`.
This commit is contained in:
parent
d6d0e781bb
commit
711b2e1f48
|
@ -77,12 +77,16 @@ struct MixFlakeOptions : virtual Args, EvalCommand
|
||||||
{
|
{
|
||||||
flake::LockFlags lockFlags;
|
flake::LockFlags lockFlags;
|
||||||
|
|
||||||
|
std::optional<std::string> needsFlakeInputCompletion = {};
|
||||||
|
|
||||||
MixFlakeOptions();
|
MixFlakeOptions();
|
||||||
|
|
||||||
virtual std::vector<std::string> getFlakesForCompletion()
|
virtual std::vector<std::string> getFlakesForCompletion()
|
||||||
{ return {}; }
|
{ return {}; }
|
||||||
|
|
||||||
void completeFlakeInput(std::string_view prefix);
|
void completeFlakeInput(std::string_view prefix);
|
||||||
|
|
||||||
|
void completionHook() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
struct SourceExprCommand : virtual Args, MixFlakeOptions
|
||||||
|
|
|
@ -23,18 +23,6 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void MixFlakeOptions::completeFlakeInput(std::string_view prefix)
|
|
||||||
{
|
|
||||||
auto evalState = getEvalState();
|
|
||||||
for (auto & flakeRefS : getFlakesForCompletion()) {
|
|
||||||
auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first;
|
|
||||||
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
|
||||||
for (auto & input : flake.inputs)
|
|
||||||
if (hasPrefix(input.first, prefix))
|
|
||||||
completions->add(input.first);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MixFlakeOptions::MixFlakeOptions()
|
MixFlakeOptions::MixFlakeOptions()
|
||||||
{
|
{
|
||||||
auto category = "Common flake-related options";
|
auto category = "Common flake-related options";
|
||||||
|
@ -87,7 +75,7 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
|
lockFlags.inputUpdates.insert(flake::parseInputPath(s));
|
||||||
}},
|
}},
|
||||||
.completer = {[&](size_t, std::string_view prefix) {
|
.completer = {[&](size_t, std::string_view prefix) {
|
||||||
completeFlakeInput(prefix);
|
needsFlakeInputCompletion = {std::string(prefix)};
|
||||||
}}
|
}}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -104,7 +92,7 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
}},
|
}},
|
||||||
.completer = {[&](size_t n, std::string_view prefix) {
|
.completer = {[&](size_t n, std::string_view prefix) {
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
completeFlakeInput(prefix);
|
needsFlakeInputCompletion = {std::string(prefix)};
|
||||||
else if (n == 1)
|
else if (n == 1)
|
||||||
completeFlakeRef(getEvalState()->store, prefix);
|
completeFlakeRef(getEvalState()->store, prefix);
|
||||||
}}
|
}}
|
||||||
|
@ -137,6 +125,24 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MixFlakeOptions::completeFlakeInput(std::string_view prefix)
|
||||||
|
{
|
||||||
|
auto evalState = getEvalState();
|
||||||
|
for (auto & flakeRefS : getFlakesForCompletion()) {
|
||||||
|
auto flakeRef = parseFlakeRefWithFragment(expandTilde(flakeRefS), absPath(".")).first;
|
||||||
|
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
||||||
|
for (auto & input : flake.inputs)
|
||||||
|
if (hasPrefix(input.first, prefix))
|
||||||
|
completions->add(input.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MixFlakeOptions::completionHook()
|
||||||
|
{
|
||||||
|
if (auto & prefix = needsFlakeInputCompletion)
|
||||||
|
completeFlakeInput(*prefix);
|
||||||
|
}
|
||||||
|
|
||||||
SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
|
SourceExprCommand::SourceExprCommand(bool supportReadOnlyMode)
|
||||||
{
|
{
|
||||||
addFlag({
|
addFlag({
|
||||||
|
|
|
@ -124,7 +124,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
bool anyCompleted = false;
|
bool anyCompleted = false;
|
||||||
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
|
for (size_t n = 0 ; n < flag.handler.arity; ++n) {
|
||||||
if (pos == end) {
|
if (pos == end) {
|
||||||
if (flag.handler.arity == ArityAny) break;
|
if (flag.handler.arity == ArityAny || anyCompleted) break;
|
||||||
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
|
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
|
||||||
}
|
}
|
||||||
if (auto prefix = needsCompletion(*pos)) {
|
if (auto prefix = needsCompletion(*pos)) {
|
||||||
|
@ -362,6 +362,14 @@ bool MultiCommand::processArgs(const Strings & args, bool finish)
|
||||||
return Args::processArgs(args, finish);
|
return Args::processArgs(args, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MultiCommand::completionHook()
|
||||||
|
{
|
||||||
|
if (command)
|
||||||
|
return command->second->completionHook();
|
||||||
|
else
|
||||||
|
return Args::completionHook();
|
||||||
|
}
|
||||||
|
|
||||||
nlohmann::json MultiCommand::toJSON()
|
nlohmann::json MultiCommand::toJSON()
|
||||||
{
|
{
|
||||||
auto cmds = nlohmann::json::object();
|
auto cmds = nlohmann::json::object();
|
||||||
|
|
|
@ -148,6 +148,11 @@ protected:
|
||||||
argument (if any) have been processed. */
|
argument (if any) have been processed. */
|
||||||
virtual void initialFlagsProcessed() {}
|
virtual void initialFlagsProcessed() {}
|
||||||
|
|
||||||
|
/* Called after the command line has been processed if we need to generate
|
||||||
|
completions. Useful for commands that need to know the whole command line
|
||||||
|
in order to know what completions to generate. */
|
||||||
|
virtual void completionHook() { }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void addFlag(Flag && flag);
|
void addFlag(Flag && flag);
|
||||||
|
@ -223,6 +228,8 @@ public:
|
||||||
|
|
||||||
bool processArgs(const Strings & args, bool finish) override;
|
bool processArgs(const Strings & args, bool finish) override;
|
||||||
|
|
||||||
|
void completionHook() override;
|
||||||
|
|
||||||
nlohmann::json toJSON() override;
|
nlohmann::json toJSON() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -342,7 +342,10 @@ void mainWrapped(int argc, char * * argv)
|
||||||
if (!completions) throw;
|
if (!completions) throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completions) return;
|
if (completions) {
|
||||||
|
args.completionHook();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (args.showVersion) {
|
if (args.showVersion) {
|
||||||
printVersion(programName);
|
printVersion(programName);
|
||||||
|
|
Loading…
Reference in a new issue