mirror of
https://github.com/fish-shell/fish-shell.git
synced 2025-03-27 14:45:13 +08:00
Add sort --unique
This commit is contained in:
parent
54778f65f8
commit
c88f648cdf
@ -21,7 +21,7 @@ Synopsis
|
|||||||
path resolve GENERAL_OPTIONS [PATH...]
|
path resolve GENERAL_OPTIONS [PATH...]
|
||||||
path change-extension GENERAL_OPTIONS EXTENSION [PATH...]
|
path change-extension GENERAL_OPTIONS EXTENSION [PATH...]
|
||||||
path sort GENERAL_OPTIONS [(-v | --invert)] \
|
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)]
|
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 ``--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.
|
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.
|
It currently returns 0 if it was given any paths.
|
||||||
@ -368,6 +370,10 @@ Examples
|
|||||||
10-foo
|
10-foo
|
||||||
2-bar
|
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``
|
Combining ``path``
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -157,6 +157,8 @@ struct options_t { //!OCLINT(too many fields)
|
|||||||
bool type_valid = false;
|
bool type_valid = false;
|
||||||
bool invert_valid = false;
|
bool invert_valid = false;
|
||||||
bool what_valid = false;
|
bool what_valid = false;
|
||||||
|
bool unique_valid = false;
|
||||||
|
bool unique = false;
|
||||||
bool have_what = false;
|
bool have_what = false;
|
||||||
const wchar_t *what = nullptr;
|
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;
|
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,
|
static int handle_flag_what(const wchar_t **argv, parser_t &parser, io_streams_t &streams,
|
||||||
const wgetopter_t &w, options_t *opts) {
|
const wgetopter_t &w, options_t *opts) {
|
||||||
UNUSED(argv);
|
UNUSED(argv);
|
||||||
@ -373,6 +385,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co
|
|||||||
short_opts.append(L"fld");
|
short_opts.append(L"fld");
|
||||||
}
|
}
|
||||||
if (opts->invert_valid) short_opts.append(L"v");
|
if (opts->invert_valid) short_opts.append(L"v");
|
||||||
|
if (opts->unique_valid) short_opts.append(L"u");
|
||||||
return short_opts;
|
return short_opts;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,6 +399,7 @@ static const struct woption long_options[] = {
|
|||||||
{L"perm", required_argument, nullptr, 'p'},
|
{L"perm", required_argument, nullptr, 'p'},
|
||||||
{L"type", required_argument, nullptr, 't'},
|
{L"type", required_argument, nullptr, 't'},
|
||||||
{L"invert", required_argument, nullptr, 't'},
|
{L"invert", required_argument, nullptr, 't'},
|
||||||
|
{L"unique", no_argument, nullptr, 'u'},
|
||||||
{L"what", required_argument, nullptr, 1},
|
{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},
|
{'r', handle_flag_r}, {'w', handle_flag_w},
|
||||||
{'x', handle_flag_x}, {'f', handle_flag_f},
|
{'x', handle_flag_x}, {'f', handle_flag_f},
|
||||||
{'l', handle_flag_l}, {'d', handle_flag_d},
|
{'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.
|
/// 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;
|
options_t opts;
|
||||||
opts.invert_valid = true;
|
opts.invert_valid = true;
|
||||||
opts.what_valid = true;
|
opts.what_valid = true;
|
||||||
|
opts.unique_valid = true;
|
||||||
int optind;
|
int optind;
|
||||||
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
|
int retval = parse_opts(&opts, &optind, 0, argc, argv, parser, streams);
|
||||||
if (retval != STATUS_CMD_OK) return retval;
|
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
|
else
|
||||||
return (wcsfilecmp_glob(funced[a].c_str(), funced[b].c_str()) > 0);
|
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 {
|
} else {
|
||||||
// Without --what, we just sort by the entire path,
|
// Without --what, we just sort by the entire path,
|
||||||
// so we have no need to transform and such.
|
// 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
|
else
|
||||||
return (wcsfilecmp_glob(a.c_str(), b.c_str()) > 0);
|
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) {
|
for (const auto &entry : list) {
|
||||||
|
@ -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/789
|
||||||
# CHECK: abc/abc
|
# CHECK: abc/abc
|
||||||
# CHECK: abc/def
|
# 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
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user