builtin_complete: Allow complete -C something

This is a long-standing issue with how `complete --do-complete` does
its argument parsing: It takes an optional argument, so it has to be
attached to the token like `complete --do-complete=foo` or (worse)
`complete -Cfoo`.

But since `complete` doesn't take any bare arguments otherwise (it
would error with "too many arguments" if you did `complete -C foo`) we
can just take one free argument as the argument to `--do-complete`.

It's more of a command than an option anyway, since it entirely
changes what the `complete` call _does_.
This commit is contained in:
Fabian Homborg 2019-04-26 14:54:51 +02:00
parent cd86c0ee88
commit 22ce8c23c6
3 changed files with 28 additions and 11 deletions

View file

@ -120,6 +120,7 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
wcstring_list_t gnu_opt, old_opt;
const wchar_t *comp = L"", *desc = L"", *condition = L"";
bool do_complete = false;
bool have_do_complete_param = false;
wcstring do_complete_param;
wcstring_list_t cmd_to_complete;
wcstring_list_t path;
@ -236,14 +237,8 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
case 'C': {
do_complete = true;
const wchar_t *arg = w.woptarg ? w.woptarg : reader_get_buffer();
if (arg == NULL) {
// This corresponds to using 'complete -C' in non-interactive mode.
// See #2361.
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
do_complete_param = arg;
have_do_complete_param = w.woptarg != NULL;
if (have_do_complete_param) do_complete_param = w.woptarg;
break;
}
case 'h': {
@ -266,9 +261,17 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
if (w.woptind != argc) {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
// Use one left-over arg as the do-complete argument
// to enable `complete -C "git check"`.
if (do_complete && !have_do_complete_param && argc == w.woptind + 1) {
do_complete_param = argv[argc - 1];
have_do_complete_param = true;
} else {
streams.err.append_format(BUILTIN_ERR_TOO_MANY_ARGUMENTS, cmd);
builtin_print_error_trailer(parser, streams.err, cmd);
return STATUS_INVALID_ARGS;
}
}
if (condition && std::wcslen(condition)) {
@ -302,6 +305,17 @@ int builtin_complete(parser_t &parser, io_streams_t &streams, wchar_t **argv) {
}
if (do_complete) {
if (!have_do_complete_param) {
// No argument given, try to use the current commandline.
const wchar_t* cmd = reader_get_buffer();
if (cmd == NULL) {
// This corresponds to using 'complete -C' in non-interactive mode.
// See #2361 .
builtin_missing_argument(parser, streams, cmd, argv[w.woptind - 1]);
return STATUS_INVALID_ARGS;
}
do_complete_param = cmd;
}
const wchar_t *token;
parse_util_token_extent(do_complete_param.c_str(), do_complete_param.size(), &token, 0, 0,

View file

@ -9,6 +9,8 @@ complete -c complete_test_alpha3 --no-files -w 'complete_test_alpha2 extra2'
complete -C'complete_test_alpha1 arg1 '
complete -C'complete_test_alpha2 arg2 '
complete -C'complete_test_alpha3 arg3 '
# Works even with the argument as a separate token.
complete -C 'complete_test_alpha3 arg3 '
logmsg Alias Completions

View file

@ -4,6 +4,7 @@
complete_test_alpha1 arg1
complete_test_alpha1 extra1 arg2
complete_test_alpha1 extra1 extra2 arg3
complete_test_alpha1 extra1 extra2 arg3
####################
# Alias Completions