feat: Add a way to escape { in exec templates.

fixes #1303
This commit is contained in:
Thayne McCombs 2023-05-03 23:33:44 -06:00
parent 0884b837b2
commit 3b4bbe2817
3 changed files with 38 additions and 3 deletions

5
doc/fd.1 vendored
View File

@ -376,10 +376,15 @@ parent directory
path without file extension
.IP {/.}
basename without file extension
.IP {{}
literal '{'
.RE
If no placeholder is present, an implicit "{}" at the end is assumed.
If you need to include the literal text of one of the placeholders, you can use "{{}" to
escape the first "{". For example "{{}}" expands to "{}", and "{{}{{}}}" expands to "{{}".
Examples:
- find all *.zip files and unzip them:

View File

@ -799,7 +799,8 @@ impl clap::Args for Exec {
'{/}': basename\n \
'{//}': parent directory\n \
'{.}': path without file extension\n \
'{/.}': basename without file extension\n\n\
'{/.}': basename without file extension\n \
'{{}': literal '{' (for escaping)\n\n\
If no placeholder is present, an implicit \"{}\" at the end is assumed.\n\n\
Examples:\n\n \
- find all *.zip files and unzip them:\n\n \
@ -829,7 +830,8 @@ impl clap::Args for Exec {
'{/}': basename\n \
'{//}': parent directory\n \
'{.}': path without file extension\n \
'{/.}': basename without file extension\n\n\
'{/.}': basename without file extension\n \
'{{}': literal '{' (for escaping)\n\n\
If no placeholder is present, an implicit \"{}\" at the end is assumed.\n\n\
Examples:\n\n \
- Find all test_*.py files and open them in your favorite editor:\n\n \

View File

@ -232,7 +232,7 @@ impl CommandTemplate {
S: AsRef<str>,
{
static PLACEHOLDER_PATTERN: Lazy<Regex> =
Lazy::new(|| Regex::new(r"\{(/?\.?|//)\}").unwrap());
Lazy::new(|| Regex::new(r"\{(/?\.?|//|\{)\}").unwrap());
let mut args = Vec::new();
let mut has_placeholder = false;
@ -257,6 +257,11 @@ impl CommandTemplate {
"{/}" => tokens.push(Token::Basename),
"{//}" => tokens.push(Token::Parent),
"{/.}" => tokens.push(Token::BasenameNoExt),
"{{}" => {
tokens.push(Token::Text("{".to_owned()));
// Continue, because this isn't a real placeholder
continue;
}
_ => unreachable!("Unhandled placeholder"),
}
@ -420,6 +425,14 @@ impl ArgumentTemplate {
mod tests {
use super::*;
fn generate_str(template: &CommandTemplate, input: &str) -> Vec<String> {
template
.args
.iter()
.map(|arg| arg.generate(input, None).into_string().unwrap())
.collect()
}
#[test]
fn tokens_with_placeholder() {
assert_eq!(
@ -501,6 +514,21 @@ mod tests {
);
}
#[test]
fn tokens_with_literal_braces() {
let template = CommandTemplate::new(vec!["{{}}", "{{}", "{{}.}"]).unwrap();
assert_eq!(
generate_str(&template, "foo"),
vec!["{}", "{", "{.}", "foo"]
);
}
#[test]
fn tokens_with_literal_braces_and_placeholder() {
let template = CommandTemplate::new(vec!["{{}{},end}"]).unwrap();
assert_eq!(generate_str(&template, "foo"), vec!["{foo,end}"]);
}
#[test]
fn tokens_multiple() {
assert_eq!(