Add sort --unique

This commit is contained in:
Fabian Homborg 2022-04-26 21:10:54 +02:00
parent 54778f65f8
commit c88f648cdf
3 changed files with 47 additions and 2 deletions

View File

@ -21,7 +21,7 @@ Synopsis
path resolve GENERAL_OPTIONS [PATH...]
path change-extension GENERAL_OPTIONS EXTENSION [PATH...]
path sort GENERAL_OPTIONS [(-v | --invert)] \
[--what=basename|dirname|path] [([PATH...]
[-u | --unique] [--what=basename|dirname|path] [([PATH...]
GENERAL_OPTIONS := [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)]
@ -351,6 +351,8 @@ With ``--invert`` or ``-v`` the sort is reversed.
With ``--what=`` only the given path of the path is compared, e.g. ``--what=dirname`` causes only the dirname to be compared, ``--what=basename`` only the basename and ``--what=path`` causes the entire path to be compared (this is the default).
With ``--unique`` or ``-u`` the sort is deduplicated, meaning only the first of a run that have the same key is kept. So if you are sorting by basename, then only the first of each basename is used.
The sort used is stable, so sorting first by basename and then by dirname works and causes the files to be grouped according to directory.
It currently returns 0 if it was given any paths.
@ -368,6 +370,10 @@ Examples
10-foo
2-bar
>_ path sort --unique --what=basename $fish_function_path/*.fish
# prints a list of all function files fish would use, sorted by name.
Combining ``path``
-------------------

View File

@ -157,6 +157,8 @@ struct options_t { //!OCLINT(too many fields)
bool type_valid = false;
bool invert_valid = false;
bool what_valid = false;
bool unique_valid = false;
bool unique = false;
bool have_what = false;
const wchar_t *what = nullptr;
@ -348,6 +350,16 @@ static int handle_flag_v(const wchar_t **argv, parser_t &parser, io_streams_t &s
return STATUS_INVALID_ARGS;
}
static int handle_flag_u(const wchar_t **argv, parser_t &parser, io_streams_t &streams,
const wgetopter_t &w, options_t *opts) {
if (opts->unique_valid) {
opts->unique = true;
return STATUS_CMD_OK;
}
path_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
static int handle_flag_what(const wchar_t **argv, parser_t &parser, io_streams_t &streams,
const wgetopter_t &w, options_t *opts) {
UNUSED(argv);
@ -373,6 +385,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co
short_opts.append(L"fld");
}
if (opts->invert_valid) short_opts.append(L"v");
if (opts->unique_valid) short_opts.append(L"u");
return short_opts;
}
@ -386,6 +399,7 @@ static const struct woption long_options[] = {
{L"perm", required_argument, nullptr, 'p'},
{L"type", required_argument, nullptr, 't'},
{L"invert", required_argument, nullptr, 't'},
{L"unique", no_argument, nullptr, 'u'},
{L"what", required_argument, nullptr, 1},
{}};
@ -396,7 +410,8 @@ static const std::unordered_map<char, decltype(*handle_flag_q)> flag_to_function
{'r', handle_flag_r}, {'w', handle_flag_w},
{'x', handle_flag_x}, {'f', handle_flag_f},
{'l', handle_flag_l}, {'d', handle_flag_d},
{1, handle_flag_what},
{'l', handle_flag_l}, {'d', handle_flag_d},
{'u', handle_flag_u}, {1, handle_flag_what},
};
/// Parse the arguments for flags recognized by a specific string subcommand.
@ -700,6 +715,7 @@ static int path_sort(parser_t &parser, io_streams_t &streams, int argc, const wc
options_t opts;
opts.invert_valid = true;
opts.what_valid = true;
opts.unique_valid = true;
int optind;
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
if (retval != STATUS_CMD_OK) return retval;
@ -745,6 +761,13 @@ static int path_sort(parser_t &parser, io_streams_t &streams, int argc, const wc
else
return (wcsfilecmp_glob(funced[a].c_str(), funced[b].c_str()) > 0);
});
if (opts.unique) {
list.erase(std::unique(list.begin(), list.end(),
[&](const wcstring &a, const wcstring &b) {
return funced[a] == funced[b];
}),
list.end());
}
} else {
// Without --what, we just sort by the entire path,
// so we have no need to transform and such.
@ -755,6 +778,9 @@ static int path_sort(parser_t &parser, io_streams_t &streams, int argc, const wc
else
return (wcsfilecmp_glob(a.c_str(), b.c_str()) > 0);
});
if (opts.unique) {
list.erase(std::unique(list.begin(), list.end()), list.end());
}
}
for (const auto &entry : list) {

View File

@ -155,3 +155,16 @@ path sort --what=basename {def,abc}/{456,123,789,abc,def,0} | path sort --what=d
# CHECK: abc/789
# CHECK: abc/abc
# CHECK: abc/def
path sort --unique --what=basename {def,abc}/{456,123,789} def/{abc,def,0} abc/{foo,bar,baz}
# CHECK: def/0
# CHECK: def/123
# CHECK: def/456
# CHECK: def/789
# CHECK: def/abc
# CHECK: abc/bar
# CHECK: abc/baz
# CHECK: def/def
# CHECK: abc/foo