@@ -3,8 +3,9 @@ use std::borrow::Cow;
33/// Get the vec of escaped / quoted / doublequoted filenames from the input str
44pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
55 enum State {
6− Normal,
7− NormalEscaped,
6+ OnWhitespace,
7+ Unquoted,
8+ UnquotedEscaped,
89 Quoted,
910 QuoteEscaped,
1011 Dquoted,
@@ -13,7 +14,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
1314
1415 use State::*;
1516
16− let mut state = Normal;
17+ let mut state = Unquoted;
1718 let mut args: Vec<Cow<str>> = Vec::new();
1819 let mut escaped = String::with_capacity(input.len());
1920
@@ -22,31 +23,47 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
2223
2324 for (i, c) in input.char_indices() {
2425 state = match state {
25− Normal => match c {
26+ OnWhitespace => match c {
27+ '"' => {
28+ end = i;
29+ Dquoted
30+ }
31+ '\'' => {
32+ end = i;
33+ Quoted
34+ }
2635 '\\' => {
2736 if cfg!(unix) {
2837 escaped.push_str(&input[start..i]);
2938 start = i + 1;
30− NormalEscaped
39+ UnquotedEscaped
3140 } else {
32− Normal
41+ OnWhitespace
3342 }
3443 }
35− '"' => {
44+ c if c.is_ascii_whitespace() => {
3645 end = i;
37− Dquoted
46+ OnWhitespace
3847 }
39− '\'' => {
40− end = i;
41− Quoted
48+ _ => Unquoted,
49+ },
50+ Unquoted => match c {
51+ '\\' => {
52+ if cfg!(unix) {
53+ escaped.push_str(&input[start..i]);
54+ start = i + 1;
55+ UnquotedEscaped
56+ } else {
57+ Unquoted
58+ }
4259 }
4360 c if c.is_ascii_whitespace() => {
4461 end = i;
45− Normal
62+ OnWhitespace
4663 }
47− _ => Normal,
64+ _ => Unquoted,
4865 },
49− NormalEscaped => Normal,
66+ UnquotedEscaped => Unquoted,
5067 Quoted => match c {
5168 '\\' => {
5269 if cfg!(unix) {
@@ -59,7 +76,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
5976 }
6077 '\'' => {
6178 end = i;
62− Normal
79+ OnWhitespace
6380 }
6481 _ => Quoted,
6582 },
@@ -76,7 +93,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
7693 }
7794 '"' => {
7895 end = i;
79− Normal
96+ OnWhitespace
8097 }
8198 _ => Dquoted,
8299 },
@@ -195,4 +212,18 @@ mod test {
195212 ];
196213 assert_eq!(expected, result);
197214 }
215+
216+ #[test]
217+ fn test_lists() {
218+ let input =
219+ r#":set statusline.center ["file-type","file-encoding"] '["list", "in", "qoutes"]'"#;
220+ let result = shellwords(input);
221+ let expected = vec![
222+ Cow::from(":set"),
223+ Cow::from("statusline.center"),
224+ Cow::from(r#"["file-type","file-encoding"]"#),
225+ Cow::from(r#"["list", "in", "qoutes"]"#),
226+ ];
227+ assert_eq!(expected, result);
228+ }
198229}