on master help sign in
Escape filenames in command completion
3d283b2Michael Davis
helix-core/src/shellwords.rs+7−7
@@ -1,9 +1,9 @@
1use std::borrow::Cow;
1use std::borrow::Cow;
2
2
3/// Auto escape for shellwords usage.
3/// Auto escape for shellwords usage.
4−pub fn escape(input: &str) -> Cow<'_, str> {
4+pub fn escape(input: Cow<str>) -> Cow<str> {
5 if !input.chars().any(|x| x.is_ascii_whitespace()) {
5 if !input.chars().any(|x| x.is_ascii_whitespace()) {
6− Cow::Borrowed(input)
6+ input
7 } else if cfg!(unix) {
7 } else if cfg!(unix) {
8 Cow::Owned(input.chars().fold(String::new(), |mut buf, c| {
8 Cow::Owned(input.chars().fold(String::new(), |mut buf, c| {
9 if c.is_ascii_whitespace() {
9 if c.is_ascii_whitespace() {
@@ -311,15 +311,15 @@ mod test {
311 #[test]
311 #[test]
312 #[cfg(unix)]
312 #[cfg(unix)]
313 fn test_escaping_unix() {
313 fn test_escaping_unix() {
314− assert_eq!(escape("foobar"), Cow::Borrowed("foobar"));
314+ assert_eq!(escape("foobar".into()), Cow::Borrowed("foobar"));
315− assert_eq!(escape("foo bar"), Cow::Borrowed("foo\\ bar"));
315+ assert_eq!(escape("foo bar".into()), Cow::Borrowed("foo\\ bar"));
316− assert_eq!(escape("foo\tbar"), Cow::Borrowed("foo\\\tbar"));
316+ assert_eq!(escape("foo\tbar".into()), Cow::Borrowed("foo\\\tbar"));
317 }
317 }
318
318
319 #[test]
319 #[test]
320 #[cfg(windows)]
320 #[cfg(windows)]
321 fn test_escaping_windows() {
321 fn test_escaping_windows() {
322− assert_eq!(escape("foobar"), Cow::Borrowed("foobar"));
322+ assert_eq!(escape("foobar".into()), Cow::Borrowed("foobar"));
323− assert_eq!(escape("foo bar"), Cow::Borrowed("\"foo bar\""));
323+ assert_eq!(escape("foo bar".into()), Cow::Borrowed("\"foo bar\""));
324 }
324 }
325}
325}
helix-term/src/commands/typed.rs+1
@@ -2219,6 +2219,7 @@ pub(super) fn command_mode(cx: &mut Context) {
2219 completer(editor, part)
2219 completer(editor, part)
2220 .into_iter()
2220 .into_iter()
2221 .map(|(range, file)| {
2221 .map(|(range, file)| {
2222+ let file = shellwords::escape(file);
2222 // offset ranges to input
2223 // offset ranges to input
2223 let offset = input.len() - part.len();
2224 let offset = input.len() - part.len();
2224 let range = (range.start + offset)..;
2225 let range = (range.start + offset)..;
helix-term/src/ui/prompt.rs+1−5
@@ -1,6 +1,5 @@
1use crate::compositor::{Component, Compositor, Context, Event, EventResult};
1use crate::compositor::{Component, Compositor, Context, Event, EventResult};
2use crate::{alt, ctrl, key, shift, ui};
2use crate::{alt, ctrl, key, shift, ui};
3−use helix_core::shellwords;
4use helix_view::input::KeyEvent;
3use helix_view::input::KeyEvent;
5use helix_view::keyboard::KeyCode;
4use helix_view::keyboard::KeyCode;
6use std::{borrow::Cow, ops::RangeFrom};
5use std::{borrow::Cow, ops::RangeFrom};
@@ -336,10 +335,7 @@ impl Prompt {
336
335
337 let (range, item) = &self.completion[index];
336 let (range, item) = &self.completion[index];
338
337
339− // since we are using shellwords to parse arguments, make sure
340− // that whitespace in files is properly escaped.
341− let item = shellwords::escape(item);
342− self.line.replace_range(range.clone(), &item);
338+ self.line.replace_range(range.clone(), item);
343
339
344 self.move_end();
340 self.move_end();
345 }
341 }