Skip to content

Commit

Permalink
fix: .file path args do not need double backslash on Windows (#1053)
Browse files Browse the repository at this point in the history
  • Loading branch information
sigoden authored Dec 12, 2024
1 parent 1a4a2fc commit c0f34d4
Showing 1 changed file with 105 additions and 27 deletions.
132 changes: 105 additions & 27 deletions src/repl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,6 @@ use reedline::{
use reedline::{MenuBuilder, Signal};
use std::{env, process};

lazy_static::lazy_static! {
static ref SPLIT_FILES_TEXT_ARGS_RE: Regex =
Regex::new(r"(?m) (-- |--\n|--\r\n|--\r|--$)").unwrap();
}

const MENU_NAME: &str = "completion_menu";

lazy_static::lazy_static! {
Expand Down Expand Up @@ -406,8 +401,7 @@ impl Repl {
},
".file" => match args {
Some(args) => {
let (files, text) = split_files_text(args);
let files = shell_words::split(files).with_context(|| "Invalid args")?;
let (files, text) = split_files_text(args, cfg!(windows));
let input = Input::from_files_with_spinner(
&self.config,
text,
Expand Down Expand Up @@ -708,19 +702,72 @@ fn split_args(args: Option<&str>) -> Option<(&str, Option<&str>)> {
})
}

fn split_files_text(args: &str) -> (&str, &str) {
match SPLIT_FILES_TEXT_ARGS_RE.find(args).ok().flatten() {
Some(mat) => {
let files = &args[0..mat.start()];
let text = if mat.end() < args.len() {
&args[mat.end()..]
} else {
""
};
(files, text)
fn split_files_text(line: &str, is_win: bool) -> (Vec<String>, &str) {
let mut words = Vec::new();
let mut word = String::new();
let mut unbalance: Option<char> = None;
let mut prev_char: Option<char> = None;
let mut text_starts_at = None;
let unquote_word = |word: &str| {
if ((word.starts_with('"') && word.ends_with('"'))
|| (word.starts_with('\'') && word.ends_with('\'')))
&& word.len() >= 2
{
word[1..word.len() - 1].to_string()
} else {
word.to_string()
}
};

for (i, char) in line.chars().enumerate() {
match unbalance {
Some(ub_char) if ub_char == char => {
word.push(char);
unbalance = None;
}
Some(_) => {
word.push(char);
}
None => match char {
' ' | '\t' | '\r' | '\n' => {
if let Some('\\') = prev_char.filter(|_| !is_win) {
word.push(char);
} else if !word.is_empty() {
if word == "--" {
word.clear();
text_starts_at = Some(i);
break;
}
words.push(unquote_word(&word));
word.clear();
}
}
'\'' | '"' => {
word.push(char);
unbalance = Some(char);
}
'\\' => {
if is_win || prev_char.map(|c| c == '\\').unwrap_or_default() {
word.push(char);
}
}
_ => {
word.push(char);
}
},
}
None => (args, ""),
prev_char = Some(char);
}

if !word.is_empty() && word != "--" {
words.push(unquote_word(&word));
}
let text = match text_starts_at {
Some(start) => line[start..].trim(),
None => "",
};

(words, text)
}

#[cfg(test)]
Expand Down Expand Up @@ -748,20 +795,51 @@ mod tests {

#[test]
fn test_split_files_text() {
assert_eq!(split_files_text("file.txt"), ("file.txt", ""));
assert_eq!(split_files_text("file.txt --"), ("file.txt", ""));
assert_eq!(split_files_text("file.txt -- hello"), ("file.txt", "hello"));
assert_eq!(
split_files_text("file.txt --\nhello"),
("file.txt", "hello")
split_files_text("file.txt", false),
(vec!["file.txt".into()], "")
);
assert_eq!(
split_files_text("file.txt --", false),
(vec!["file.txt".into()], "")
);
assert_eq!(
split_files_text("file.txt -- hello", false),
(vec!["file.txt".into()], "hello")
);
assert_eq!(
split_files_text("file.txt --\nhello", false),
(vec!["file.txt".into()], "hello")
);
assert_eq!(
split_files_text("file.txt --\r\nhello", false),
(vec!["file.txt".into()], "hello")
);
assert_eq!(
split_files_text("file.txt --\rhello", false),
(vec!["file.txt".into()], "hello")
);
assert_eq!(
split_files_text("file.txt --\r\nhello"),
("file.txt", "hello")
split_files_text(r#"file1.txt 'file2.txt' "file3.txt""#, false),
(
vec!["file1.txt".into(), "file2.txt".into(), "file3.txt".into()],
""
)
);
assert_eq!(
split_files_text(r#"./file1.txt 'file1 - Copy.txt' file\ 2.txt"#, false),
(
vec![
"./file1.txt".into(),
"file1 - Copy.txt".into(),
"file 2.txt".into()
],
""
)
);
assert_eq!(
split_files_text("file.txt --\rhello"),
("file.txt", "hello")
split_files_text(r#".\file.txt C:\dir\file.txt"#, true),
(vec![".\\file.txt".into(), "C:\\dir\\file.txt".into()], "")
);
}
}

0 comments on commit c0f34d4

Please sign in to comment.