mirror of
https://github.com/fish-shell/fish-shell
synced 2024-11-10 15:14:44 +00:00
Add --invert to filter/match
Like `grep -v`/`string match -v`.
This commit is contained in:
parent
f6fb347d98
commit
3a9c52cefa
2 changed files with 23 additions and 6 deletions
|
@ -11,7 +11,7 @@ Synopsis
|
|||
path base [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
path dir [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
path extension [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
path filter [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH...]
|
||||
path filter [(-z | --null-in)] [(-Z | --null-out)] [(-v | --invert)] [(-q | --quiet)] [(-t | --type) TYPE] [(-p | --perm) PERMISSION] [PATH...]
|
||||
path normalize [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
path real [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
path strip-extension [(-z | --null-in)] [(-Z | --null-out)] [(-q | --quiet)] [PATH...]
|
||||
|
@ -139,6 +139,8 @@ Note that the path needs to be *any* of the given types, but have *all* of the g
|
|||
|
||||
And if your operating system doesn't support a "sticky" bit, checking for it will always be false, so no path will pass.
|
||||
|
||||
With ``--invert``, the meaning of the filtering is inverted - any path that wouldn't pass (including by not existing) passes, and any path that would pass fails.
|
||||
|
||||
It returns 0 if at least one path passed the filter.
|
||||
|
||||
Examples
|
||||
|
|
|
@ -143,10 +143,10 @@ typedef uint32_t path_perm_flags_t;
|
|||
struct options_t { //!OCLINT(too many fields)
|
||||
bool perm_valid = false;
|
||||
bool type_valid = false;
|
||||
bool invert_valid = false;
|
||||
|
||||
bool null_in = false;
|
||||
bool null_out = false;
|
||||
|
||||
bool quiet = false;
|
||||
|
||||
bool have_type = false;
|
||||
|
@ -156,6 +156,9 @@ struct options_t { //!OCLINT(too many fields)
|
|||
// Whether we need to check a special permission like suid.
|
||||
bool have_special_perm = false;
|
||||
path_perm_flags_t perm = 0;
|
||||
|
||||
bool invert = false;
|
||||
|
||||
};
|
||||
|
||||
static void path_out(io_streams_t &streams, const options_t &opts, const wcstring &str) {
|
||||
|
@ -272,6 +275,16 @@ static int handle_flag_p(const wchar_t **argv, parser_t &parser, io_streams_t &s
|
|||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
static int handle_flag_v(const wchar_t **argv, parser_t &parser, io_streams_t &streams,
|
||||
const wgetopter_t &w, options_t *opts) {
|
||||
if (opts->invert_valid) {
|
||||
opts->invert = true;
|
||||
return STATUS_CMD_OK;
|
||||
}
|
||||
path_unknown_option(parser, streams, argv[0], argv[w.woptind - 1]);
|
||||
return STATUS_INVALID_ARGS;
|
||||
}
|
||||
|
||||
/// This constructs the wgetopt() short options string based on which arguments are valid for the
|
||||
/// subcommand. We have to do this because many short flags have multiple meanings and may or may
|
||||
/// not require an argument depending on the meaning.
|
||||
|
@ -280,6 +293,7 @@ static wcstring construct_short_opts(options_t *opts) { //!OCLINT(high npath co
|
|||
wcstring short_opts(L":zZq");
|
||||
if (opts->perm_valid) short_opts.append(L"p:");
|
||||
if (opts->type_valid) short_opts.append(L"t:");
|
||||
if (opts->invert_valid) short_opts.append(L"v");
|
||||
return short_opts;
|
||||
}
|
||||
|
||||
|
@ -292,10 +306,11 @@ static const struct woption long_options[] = {
|
|||
{L"null-output", no_argument, nullptr, 'Z'},
|
||||
{L"perm", required_argument, nullptr, 'p'},
|
||||
{L"type", required_argument, nullptr, 't'},
|
||||
{L"invert", required_argument, nullptr, 't'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
static const std::unordered_map<char, decltype(*handle_flag_q)> flag_to_function = {
|
||||
{'q', handle_flag_q},
|
||||
{'q', handle_flag_q}, {'v', handle_flag_v},
|
||||
{'z', handle_flag_z}, {'Z', handle_flag_Z},
|
||||
{'t', handle_flag_t}, {'p', handle_flag_p},
|
||||
};
|
||||
|
@ -562,13 +577,13 @@ static int path_real(parser_t &parser, io_streams_t &streams, int argc, const wc
|
|||
}
|
||||
|
||||
|
||||
// `path filter`
|
||||
// All strings are taken to be filenames, and if they match the type/perms/etc (and exist!)
|
||||
// they are passed along.
|
||||
static int path_filter(parser_t &parser, io_streams_t &streams, int argc, const wchar_t **argv) {
|
||||
options_t opts;
|
||||
opts.type_valid = true;
|
||||
opts.perm_valid = true;
|
||||
opts.invert_valid = true;
|
||||
int optind;
|
||||
int retval = parse_opts(&opts, &optind, argc, argv, parser, streams);
|
||||
if (retval != STATUS_CMD_OK) return retval;
|
||||
|
@ -576,11 +591,11 @@ static int path_filter(parser_t &parser, io_streams_t &streams, int argc, const
|
|||
int n_transformed = 0;
|
||||
arg_iterator_t aiter(argv, optind, streams, opts.null_in ? '\0' : '\n');
|
||||
while (const wcstring *arg = aiter.nextstr()) {
|
||||
if (filter_path(opts, *arg)) {
|
||||
if ((!opts.invert || (!opts.have_perm && !opts.have_type)) && filter_path(opts, *arg)) {
|
||||
// If we don't have filters, check if it exists.
|
||||
// (for match this is done by the glob already)
|
||||
if (!opts.have_type && !opts.have_perm) {
|
||||
if (waccess(*arg, F_OK)) continue;
|
||||
if (!(!waccess(*arg, F_OK) ^ opts.invert)) continue;
|
||||
}
|
||||
|
||||
path_out(streams, opts, *arg);
|
||||
|
|
Loading…
Reference in a new issue