From 04dc0aca5064b7424979c000a41676758aa8b1b6 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 20 Nov 2014 11:12:19 -0800 Subject: [PATCH] Fix issue where tab completions could ignore command-specific completions Fixes #1742 --- complete.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/complete.cpp b/complete.cpp index 173fc83f5..76e8e4e81 100644 --- a/complete.cpp +++ b/complete.cpp @@ -1360,9 +1360,14 @@ static int complete_load_no_reload(wcstring *name) } /** - Find completion for the argument str of command cmd_orig with - previous option popt. Insert results into comp_out. Return 0 if file - completion should be disabled, 1 otherwise. + complete_param: Given a command, find completions for the argument str of command cmd_orig with previous option popt. + + Examples in format (cmd, popt, str): + + echo hello world -> ("echo", "world", "") + echo hello world -> ("echo", "hello", "world") + + Insert results into comp_out. Return true to perform file completion, false to disable it. */ struct local_options_t { @@ -1967,7 +1972,7 @@ void complete(const wcstring &cmd_with_subcmds, std::vector &comps for (size_t i=0; i < all_arguments.size(); i++) { const parse_node_t *node = all_arguments.at(i); - if (node->location_in_or_at_end_of_source_range(pos)) + if (node->location_in_or_at_end_of_source_range(adjusted_pos)) { matching_arg_index = i; break; @@ -1978,11 +1983,23 @@ void complete(const wcstring &cmd_with_subcmds, std::vector &comps wcstring current_argument, previous_argument; if (matching_arg_index != (size_t)(-1)) { - /* Get the current argument and the previous argument, if we have one */ - current_argument = all_arguments.at(matching_arg_index)->get_source(cmd); - - if (matching_arg_index > 0) - previous_argument = all_arguments.at(matching_arg_index - 1)->get_source(cmd); + const wcstring matching_arg = all_arguments.at(matching_arg_index)->get_source(cmd); + + /* If the cursor is in whitespace, then the "current" argument is empty and the previous argument is the matching one. But if the cursor was in or at the end of the argument, then the current argument is the matching one, and the previous argument is the one before it. */ + bool cursor_in_whitespace = (adjusted_pos < pos); + if (cursor_in_whitespace) + { + current_argument = L""; + previous_argument = matching_arg; + } + else + { + current_argument = matching_arg; + if (matching_arg_index > 0) + { + previous_argument = all_arguments.at(matching_arg_index - 1)->get_source(cmd); + } + } /* Check to see if we have a preceding double-dash */ for (size_t i=0; i < matching_arg_index; i++)