mirror of
https://github.com/NixOS/nix
synced 2025-06-30 07:33:16 +02:00
Add completion for paths
This commit is contained in:
parent
91ddee6bf0
commit
e0c19ee620
13 changed files with 82 additions and 15 deletions
|
@ -1,6 +1,8 @@
|
|||
#include "args.hh"
|
||||
#include "hash.hh"
|
||||
|
||||
#include <glob.h>
|
||||
|
||||
namespace nix {
|
||||
|
||||
void Args::addFlag(Flag && flag_)
|
||||
|
@ -13,6 +15,7 @@ void Args::addFlag(Flag && flag_)
|
|||
if (flag->shortName) shortFlags[flag->shortName] = flag;
|
||||
}
|
||||
|
||||
bool pathCompletions = false;
|
||||
std::shared_ptr<std::set<std::string>> completions;
|
||||
|
||||
std::string completionMarker = "___COMPLETE___";
|
||||
|
@ -128,8 +131,11 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
|||
else
|
||||
throw UsageError("flag '%s' requires %d argument(s)", name, flag.handler.arity);
|
||||
} else {
|
||||
if (needsCompletion(*pos))
|
||||
if (needsCompletion(*pos)) {
|
||||
if (flag.completer)
|
||||
flag.completer(n, *pos);
|
||||
anyNeedsCompletion = true;
|
||||
}
|
||||
args.push_back(*pos++);
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +220,46 @@ Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht)
|
|||
};
|
||||
}
|
||||
|
||||
void completePath(size_t, std::string_view s)
|
||||
{
|
||||
if (auto prefix = needsCompletion(s)) {
|
||||
pathCompletions = true;
|
||||
glob_t globbuf;
|
||||
if (glob((*prefix + "*").c_str(), GLOB_NOESCAPE | GLOB_TILDE, nullptr, &globbuf) == 0) {
|
||||
for (size_t i = 0; i < globbuf.gl_pathc; ++i)
|
||||
completions->insert(globbuf.gl_pathv[i]);
|
||||
globfree(&globbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Args::expectPathArg(const std::string & label, string * dest, bool optional)
|
||||
{
|
||||
expectedArgs.push_back({
|
||||
.label = label,
|
||||
.arity = 1,
|
||||
.optional = optional,
|
||||
.handler = {[=](std::vector<std::string> ss) {
|
||||
completePath(0, ss[0]);
|
||||
*dest = ss[0];
|
||||
}}
|
||||
});
|
||||
}
|
||||
|
||||
void Args::expectPathArgs(const std::string & label, std::vector<std::string> * dest)
|
||||
{
|
||||
expectedArgs.push_back({
|
||||
.label = label,
|
||||
.arity = 0,
|
||||
.optional = false,
|
||||
.handler = {[=](std::vector<std::string> ss) {
|
||||
for (auto & s : ss)
|
||||
completePath(0, s);
|
||||
*dest = std::move(ss);
|
||||
}}
|
||||
});
|
||||
}
|
||||
|
||||
Strings argvToStrings(int argc, char * * argv)
|
||||
{
|
||||
Strings args;
|
||||
|
|
|
@ -83,6 +83,7 @@ protected:
|
|||
std::string category;
|
||||
Strings labels;
|
||||
Handler handler;
|
||||
std::function<void(size_t, std::string_view)> completer;
|
||||
|
||||
static Flag mkHashTypeFlag(std::string && longName, HashType * ht);
|
||||
};
|
||||
|
@ -98,8 +99,8 @@ protected:
|
|||
struct ExpectedArg
|
||||
{
|
||||
std::string label;
|
||||
size_t arity; // 0 = any
|
||||
bool optional;
|
||||
size_t arity = 0; // 0 = any
|
||||
bool optional = false;
|
||||
std::function<void(std::vector<std::string>)> handler;
|
||||
};
|
||||
|
||||
|
@ -182,6 +183,8 @@ public:
|
|||
}});
|
||||
}
|
||||
|
||||
void expectPathArg(const std::string & label, string * dest, bool optional = false);
|
||||
|
||||
/* Expect 0 or more arguments. */
|
||||
void expectArgs(const std::string & label, std::vector<std::string> * dest)
|
||||
{
|
||||
|
@ -190,6 +193,8 @@ public:
|
|||
}});
|
||||
}
|
||||
|
||||
void expectPathArgs(const std::string & label, std::vector<std::string> * dest);
|
||||
|
||||
friend class MultiCommand;
|
||||
};
|
||||
|
||||
|
@ -257,7 +262,10 @@ typedef std::vector<std::pair<std::string, std::string>> Table2;
|
|||
void printTable(std::ostream & out, const Table2 & table);
|
||||
|
||||
extern std::shared_ptr<std::set<std::string>> completions;
|
||||
extern bool pathCompletions;
|
||||
|
||||
std::optional<std::string> needsCompletion(std::string_view s);
|
||||
|
||||
void completePath(size_t, std::string_view s);
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue