abbr: stop parsing option after first expansion token

Historical behavior is to stop option parsing at the first non-option argument.
Since we have added more options, it seemed impractical to keep that behavior.

However people are using options in their abbr expansions ("abbr e emacs
-nw").  To support this, we ignore options. However, we only ignore them
if they are not valid "abbr" options.  Let's ignore all options in the
expansion definition, which is a small price to pay to keep most existing
configurations working.

Fixes #9410

This does not fix other cases which used to work, like

    abbr x -unknown

Those are hopefully not used by anyone, so I don't think we need to maintain
support for that.
This commit is contained in:
Johannes Altmanninger 2022-12-13 01:18:04 +01:00
parent d14b4b96f0
commit 9790907ca8
2 changed files with 10 additions and 13 deletions

View File

@ -295,8 +295,9 @@ maybe_t<int> builtin_abbr(parser_t &parser, io_streams_t &streams, const wchar_t
int argc = builtin_count_args(argv);
int opt;
wgetopter_t w;
bool unrecognized_options_are_args = false;
while ((opt = w.wgetopt_long(argc, argv, short_options, long_options, nullptr)) != -1) {
bool in_expansion = false;
while (!in_expansion &&
(opt = w.wgetopt_long(argc, argv, short_options, long_options, nullptr)) != -1) {
switch (opt) {
case NON_OPTION_ARGUMENT:
// If --add is specified (or implied by specifying no other commands), all
@ -307,7 +308,7 @@ maybe_t<int> builtin_abbr(parser_t &parser, io_streams_t &streams, const wchar_t
opts.args.push_back(w.woptarg);
if (opts.args.size() >= 2 &&
!(opts.rename || opts.show || opts.list || opts.erase || opts.query)) {
unrecognized_options_are_args = true;
in_expansion = true;
}
break;
case 'a':
@ -376,12 +377,8 @@ maybe_t<int> builtin_abbr(parser_t &parser, io_streams_t &streams, const wchar_t
return STATUS_CMD_OK;
}
case '?': {
if (unrecognized_options_are_args) {
opts.args.push_back(argv[w.woptind - 1]);
} else {
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
builtin_unknown_option(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
}
}

View File

@ -30,10 +30,10 @@ send(r"echo alpha ?")
expect_str(r"<echo alpha >")
# Abbreviation expansions may have multiple words.
sendline(r"abbr --add emacsnw emacs -nw")
sendline(r"abbr --add emacsnw emacs -nw -l")
expect_prompt()
send(r"emacsnw ?")
expect_str(r"<emacs -nw >")
expect_str(r"<emacs -nw -l >")
# Regression test that abbreviations still expand in incomplete positions.
sendline(r"""abbr --erase (abbr --list)""")
@ -103,9 +103,9 @@ expect_prompt()
# Abbreviations which cause the command line to become incomplete or invalid
# are visibly expanded.
sendline(r"abbr openparen '(' --position anywhere")
sendline(r"abbr openparen --position anywhere '('")
expect_prompt()
sendline(r"abbr closeparen ')' --position anywhere")
sendline(r"abbr closeparen --position anywhere ')'")
expect_prompt()
sendline(r"echo openparen")
expect_str(r"echo (")