Add --escape option to complete -C

An example use case is an external completion pager:

    bind \cg "commandline -rt (complete -C --escape|fzf|cut -d\t -f1)\ "

Fixes #3469
This commit is contained in:
Nadav Zingerman 2022-01-15 16:57:29 +02:00 committed by Johannes Altmanninger
parent d1d9f147ec
commit 9e0f74eb6c
4 changed files with 22 additions and 5 deletions

View File

@ -94,6 +94,7 @@ Scripting improvements
- ``command -v`` returns an exit status of 127 instead of 1 if no command was found (:issue:`8547`). - ``command -v`` returns an exit status of 127 instead of 1 if no command was found (:issue:`8547`).
- ``argparse`` with ``--ignore-unknown`` no longer breaks with multiple unknown options in a short option group (:issue:`8637`). - ``argparse`` with ``--ignore-unknown`` no longer breaks with multiple unknown options in a short option group (:issue:`8637`).
- Comments inside command substitutions or brackets now correctly ignore parentheses, quotes, and brackets (:issue:`7866`, :issue:`8022`). - Comments inside command substitutions or brackets now correctly ignore parentheses, quotes, and brackets (:issue:`7866`, :issue:`8022`).
- ``complete -C`` supports a new ``--escape`` option, which turns on escaping in returned completion strings (:issue:`3469`).
Interactive improvements Interactive improvements
------------------------ ------------------------

View File

@ -9,7 +9,7 @@ Synopsis
.. synopsis:: .. synopsis::
complete ((-c | --command) | (-p | --path)) COMMAND [OPTIONS] complete ((-c | --command) | (-p | --path)) COMMAND [OPTIONS]
complete ((-C | --do-complete)) STRING complete ((-C | --do-complete)) [STRING] [--escape]
Description Description
----------- -----------
@ -49,6 +49,8 @@ the fish manual.
- ``-C STRING`` or ``--do-complete=STRING`` makes complete try to find all possible completions for the specified string. If there is no STRING, the current commandline is used instead. - ``-C STRING`` or ``--do-complete=STRING`` makes complete try to find all possible completions for the specified string. If there is no STRING, the current commandline is used instead.
- When using ``-C``, specify ``--escape`` to escape special characters in completions.
Command specific tab-completions in ``fish`` are based on the notion of options and arguments. An option is a parameter which begins with a hyphen, such as ``-h``, ``-help`` or ``--help``. Arguments are parameters that do not begin with a hyphen. Fish recognizes three styles of options, the same styles as the GNU getopt library. These styles are: Command specific tab-completions in ``fish`` are based on the notion of options and arguments. An option is a parameter which begins with a hyphen, such as ``-h``, ``-help`` or ``--help``. Arguments are parameters that do not begin with a hyphen. Fish recognizes three styles of options, the same styles as the GNU getopt library. These styles are:
- Short options, like ``-a``. Short options are a single character long, are preceded by a single hyphen and can be grouped together (like ``-la``, which is equivalent to ``-l -a``). Option arguments may be specified by appending the option with the value (``-w32``), or, if ``--require-parameter`` is given, in the following parameter (``-w 32``). - Short options, like ``-a``. Short options are a single character long, are preceded by a single hyphen and can be grouped together (like ``-la``, which is equivalent to ``-l -a``). Option arguments may be specified by appending the option with the value (``-w32``), or, if ``--require-parameter`` is given, in the following parameter (``-w 32``).

View File

@ -122,6 +122,10 @@ static void builtin_complete_print(const wcstring &cmd, io_streams_t &streams, p
} }
} }
/// Values used for long-only options.
enum {
opt_escape = 1,
};
/// The complete builtin. Used for specifying programmable tab-completions. Calls the functions in /// The complete builtin. Used for specifying programmable tab-completions. Calls the functions in
// complete.cpp for any heavy lifting. // complete.cpp for any heavy lifting.
maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wchar_t **argv) { maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wchar_t **argv) {
@ -139,6 +143,7 @@ maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wch
wcstring_list_t path; wcstring_list_t path;
wcstring_list_t wrap_targets; wcstring_list_t wrap_targets;
bool preserve_order = false; bool preserve_order = false;
bool unescape_output = true;
static const wchar_t *const short_options = L":a:c:p:s:l:o:d:fFrxeuAn:C::w:hk"; static const wchar_t *const short_options = L":a:c:p:s:l:o:d:fFrxeuAn:C::w:hk";
static const struct woption long_options[] = { static const struct woption long_options[] = {
@ -162,6 +167,7 @@ maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wch
{L"do-complete", optional_argument, nullptr, 'C'}, {L"do-complete", optional_argument, nullptr, 'C'},
{L"help", no_argument, nullptr, 'h'}, {L"help", no_argument, nullptr, 'h'},
{L"keep-order", no_argument, nullptr, 'k'}, {L"keep-order", no_argument, nullptr, 'k'},
{L"escape", no_argument, nullptr, opt_escape},
{nullptr, 0, nullptr, 0}}; {nullptr, 0, nullptr, 0}};
int opt; int opt;
@ -272,6 +278,10 @@ maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wch
if (have_do_complete_param) do_complete_param = w.woptarg; if (have_do_complete_param) do_complete_param = w.woptarg;
break; break;
} }
case opt_escape: {
unescape_output = false;
break;
}
case 'h': { case 'h': {
builtin_print_help(parser, streams, cmd); builtin_print_help(parser, streams, cmd);
return STATUS_CMD_OK; return STATUS_CMD_OK;
@ -388,10 +398,12 @@ maybe_t<int> builtin_complete(parser_t &parser, io_streams_t &streams, const wch
faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() - 1); faux_cmdline_with_completion.resize(faux_cmdline_with_completion.size() - 1);
} }
// The input data is meant to be something like you would have on the command if (unescape_output) {
// line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So // The input data is meant to be something like you would have on the command
// we need to unescape the command line. See #1127. // line, e.g. includes backslashes. The output should be raw, i.e. unescaped. So
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT); // we need to unescape the command line. See #1127.
unescape_string_in_place(&faux_cmdline_with_completion, UNESCAPE_DEFAULT);
}
streams.out.append(faux_cmdline_with_completion); streams.out.append(faux_cmdline_with_completion);
// Append any description. // Append any description.

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_alpha1 arg1 '
# CHECK: complete_test_alpha1 arg1 # CHECK: complete_test_alpha1 arg1
complete --escape -C'complete_test_alpha1 arg1 '
# CHECK: complete_test_alpha1\ arg1\
complete -C'complete_test_alpha2 arg2 ' complete -C'complete_test_alpha2 arg2 '
# CHECK: complete_test_alpha1 extra1 arg2 # CHECK: complete_test_alpha1 extra1 arg2
complete -C'complete_test_alpha3 arg3 ' complete -C'complete_test_alpha3 arg3 '