aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorA-Walrus2022-10-21 01:06:57 +0000
committerGitHub2022-10-21 01:06:57 +0000
commit4ff5feeb0c6c1ce012aa1179a44f35b6f0df4da1 (patch)
treea905e73418f38e5af9eb689cdda6d1c73d592db5
parent9af7c1c9f3aa498719bd0fa39d4d35746f23adaa (diff)
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
-rw-r--r--helix-core/src/shellwords.rs63
1 files changed, 47 insertions, 16 deletions
diff --git a/helix-core/src/shellwords.rs b/helix-core/src/shellwords.rs
index 4323039a..afc83496 100644
--- a/helix-core/src/shellwords.rs
+++ b/helix-core/src/shellwords.rs
@@ -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,
@@ -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());
@@ -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) {
@@ -59,7 +76,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
}
'\'' => {
end = i;
- Normal
+ OnWhitespace
}
_ => Quoted,
},
@@ -76,7 +93,7 @@ pub fn shellwords(input: &str) -> Vec<Cow<'_, str>> {
}
'"' => {
end = i;
- Normal
+ OnWhitespace
}
_ => Dquoted,
},
@@ -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);
+ }
}