forked from lix-project/lix
Merge pull request #6618 from afishhh/search-exclude
Add `-e`/`--exclude` flag to `nix search`
This commit is contained in:
commit
b2dea231cf
|
@ -8,9 +8,9 @@ std::string hiliteMatches(
|
||||||
std::string_view prefix,
|
std::string_view prefix,
|
||||||
std::string_view postfix)
|
std::string_view postfix)
|
||||||
{
|
{
|
||||||
// Avoid copy on zero matches
|
// Avoid extra work on zero matches
|
||||||
if (matches.size() == 0)
|
if (matches.size() == 0)
|
||||||
return (std::string) s;
|
return std::string(s);
|
||||||
|
|
||||||
std::sort(matches.begin(), matches.end(), [](const auto & a, const auto & b) {
|
std::sort(matches.begin(), matches.end(), [](const auto & a, const auto & b) {
|
||||||
return a.position() < b.position();
|
return a.position() < b.position();
|
||||||
|
|
|
@ -18,16 +18,24 @@ using namespace nix;
|
||||||
|
|
||||||
std::string wrap(std::string prefix, std::string s)
|
std::string wrap(std::string prefix, std::string s)
|
||||||
{
|
{
|
||||||
return prefix + s + ANSI_NORMAL;
|
return concatStrings(prefix, s, ANSI_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CmdSearch : InstallableCommand, MixJSON
|
struct CmdSearch : InstallableCommand, MixJSON
|
||||||
{
|
{
|
||||||
std::vector<std::string> res;
|
std::vector<std::string> res;
|
||||||
|
std::vector<std::string> excludeRes;
|
||||||
|
|
||||||
CmdSearch()
|
CmdSearch()
|
||||||
{
|
{
|
||||||
expectArgs("regex", &res);
|
expectArgs("regex", &res);
|
||||||
|
addFlag(Flag {
|
||||||
|
.longName = "exclude",
|
||||||
|
.shortName = 'e',
|
||||||
|
.description = "Hide packages whose attribute path, name or description contain *regex*.",
|
||||||
|
.labels = {"regex"},
|
||||||
|
.handler = Handler(&excludeRes),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string description() override
|
std::string description() override
|
||||||
|
@ -62,11 +70,16 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||||
res.push_back("^");
|
res.push_back("^");
|
||||||
|
|
||||||
std::vector<std::regex> regexes;
|
std::vector<std::regex> regexes;
|
||||||
|
std::vector<std::regex> excludeRegexes;
|
||||||
regexes.reserve(res.size());
|
regexes.reserve(res.size());
|
||||||
|
excludeRegexes.reserve(excludeRes.size());
|
||||||
|
|
||||||
for (auto & re : res)
|
for (auto & re : res)
|
||||||
regexes.push_back(std::regex(re, std::regex::extended | std::regex::icase));
|
regexes.push_back(std::regex(re, std::regex::extended | std::regex::icase));
|
||||||
|
|
||||||
|
for (auto & re : excludeRes)
|
||||||
|
excludeRegexes.emplace_back(re, std::regex::extended | std::regex::icase);
|
||||||
|
|
||||||
auto state = getEvalState();
|
auto state = getEvalState();
|
||||||
|
|
||||||
auto jsonOut = json ? std::make_unique<JSONObject>(std::cout) : nullptr;
|
auto jsonOut = json ? std::make_unique<JSONObject>(std::cout) : nullptr;
|
||||||
|
@ -106,6 +119,14 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||||
std::vector<std::smatch> nameMatches;
|
std::vector<std::smatch> nameMatches;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
for (auto & regex : excludeRegexes) {
|
||||||
|
if (
|
||||||
|
std::regex_search(attrPath2, regex)
|
||||||
|
|| std::regex_search(name.name, regex)
|
||||||
|
|| std::regex_search(description, regex))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto & regex : regexes) {
|
for (auto & regex : regexes) {
|
||||||
found = false;
|
found = false;
|
||||||
auto addAll = [&found](std::sregex_iterator it, std::vector<std::smatch> & vec) {
|
auto addAll = [&found](std::sregex_iterator it, std::vector<std::smatch> & vec) {
|
||||||
|
@ -133,15 +154,15 @@ struct CmdSearch : InstallableCommand, MixJSON
|
||||||
jsonElem.attr("version", name.version);
|
jsonElem.attr("version", name.version);
|
||||||
jsonElem.attr("description", description);
|
jsonElem.attr("description", description);
|
||||||
} else {
|
} else {
|
||||||
auto name2 = hiliteMatches(name.name, std::move(nameMatches), ANSI_GREEN, "\e[0;2m");
|
auto name2 = hiliteMatches(name.name, nameMatches, ANSI_GREEN, "\e[0;2m");
|
||||||
if (results > 1) logger->cout("");
|
if (results > 1) logger->cout("");
|
||||||
logger->cout(
|
logger->cout(
|
||||||
"* %s%s",
|
"* %s%s",
|
||||||
wrap("\e[0;1m", hiliteMatches(attrPath2, std::move(attrPathMatches), ANSI_GREEN, "\e[0;1m")),
|
wrap("\e[0;1m", hiliteMatches(attrPath2, attrPathMatches, ANSI_GREEN, "\e[0;1m")),
|
||||||
name.version != "" ? " (" + name.version + ")" : "");
|
name.version != "" ? " (" + name.version + ")" : "");
|
||||||
if (description != "")
|
if (description != "")
|
||||||
logger->cout(
|
logger->cout(
|
||||||
" %s", hiliteMatches(description, std::move(descriptionMatches), ANSI_GREEN, ANSI_NORMAL));
|
" %s", hiliteMatches(description, descriptionMatches, ANSI_GREEN, ANSI_NORMAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,12 +43,23 @@ R""(
|
||||||
# nix search nixpkgs 'firefox|chromium'
|
# nix search nixpkgs 'firefox|chromium'
|
||||||
```
|
```
|
||||||
|
|
||||||
* Search for packages containing `git'`and either `frontend` or `gui`:
|
* Search for packages containing `git` and either `frontend` or `gui`:
|
||||||
|
|
||||||
```console
|
```console
|
||||||
# nix search nixpkgs git 'frontend|gui'
|
# nix search nixpkgs git 'frontend|gui'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
* Search for packages containing `neovim` but hide ones containing either `gui` or `python`:
|
||||||
|
|
||||||
|
```console
|
||||||
|
# nix search nixpkgs neovim -e 'python|gui'
|
||||||
|
```
|
||||||
|
or
|
||||||
|
|
||||||
|
```console
|
||||||
|
# nix search nixpkgs neovim -e 'python' -e 'gui'
|
||||||
|
```
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
|
|
||||||
`nix search` searches *installable* (which must be evaluatable, e.g. a
|
`nix search` searches *installable* (which must be evaluatable, e.g. a
|
||||||
|
|
|
@ -28,11 +28,18 @@ nix search -f search.nix '' |grep -q hello
|
||||||
|
|
||||||
e=$'\x1b' # grep doesn't support \e, \033 or even \x1b
|
e=$'\x1b' # grep doesn't support \e, \033 or even \x1b
|
||||||
# Multiple overlapping regexes
|
# Multiple overlapping regexes
|
||||||
(( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep "$e\[32;1mfoo$e\\[0;1m" | wc -l) == 1 ))
|
(( $(nix search -f search.nix '' 'oo' 'foo' 'oo' | grep -c "$e\[32;1mfoo$e\\[0;1m") == 1 ))
|
||||||
(( $(nix search -f search.nix '' 'broken b' 'en bar' | grep "$e\[32;1mbroken bar$e\\[0m" | wc -l) == 1 ))
|
(( $(nix search -f search.nix '' 'broken b' 'en bar' | grep -c "$e\[32;1mbroken bar$e\\[0m") == 1 ))
|
||||||
|
|
||||||
# Multiple matches
|
# Multiple matches
|
||||||
# Searching for 'o' should yield the 'o' in 'broken bar', the 'oo' in foo and 'o' in hello
|
# Searching for 'o' should yield the 'o' in 'broken bar', the 'oo' in foo and 'o' in hello
|
||||||
(( $(nix search -f search.nix '' 'o' | grep -Eo "$e\[32;1mo{1,2}$e\[(0|0;1)m" | wc -l) == 3 ))
|
(( $(nix search -f search.nix '' 'o' | grep -Eoc "$e\[32;1mo{1,2}$e\[(0|0;1)m") == 3 ))
|
||||||
# Searching for 'b' should yield the 'b' in bar and the two 'b's in 'broken bar'
|
# Searching for 'b' should yield the 'b' in bar and the two 'b's in 'broken bar'
|
||||||
|
# NOTE: This does not work with `grep -c` because it counts the two 'b's in 'broken bar' as one matched line
|
||||||
(( $(nix search -f search.nix '' 'b' | grep -Eo "$e\[32;1mb$e\[(0|0;1)m" | wc -l) == 3 ))
|
(( $(nix search -f search.nix '' 'b' | grep -Eo "$e\[32;1mb$e\[(0|0;1)m" | wc -l) == 3 ))
|
||||||
|
|
||||||
|
## Tests for --exclude
|
||||||
|
(( $(nix search -f search.nix -e hello | grep -c hello) == 0 ))
|
||||||
|
|
||||||
|
(( $(nix search -f search.nix foo --exclude 'foo|bar' | grep -Ec 'foo|bar') == 0 ))
|
||||||
|
(( $(nix search -f search.nix foo -e foo --exclude bar | grep -Ec 'foo|bar') == 0 ))
|
||||||
|
|
Loading…
Reference in a new issue