From 9f79fe17fcc125e03f51d1417423ccd149aa5b8d Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Thu, 13 Mar 2025 07:32:37 +0100 Subject: [PATCH] Quote only unique completions, use backslashes for ambiguous ones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 29dc307111 (Insert some completions with quotes instead of backslashes, 2024-04-13) breaks some workflows. Given touch '[test] file1' touch '[test] file2' ls tes we insert completions quoted, which is inconvenient when using globs. This implicit quoting feature is somewhat minor. But quotes look nicer, so let's try to keep them. Either way, users can ask for it by starting a token with «"». Use quoting only when we insert unique completions. Closes #11271 --- src/builtins/complete.rs | 3 ++- src/reader.rs | 28 ++++++++++++++++++++++++---- src/tests/complete.rs | 4 +++- src/tests/reader.rs | 1 + tests/checks/complete.fish | 2 +- 5 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/builtins/complete.rs b/src/builtins/complete.rs index 4b1988fd4..e87241182 100644 --- a/src/builtins/complete.rs +++ b/src/builtins/complete.rs @@ -513,7 +513,8 @@ pub fn complete(parser: &Parser, streams: &mut IoStreams, argv: &mut [&wstr]) -> next.flags, faux_cmdline, &mut tmp_cursor, - false, + /*append_only=*/ false, + /*is_unique=*/ false, ); // completion_apply_to_command_line will append a space unless COMPLETE_NO_SPACE diff --git a/src/reader.rs b/src/reader.rs index d0348bfc2..ef00f2eca 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -4153,6 +4153,7 @@ fn pager_selection_changed(&mut self) { &self.cycle_command_line, &mut cursor_pos, false, + /*is_unique=*/ false, // don't care ); // Only update if something changed, to avoid useless edits in the undo history. if new_cmd_line != self.command_line.text() && new_cmd_line != self.cycle_command_line { @@ -4841,6 +4842,7 @@ fn get_autosuggestion_performer( &command_line, &mut would_be_cursor, /*append_only=*/ true, + /*is_unique=*/ false, ); line_at_cursor(&full_line, would_be_cursor).to_owned() }; @@ -6062,6 +6064,7 @@ pub fn completion_apply_to_command_line( command_line: &wstr, inout_cursor_pos: &mut usize, append_only: bool, + is_unique: bool, ) -> WString { let mut trailer = (!flags.contains(CompleteFlags::NO_SPACE)).then_some(' '); let do_replace_token = flags.contains(CompleteFlags::REPLACES_TOKEN); @@ -6088,7 +6091,7 @@ pub fn completion_apply_to_command_line( } let mut escape_flags = EscapeFlags::empty(); - if append_only || trailer.is_none() { + if append_only || !is_unique || trailer.is_none() { escape_flags.insert(EscapeFlags::NO_QUOTED); } if no_tilde { @@ -6351,7 +6354,12 @@ fn try_insert(&mut self, c: Completion, tok: &wstr, token_range: Range) { // If this is a replacement completion, check that we know how to replace it, e.g. that // the token doesn't contain evil operators like {}. if !c.flags.contains(CompleteFlags::REPLACES_TOKEN) || reader_can_replace(tok, c.flags) { - self.completion_insert(&c.completion, token_range.end, c.flags); + self.completion_insert( + &c.completion, + token_range.end, + c.flags, + /*is_unique=*/ true, + ); } } @@ -6491,7 +6499,12 @@ fn handle_completions(&mut self, token_range: Range) -> bool { if prefix_is_partial_completion { flags |= CompleteFlags::NO_SPACE; } - self.completion_insert(&common_prefix, token_range.end, flags); + self.completion_insert( + &common_prefix, + token_range.end, + flags, + /*is_unique=*/ false, + ); self.cycle_command_line = self.command_line.text().to_owned(); self.cycle_cursor_pos = self.command_line.position(); } @@ -6535,7 +6548,13 @@ fn handle_completions(&mut self, token_range: Range) -> bool { /// \param token_end the position after the token to complete /// \param flags A union of all flags describing the completion to insert. See the completion_t /// struct for more information on possible values. - fn completion_insert(&mut self, val: &wstr, token_end: usize, flags: CompleteFlags) { + fn completion_insert( + &mut self, + val: &wstr, + token_end: usize, + flags: CompleteFlags, + is_unique: bool, + ) { let (elt, el) = self.active_edit_line(); // Move the cursor to the end of the token. @@ -6552,6 +6571,7 @@ fn completion_insert(&mut self, val: &wstr, token_end: usize, flags: CompleteFla el.text(), &mut cursor, /*append_only=*/ false, + is_unique, ); self.set_buffer_maintaining_pager(&new_command_line, cursor); } diff --git a/src/tests/complete.rs b/src/tests/complete.rs index 9302b55c5..3978254c3 100644 --- a/src/tests/complete.rs +++ b/src/tests/complete.rs @@ -163,7 +163,8 @@ macro_rules! unique_completion_applies_as { completions[0].flags, cmdline, &mut cursor, - false, + /*append_only=*/ false, + /*is_unique=*/ true, ); assert_eq!(newcmdline, L!($applied), "apply result mismatch"); }; @@ -232,6 +233,7 @@ macro_rules! unique_completion_applies_as { L!("mv debug debug"), &mut cursor_pos, true, + /*is_unique=*/ false, ); assert_eq!(newcmdline, L!("mv debug Debug/")); diff --git a/src/tests/reader.rs b/src/tests/reader.rs index 627daf442..08584ac9b 100644 --- a/src/tests/reader.rs +++ b/src/tests/reader.rs @@ -80,6 +80,7 @@ macro_rules! validate { &line, &mut cursor_pos, $append_only, + /*is_unique=*/ false, ); assert_eq!(result, expected); assert_eq!(cursor_pos, out_cursor_pos); diff --git a/tests/checks/complete.fish b/tests/checks/complete.fish index 78d633e61..a146ac787 100644 --- a/tests/checks/complete.fish +++ b/tests/checks/complete.fish @@ -10,7 +10,7 @@ complete -c complete_test_alpha3 --no-files -w 'complete_test_alpha2 extra2' complete -C'complete_test_alpha1 arg1 ' # CHECK: complete_test_alpha1 arg1 complete --escape -C'complete_test_alpha1 arg1 ' -# CHECK: 'complete_test_alpha1 arg1 ' +# CHECK: complete_test_alpha1\ arg1\{{ }} complete -C'complete_test_alpha2 arg2 ' # CHECK: complete_test_alpha1 extra1 arg2 complete -C'complete_test_alpha3 arg3 '