fixing shellwords + correct command expansion in mappablecommands

pull/11164/head
Théo Daron 4 months ago
parent c2172847b2
commit 5bda25cf30

@ -40,7 +40,6 @@ pub struct Shellwords<'a> {
impl<'a> From<&'a str> for Shellwords<'a> { impl<'a> From<&'a str> for Shellwords<'a> {
fn from(input: &'a str) -> Self { fn from(input: &'a str) -> Self {
use State::*; use State::*;
let mut state = Unquoted; let mut state = Unquoted;
let mut words = Vec::new(); let mut words = Vec::new();
let mut parts = Vec::new(); let mut parts = Vec::new();
@ -52,30 +51,27 @@ impl<'a> From<&'a str> for Shellwords<'a> {
let mut end = 0; let mut end = 0;
for (i, c) in input.char_indices() { for (i, c) in input.char_indices() {
if !inside_variable_expansion { if c == '%' {
if c == '%' { //%sh{this "should" be escaped}
//%sh{this "should" be escaped} if let Some(t) = input.get(i + 1..i + 3) {
if let Some(t) = input.get(i + 1..i + 3) { if t == "sh" {
if t == "sh" { nested_variable_expansion_count += 1;
nested_variable_expansion_count += 1; inside_variable_expansion = true;
inside_variable_expansion = true;
}
} }
//%{this "should" be escaped} }
if let Some(t) = input.get(i + 1..i + 2) { //%{this "should" be escaped}
if t == "{" { if let Some(t) = input.get(i + 1..i + 2) {
nested_variable_expansion_count += 1; if t == "{" {
inside_variable_expansion = true; nested_variable_expansion_count += 1;
} inside_variable_expansion = true;
} }
} }
} else if c == '}' { }
if c == '}' {
nested_variable_expansion_count -= 1; nested_variable_expansion_count -= 1;
if nested_variable_expansion_count == 0 { if nested_variable_expansion_count == 0 {
inside_variable_expansion = false; inside_variable_expansion = false;
} }
} else if c == '{' {
nested_variable_expansion_count += 1;
} }
state = if !inside_variable_expansion { state = if !inside_variable_expansion {
@ -266,6 +262,38 @@ mod test {
// TODO test is_owned and is_borrowed, once they get stabilized. // TODO test is_owned and is_borrowed, once they get stabilized.
assert_eq!(expected, result); assert_eq!(expected, result);
} }
#[test]
fn test_expansion() {
let input = r#"echo %{filename} %{linenumber}"#;
let shellwords = Shellwords::from(input);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from("echo"),
Cow::from("%{filename}"),
Cow::from("%{linenumber}"),
];
assert_eq!(expected, result);
let input = r#"echo %{filename} 'world' %{something to 'escape}"#;
let shellwords = Shellwords::from(input);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from("echo"),
Cow::from("%{filename}"),
Cow::from("world"),
Cow::from("%{something to 'escape}"),
];
assert_eq!(expected, result);
let input = r#"echo %sh{%sh{%{filename}}} cool"#;
let shellwords = Shellwords::from(input);
let result = shellwords.words().to_vec();
let expected = vec![
Cow::from("echo"),
Cow::from("%sh{%sh{%{filename}}}"),
Cow::from("cool"),
];
assert_eq!(expected, result);
}
#[test] #[test]
#[cfg(unix)] #[cfg(unix)]

@ -217,22 +217,25 @@ impl MappableCommand {
pub fn execute(&self, cx: &mut Context) { pub fn execute(&self, cx: &mut Context) {
match &self { match &self {
Self::Typable { name, args, doc: _ } => { Self::Typable { name, args, doc: _ } => {
let args: Vec<Cow<str>> = args.iter().map(Cow::from).collect(); let mut args: Vec<Cow<str>> = args.iter().map(Cow::from).collect();
if let Some(command) = typed::TYPABLE_COMMAND_MAP.get(name.as_str()) { let joined_args = vec![Cow::from(args.join(" "))];
let mut cx = compositor::Context { if let Ok(expanded_args) = cx.editor.expand_variables(&joined_args) {
editor: cx.editor, args = expanded_args
jobs: cx.jobs, .first()
scroll: None, .unwrap()
}; .split(' ')
.map(Cow::from)
match cx.editor.expand_variables(&args) { .collect();
Ok(args) => { if let Some(command) = typed::TYPABLE_COMMAND_MAP.get(name.as_str()) {
if let Err(e) = (command.fun)(&mut cx, &args[..], PromptEvent::Validate) let mut cx = compositor::Context {
{ editor: cx.editor,
cx.editor.set_error(format!("{}", e)); jobs: cx.jobs,
} scroll: None,
};
if let Err(e) = (command.fun)(&mut cx, &args[..], PromptEvent::Validate) {
cx.editor.set_error(format!("{}", e));
} }
Err(err) => cx.editor.set_error(err.to_string()),
} }
} }
} }

Loading…
Cancel
Save