From 7d1e643d1d8a7630b6caa82cdc9a4a9e3fef9623 Mon Sep 17 00:00:00 2001 From: Paul Seyfert Date: Fri, 8 Oct 2021 09:46:41 +0200 Subject: [PATCH] Brute force attempt at https://github.com/clap-rs/clap/issues/1596 * This escapes everything that comes up in the reproducer from the above issue. NB: this means possible_values only. missing: * possible_value(...).help * Arg(...).value_name[s] * Arg(...).about * Arg(...).long --- clap_complete/src/shells/zsh.rs | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/clap_complete/src/shells/zsh.rs b/clap_complete/src/shells/zsh.rs index 2b64739cedf..1d8d4295a36 100644 --- a/clap_complete/src/shells/zsh.rs +++ b/clap_complete/src/shells/zsh.rs @@ -374,7 +374,7 @@ fn value_completion(arg: &Arg) -> Option { } else { Some(format!( r#"{name}\:"{tooltip}""#, - name = escape_value(value.get_name()), + name = escape_value(value.get_name(), true), tooltip = value.get_help().map(escape_help).unwrap_or_default() )) } @@ -388,7 +388,8 @@ fn value_completion(arg: &Arg) -> Option { values .iter() .filter(|pv| !pv.is_hide_set()) - .map(PossibleValue::get_name) + .map(|pv| escape_value(pv.get_name(), false)) + // TODO(pseyfert): review, merge conflict Some(format!("{}", escape_value(value.get_name(), false) .collect::>() .join(" ") )) @@ -431,13 +432,34 @@ fn escape_help(string: &str) -> String { } /// Escape value string inside single quotes and parentheses -fn escape_value(string: &str) -> String { +fn escape_value(string: &str, with_tooltip: bool) -> String { string - .replace('\\', "\\\\") - .replace('\'', "'\\''") + // .replace('\\', "\\\\") + // .replace('\\', "\\\\\\\\") // ':: :((\\\\\:"some descr"))' \ + .replace('\\', if with_tooltip {"\\\\\\\\"} else {"\\\\"}) + .replace('\'', "'\\\\\\''") .replace('(', "\\(") .replace(')', "\\)") + .replace('[', "\\[") + .replace(']', "\\]") + .replace('"', "\\\"") .replace(' ', "\\ ") + .replace('`', "\\`") + .replace('&', "\\&") + .replace('#', "\\#") + .replace('{', "\\{") // only needed w/o tooltip + .replace('}', "\\}") // only needed w/o tooltip + .replace('$', "\\$") // only needed w/o tooltip + .replace('|', "\\|") + .replace('~', "\\~") + .replace('?', "\\?") + .replace('^', "\\^") + .replace('*', "\\*") + .replace(';', "\\;") + .replace('<', "\\<") + .replace('>', "\\>") + .replace('=', "\\=") // ':: :((\=\:"some descr"))' \ + .replace(':', if with_tooltip {"\\\\\\:"} else {":"}) // ':: :((\\\:\:"some descr"))' \ } fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {