Skip to content

Commit

Permalink
Fix shellwords delimiter handling (helix-editor#4098)
Browse files Browse the repository at this point in the history
* Fix shellwords delimiter handling

This allows commands such as `:set statusline.center ["file-type"]` to
work. Before the quotes within the list would mess it up.
Also added a test to ensure correct behavior

* Rename Delimiter -> OnWhitespace
  • Loading branch information
A-Walrus authored and Frederik Vestre committed Feb 6, 2023
1 parent 23cdb51 commit a80e477
Showing 1 changed file with 47 additions and 16 deletions.
63 changes: 47 additions & 16 deletions helix-core/src/shellwords.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::borrow::Cow;
/// Get the vec of escaped / quoted / doublequoted filenames from the input str
pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
enum State {
Normal,
NormalEscaped,
OnWhitespace,
Unquoted,
UnquotedEscaped,
Quoted,
QuoteEscaped,
Dquoted,
Expand All @@ -13,7 +14,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {

use State::*;

let mut state = Normal;
let mut state = Unquoted;
let mut args: Vec<Cow<str>> = Vec::new();
let mut escaped = String::with_capacity(input.len());

Expand All @@ -22,31 +23,47 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {

for (i, c) in input.char_indices() {
state = match state {
Normal => match c {
OnWhitespace => match c {
'"' => {
end = i;
Dquoted
}
'\'' => {
end = i;
Quoted
}
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[start..i]);
start = i + 1;
NormalEscaped
UnquotedEscaped
} else {
Normal
OnWhitespace
}
}
'"' => {
c if c.is_ascii_whitespace() => {
end = i;
Dquoted
OnWhitespace
}
'\'' => {
end = i;
Quoted
_ => Unquoted,
},
Unquoted => match c {
'\\' => {
if cfg!(unix) {
escaped.push_str(&input[start..i]);
start = i + 1;
UnquotedEscaped
} else {
Unquoted
}
}
c if c.is_ascii_whitespace() => {
end = i;
Normal
OnWhitespace
}
_ => Normal,
_ => Unquoted,
},
NormalEscaped => Normal,
UnquotedEscaped => Unquoted,
Quoted => match c {
'\\' => {
if cfg!(unix) {
Expand All @@ -59,7 +76,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
}
'\'' => {
end = i;
Normal
OnWhitespace
}
_ => Quoted,
},
Expand All @@ -76,7 +93,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
}
'"' => {
end = i;
Normal
OnWhitespace
}
_ => Dquoted,
},
Expand Down Expand Up @@ -195,4 +212,18 @@ mod test {
];
assert_eq!(expected, result);
}

#[test]
fn test_lists() {
let input =
r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "qoutes"]'"#;
let result = shellwords(input);
let expected = vec![
Cow::from(":set"),
Cow::from("statusline.center"),
Cow::from(r#"["file-type","file-encoding"]"#),
Cow::from(r#"["list", "in", "qoutes"]"#),
];
assert_eq!(expected, result);
}
}

0 comments on commit a80e477

Please sign in to comment.