From db365b5ef89b7381a295c28988b14adbc01f86a8 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Fri, 19 Apr 2024 14:09:58 +0200 Subject: [PATCH] Do not treat \: or \= as file completion anchor Partially reapplies f7dac82ed (Escape separators (colon and equals) to improve completion, 2019-08-23) which has been reverted. --- src/complete.rs | 27 ++++++++++++++++++++++----- src/reader.rs | 4 ++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/complete.rs b/src/complete.rs index fc146f15e..63c9ac4cf 100644 --- a/src/complete.rs +++ b/src/complete.rs @@ -9,7 +9,11 @@ time::{Duration, Instant}, }; -use crate::{common::charptr2wcstring, util::wcsfilecmp}; +use crate::{ + common::charptr2wcstring, + reader::{get_quote, is_backslashed}, + util::wcsfilecmp, +}; use bitflags::bitflags; use once_cell::sync::Lazy; use printf_compat::sprintf; @@ -1522,6 +1526,7 @@ fn complete_param_expand(&mut self, s: &wstr, do_file: bool, handle_as_special_c flags -= ExpandFlags::GEN_DESCRIPTIONS; } + // Expand words separated by '=' separately, unless '=' is escaped or quoted. // We have the following cases: // // --foo=bar => expand just bar @@ -1529,13 +1534,25 @@ fn complete_param_expand(&mut self, s: &wstr, do_file: bool, handle_as_special_c // foo=bar => expand the whole thing, and also just bar // // We also support colon separator (#2178). If there's more than one, prefer the last one. - let sep_index = s.chars().rposition(|c| c == '=' || c == ':'); + let sep_index = if get_quote(s, s.len()).is_some() { + None + } else { + let mut end = s.len(); + loop { + match s[..end].chars().rposition(|c| c == '=' || c == ':') { + Some(pos) => { + if !is_backslashed(s, pos) { + break Some(pos); + } + end = pos; + } + None => break None, + } + } + }; let complete_from_start = sep_index.is_none() || !string_prefixes_string(L!("-"), s); if let Some(sep_index) = sep_index { - // FIXME: This just cuts the token, - // so any quoting or braces gets lost. - // See #4954. let sep_string = s.slice_from(sep_index + 1); let mut local_completions = Vec::new(); if expand_string( diff --git a/src/reader.rs b/src/reader.rs index f35c55796..41830d630 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -5043,7 +5043,7 @@ fn try_expand_wildcard( /// Test if the specified character in the specified string is backslashed. pos may be at the end of /// the string, which indicates if there is a trailing backslash. -fn is_backslashed(s: &wstr, pos: usize) -> bool { +pub(crate) fn is_backslashed(s: &wstr, pos: usize) -> bool { // note pos == str.size() is OK. if pos > s.len() { return false; @@ -5093,7 +5093,7 @@ fn replace_line_at_cursor( text[..start].to_owned() + replacement + &text[end..] } -fn get_quote(cmd_str: &wstr, len: usize) -> Option { +pub(crate) fn get_quote(cmd_str: &wstr, len: usize) -> Option { let cmd = cmd_str.as_char_slice(); let mut i = 0; while i < cmd.len() {