From df3b0bd89fad1b4c2274c396ccabc5d050a5a900 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Wed, 26 Jan 2022 15:22:18 +0100 Subject: [PATCH] Fix commandline state for custom completions with variable overrides Today, a command like "var=val status " has custom completions because we skip over the var=val variable override when detecting the command token. However if the custom completions read the commandline state (via "commandline -opc") they do see they variable override, which breaks them, most likely. Try "a=b git ". For completions of wrapped commands, we already set a transient commandline. Do the same for commands with leading variable overrides; then git completions for "a=b git " will think the commandline is "git ". --- CHANGELOG.rst | 1 + src/complete.cpp | 16 +++++++++++++--- tests/checks/complete.fish | 7 +++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 6d41f61cc..97fbb26da 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -175,6 +175,7 @@ Completions - Improvements to many completions, especially for ``git`` aliases (:issue:`8129`) and subcommands (:issue:`8134`). - Add missing completions for the ``-p`` option of ``xbps-query``. - The ``fish_is_nth_token`` function, which is particularly useful in completions for identifying the token number within the command line, replaces various internal functions to do the same (:issue:`8008`). +- When evaluating custom completions, the command line state no longer includes variable overrides (``var=val``). This unbreaks completions that read ``commandline -op``. Improved terminal support ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/complete.cpp b/src/complete.cpp index 559791c7f..043cc7fa9 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1390,7 +1390,7 @@ void completer_t::complete_custom(const wcstring &cmd, const wcstring &cmdline, // buitin_commandline will refer to the wrapped command. But not if // we're doing autosuggestions. maybe_t remove_transient{}; - bool wants_transient = ad->wrap_depth > 0 && !is_autosuggest; + bool wants_transient = (ad->wrap_depth > 0 || ad->var_assignments) && !is_autosuggest; if (wants_transient) { ctx.parser->libdata().transient_commandlines.push_back(cmdline); remove_transient.emplace([=] { ctx.parser->libdata().transient_commandlines.pop_back(); }); @@ -1575,6 +1575,7 @@ void completer_t::perform_for_commandline(wcstring cmdline) { // Get all the arguments. std::vector tokens; parse_util_process_extent(cmdline.c_str(), position_in_statement, nullptr, nullptr, &tokens); + size_t actual_token_count = tokens.size(); // Hack: fix autosuggestion by removing prefixing "and"s #6249. if (is_autosuggest) { @@ -1603,6 +1604,14 @@ void completer_t::perform_for_commandline(wcstring cmdline) { return; } + wcstring *effective_cmdline, effective_cmdline_buf; + if (tokens.size() == actual_token_count) { + effective_cmdline = &cmdline; + } else { + effective_cmdline_buf.assign(cmdline, tokens.front().offset); + effective_cmdline = &effective_cmdline_buf; + } + const tok_t &cmd_tok = tokens.front(); const tok_t &cur_tok = tokens.back(); @@ -1674,7 +1683,8 @@ void completer_t::perform_for_commandline(wcstring cmdline) { custom_arg_data_t arg_data{&var_assignments}; arg_data.had_ddash = had_ddash; - source_range_t command_range = {cmd_tok.offset, cmd_tok.length}; + source_offset_t bias = cmdline.size() - effective_cmdline->size(); + source_range_t command_range = {cmd_tok.offset - bias, cmd_tok.length}; wcstring exp_command = cmd_tok.get_source(cmdline); bool unescaped = @@ -1684,7 +1694,7 @@ void completer_t::perform_for_commandline(wcstring cmdline) { if (unescaped) { // Have to walk over the command and its entire wrap chain. If any command // disables do_file, then they all do. - walk_wrap_chain(exp_command, cmdline, command_range, &arg_data); + walk_wrap_chain(exp_command, *effective_cmdline, command_range, &arg_data); do_file = arg_data.do_file; // If we're autosuggesting, and the token is empty, don't do file suggestions. diff --git a/tests/checks/complete.fish b/tests/checks/complete.fish index 50076af04..118f5bc0a 100644 --- a/tests/checks/complete.fish +++ b/tests/checks/complete.fish @@ -454,3 +454,10 @@ function crookshanks --wraps '$path_to_cat' end complete -C 'crookshanks ' # CHECK: +pet + +# Custom completion works with variable overrides. +complete cmd_with_fancy_completion -xa '(commandline -opc | count)' +complete -C"a=1 b=2 cmd_with_fancy_completion " +# CHECK: 1 +complete -C"a=1 b=2 cmd_with_fancy_completion 1 " +# CHECK: 2