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> {
fn from(input: &'a str) -> Self {
use State::*;
let mut state = Unquoted;
let mut words = Vec::new();
let mut parts = Vec::new();
@ -52,30 +51,27 @@ impl<'a> From<&'a str> for Shellwords<'a> {
let mut end = 0;
for (i, c) in input.char_indices() {
if !inside_variable_expansion {
if c == '%' {
//%sh{this "should" be escaped}
if let Some(t) = input.get(i + 1..i + 3) {
if t == "sh" {
nested_variable_expansion_count += 1;
inside_variable_expansion = true;
}
if c == '%' {
//%sh{this "should" be escaped}
if let Some(t) = input.get(i + 1..i + 3) {
if t == "sh" {
nested_variable_expansion_count += 1;
inside_variable_expansion = true;
}
//%{this "should" be escaped}
if let Some(t) = input.get(i + 1..i + 2) {
if t == "{" {
nested_variable_expansion_count += 1;
inside_variable_expansion = true;
}
}
//%{this "should" be escaped}
if let Some(t) = input.get(i + 1..i + 2) {
if t == "{" {
nested_variable_expansion_count += 1;
inside_variable_expansion = true;
}
}
} else if c == '}' {
}
if c == '}' {
nested_variable_expansion_count -= 1;
if nested_variable_expansion_count == 0 {
inside_variable_expansion = false;
}
} else if c == '{' {
nested_variable_expansion_count += 1;
}
state = if !inside_variable_expansion {
@ -266,6 +262,38 @@ mod test {
// TODO test is_owned and is_borrowed, once they get stabilized.
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]
#[cfg(unix)]

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