forked from lix-project/lix
Merge pull request #4128 from tweag/extended-completions
Add a zsh completion script
This commit is contained in:
commit
ea4b2b985f
|
@ -4,13 +4,14 @@ function _complete_nix {
|
||||||
_get_comp_words_by_ref -n ':=&' words cword cur
|
_get_comp_words_by_ref -n ':=&' words cword cur
|
||||||
local have_type
|
local have_type
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
|
local completion=${line%% *}
|
||||||
if [[ -z $have_type ]]; then
|
if [[ -z $have_type ]]; then
|
||||||
have_type=1
|
have_type=1
|
||||||
if [[ $line = filenames ]]; then
|
if [[ $completion = filenames ]]; then
|
||||||
compopt -o filenames
|
compopt -o filenames
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
COMPREPLY+=("$line")
|
COMPREPLY+=("$completion")
|
||||||
fi
|
fi
|
||||||
done < <(NIX_GET_COMPLETIONS=$cword "${words[@]}")
|
done < <(NIX_GET_COMPLETIONS=$cword "${words[@]}")
|
||||||
__ltrim_colon_completions "$cur"
|
__ltrim_colon_completions "$cur"
|
||||||
|
|
21
misc/zsh/completion.zsh
Normal file
21
misc/zsh/completion.zsh
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
function _nix() {
|
||||||
|
local ifs_bk="$IFS"
|
||||||
|
local input=("${(Q)words[@]}")
|
||||||
|
IFS=$'\n'
|
||||||
|
local res=($(NIX_GET_COMPLETIONS=$((CURRENT - 1)) "$input[@]"))
|
||||||
|
IFS="$ifs_bk"
|
||||||
|
local tpe="${${res[1]}%%> *}"
|
||||||
|
local -a suggestions
|
||||||
|
declare -a suggestions
|
||||||
|
for suggestion in ${res:1}; do
|
||||||
|
# FIXME: This doesn't work properly if the suggestion word contains a `:`
|
||||||
|
# itself
|
||||||
|
suggestions+="${suggestion/ /:}"
|
||||||
|
done
|
||||||
|
if [[ "$tpe" == filenames ]]; then
|
||||||
|
compadd -f
|
||||||
|
fi
|
||||||
|
_describe 'nix' suggestions
|
||||||
|
}
|
||||||
|
|
||||||
|
compdef _nix nix
|
|
@ -44,7 +44,7 @@ MixCommonArgs::MixCommonArgs(const string & programName)
|
||||||
globalConfig.getSettings(settings);
|
globalConfig.getSettings(settings);
|
||||||
for (auto & s : settings)
|
for (auto & s : settings)
|
||||||
if (hasPrefix(s.first, prefix))
|
if (hasPrefix(s.first, prefix))
|
||||||
completions->insert(s.first);
|
completions->add(s.first, s.second.description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,8 +17,19 @@ void Args::addFlag(Flag && flag_)
|
||||||
if (flag->shortName) shortFlags[flag->shortName] = flag;
|
if (flag->shortName) shortFlags[flag->shortName] = flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Completions::add(std::string completion, std::string description)
|
||||||
|
{
|
||||||
|
insert(Completion{
|
||||||
|
.completion = completion,
|
||||||
|
.description = description
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Completion::operator<(const Completion & other) const
|
||||||
|
{ return completion < other.completion || (completion == other.completion && description < other.description); }
|
||||||
|
|
||||||
bool pathCompletions = false;
|
bool pathCompletions = false;
|
||||||
std::shared_ptr<std::set<std::string>> completions;
|
std::shared_ptr<Completions> completions;
|
||||||
|
|
||||||
std::string completionMarker = "___COMPLETE___";
|
std::string completionMarker = "___COMPLETE___";
|
||||||
|
|
||||||
|
@ -148,7 +159,7 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
for (auto & [name, flag] : longFlags) {
|
for (auto & [name, flag] : longFlags) {
|
||||||
if (!hiddenCategories.count(flag->category)
|
if (!hiddenCategories.count(flag->category)
|
||||||
&& hasPrefix(name, std::string(*prefix, 2)))
|
&& hasPrefix(name, std::string(*prefix, 2)))
|
||||||
completions->insert("--" + name);
|
completions->add("--" + name, flag->description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto i = longFlags.find(string(*pos, 2));
|
auto i = longFlags.find(string(*pos, 2));
|
||||||
|
@ -165,9 +176,9 @@ bool Args::processFlag(Strings::iterator & pos, Strings::iterator end)
|
||||||
|
|
||||||
if (auto prefix = needsCompletion(*pos)) {
|
if (auto prefix = needsCompletion(*pos)) {
|
||||||
if (prefix == "-") {
|
if (prefix == "-") {
|
||||||
completions->insert("--");
|
completions->add("--");
|
||||||
for (auto & [flag, _] : shortFlags)
|
for (auto & [flagName, flag] : shortFlags)
|
||||||
completions->insert(std::string("-") + flag);
|
completions->add(std::string("-") + flagName, flag->description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,7 +259,7 @@ static void hashTypeCompleter(size_t index, std::string_view prefix)
|
||||||
{
|
{
|
||||||
for (auto & type : hashTypes)
|
for (auto & type : hashTypes)
|
||||||
if (hasPrefix(type, prefix))
|
if (hasPrefix(type, prefix))
|
||||||
completions->insert(type);
|
completions->add(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht)
|
Args::Flag Args::Flag::mkHashTypeFlag(std::string && longName, HashType * ht)
|
||||||
|
@ -292,7 +303,7 @@ static void _completePath(std::string_view prefix, bool onlyDirs)
|
||||||
auto st = lstat(globbuf.gl_pathv[i]);
|
auto st = lstat(globbuf.gl_pathv[i]);
|
||||||
if (!S_ISDIR(st.st_mode)) continue;
|
if (!S_ISDIR(st.st_mode)) continue;
|
||||||
}
|
}
|
||||||
completions->insert(globbuf.gl_pathv[i]);
|
completions->add(globbuf.gl_pathv[i]);
|
||||||
}
|
}
|
||||||
globfree(&globbuf);
|
globfree(&globbuf);
|
||||||
}
|
}
|
||||||
|
@ -385,7 +396,7 @@ MultiCommand::MultiCommand(const Commands & commands)
|
||||||
if (auto prefix = needsCompletion(s)) {
|
if (auto prefix = needsCompletion(s)) {
|
||||||
for (auto & [name, command] : commands)
|
for (auto & [name, command] : commands)
|
||||||
if (hasPrefix(name, *prefix))
|
if (hasPrefix(name, *prefix))
|
||||||
completions->insert(name);
|
completions->add(name);
|
||||||
}
|
}
|
||||||
auto i = commands.find(s);
|
auto i = commands.find(s);
|
||||||
if (i == commands.end())
|
if (i == commands.end())
|
||||||
|
|
|
@ -283,7 +283,17 @@ typedef std::vector<std::pair<std::string, std::string>> Table2;
|
||||||
|
|
||||||
void printTable(std::ostream & out, const Table2 & table);
|
void printTable(std::ostream & out, const Table2 & table);
|
||||||
|
|
||||||
extern std::shared_ptr<std::set<std::string>> completions;
|
struct Completion {
|
||||||
|
std::string completion;
|
||||||
|
std::string description;
|
||||||
|
|
||||||
|
bool operator<(const Completion & other) const;
|
||||||
|
};
|
||||||
|
class Completions : public std::set<Completion> {
|
||||||
|
public:
|
||||||
|
void add(std::string completion, std::string description = "");
|
||||||
|
};
|
||||||
|
extern std::shared_ptr<Completions> completions;
|
||||||
extern bool pathCompletions;
|
extern bool pathCompletions;
|
||||||
|
|
||||||
std::optional<std::string> needsCompletion(std::string_view s);
|
std::optional<std::string> needsCompletion(std::string_view s);
|
||||||
|
|
|
@ -26,7 +26,7 @@ void completeFlakeInputPath(
|
||||||
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
auto flake = flake::getFlake(*evalState, flakeRef, true);
|
||||||
for (auto & input : flake.inputs)
|
for (auto & input : flake.inputs)
|
||||||
if (hasPrefix(input.first, prefix))
|
if (hasPrefix(input.first, prefix))
|
||||||
completions->insert(input.first);
|
completions->add(input.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
MixFlakeOptions::MixFlakeOptions()
|
MixFlakeOptions::MixFlakeOptions()
|
||||||
|
@ -211,7 +211,7 @@ void completeFlakeRefWithFragment(
|
||||||
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->insert(flakeRefS + "#" + concatStringsSep(".", attrPath2));
|
completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ void completeFlakeRefWithFragment(
|
||||||
for (auto & attrPath : defaultFlakeAttrPaths) {
|
for (auto & attrPath : defaultFlakeAttrPaths) {
|
||||||
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
|
auto attr = root->findAlongAttrPath(parseAttrPath(*evalState, attrPath));
|
||||||
if (!attr) continue;
|
if (!attr) continue;
|
||||||
completions->insert(flakeRefS + "#");
|
completions->add(flakeRefS + "#");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ ref<EvalState> EvalCommand::getEvalState()
|
||||||
void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||||
{
|
{
|
||||||
if (prefix == "")
|
if (prefix == "")
|
||||||
completions->insert(".");
|
completions->add(".");
|
||||||
|
|
||||||
completeDir(0, prefix);
|
completeDir(0, prefix);
|
||||||
|
|
||||||
|
@ -254,10 +254,10 @@ void completeFlakeRef(ref<Store> store, std::string_view prefix)
|
||||||
if (!hasPrefix(prefix, "flake:") && hasPrefix(from, "flake:")) {
|
if (!hasPrefix(prefix, "flake:") && hasPrefix(from, "flake:")) {
|
||||||
std::string from2(from, 6);
|
std::string from2(from, 6);
|
||||||
if (hasPrefix(from2, prefix))
|
if (hasPrefix(from2, prefix))
|
||||||
completions->insert(from2);
|
completions->add(from2);
|
||||||
} else {
|
} else {
|
||||||
if (hasPrefix(from, prefix))
|
if (hasPrefix(from, prefix))
|
||||||
completions->insert(from);
|
completions->add(from);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,7 +208,7 @@ void mainWrapped(int argc, char * * argv)
|
||||||
if (completions) {
|
if (completions) {
|
||||||
std::cout << (pathCompletions ? "filenames\n" : "no-filenames\n");
|
std::cout << (pathCompletions ? "filenames\n" : "no-filenames\n");
|
||||||
for (auto & s : *completions)
|
for (auto & s : *completions)
|
||||||
std::cout << s << "\n";
|
std::cout << s.completion << "\t" << s.description << "\n";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue