Fix shellwords delimiter handling (#4098)
* 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
This commit is contained in:
parent
9af7c1c9f3
commit
4ff5feeb0c
1 changed files with 49 additions and 18 deletions
|
@ -3,8 +3,9 @@ use std::borrow::Cow;
|
||||||
/// Get the vec of escaped / quoted / doublequoted filenames from the input str
|
/// Get the vec of escaped / quoted / doublequoted filenames from the input str
|
||||||
pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
enum State {
|
enum State {
|
||||||
Normal,
|
OnWhitespace,
|
||||||
NormalEscaped,
|
Unquoted,
|
||||||
|
UnquotedEscaped,
|
||||||
Quoted,
|
Quoted,
|
||||||
QuoteEscaped,
|
QuoteEscaped,
|
||||||
Dquoted,
|
Dquoted,
|
||||||
|
@ -13,7 +14,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
|
|
||||||
use State::*;
|
use State::*;
|
||||||
|
|
||||||
let mut state = Normal;
|
let mut state = Unquoted;
|
||||||
let mut args: Vec<Cow<str>> = Vec::new();
|
let mut args: Vec<Cow<str>> = Vec::new();
|
||||||
let mut escaped = String::with_capacity(input.len());
|
let mut escaped = String::with_capacity(input.len());
|
||||||
|
|
||||||
|
@ -22,16 +23,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
|
|
||||||
for (i, c) in input.char_indices() {
|
for (i, c) in input.char_indices() {
|
||||||
state = match state {
|
state = match state {
|
||||||
Normal => match c {
|
OnWhitespace => match c {
|
||||||
'\\' => {
|
|
||||||
if cfg!(unix) {
|
|
||||||
escaped.push_str(&input[start..i]);
|
|
||||||
start = i + 1;
|
|
||||||
NormalEscaped
|
|
||||||
} else {
|
|
||||||
Normal
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'"' => {
|
'"' => {
|
||||||
end = i;
|
end = i;
|
||||||
Dquoted
|
Dquoted
|
||||||
|
@ -40,13 +32,38 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
end = i;
|
end = i;
|
||||||
Quoted
|
Quoted
|
||||||
}
|
}
|
||||||
|
'\\' => {
|
||||||
|
if cfg!(unix) {
|
||||||
|
escaped.push_str(&input[start..i]);
|
||||||
|
start = i + 1;
|
||||||
|
UnquotedEscaped
|
||||||
|
} else {
|
||||||
|
OnWhitespace
|
||||||
|
}
|
||||||
|
}
|
||||||
c if c.is_ascii_whitespace() => {
|
c if c.is_ascii_whitespace() => {
|
||||||
end = i;
|
end = i;
|
||||||
Normal
|
OnWhitespace
|
||||||
}
|
}
|
||||||
_ => Normal,
|
_ => Unquoted,
|
||||||
},
|
},
|
||||||
NormalEscaped => Normal,
|
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;
|
||||||
|
OnWhitespace
|
||||||
|
}
|
||||||
|
_ => Unquoted,
|
||||||
|
},
|
||||||
|
UnquotedEscaped => Unquoted,
|
||||||
Quoted => match c {
|
Quoted => match c {
|
||||||
'\\' => {
|
'\\' => {
|
||||||
if cfg!(unix) {
|
if cfg!(unix) {
|
||||||
|
@ -59,7 +76,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
}
|
}
|
||||||
'\'' => {
|
'\'' => {
|
||||||
end = i;
|
end = i;
|
||||||
Normal
|
OnWhitespace
|
||||||
}
|
}
|
||||||
_ => Quoted,
|
_ => Quoted,
|
||||||
},
|
},
|
||||||
|
@ -76,7 +93,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
|
||||||
}
|
}
|
||||||
'"' => {
|
'"' => {
|
||||||
end = i;
|
end = i;
|
||||||
Normal
|
OnWhitespace
|
||||||
}
|
}
|
||||||
_ => Dquoted,
|
_ => Dquoted,
|
||||||
},
|
},
|
||||||
|
@ -195,4 +212,18 @@ mod test {
|
||||||
];
|
];
|
||||||
assert_eq!(expected, result);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue