Skip to content

Commit

Permalink
Merge pull request #5336 from sudotac/prevent-filenames-splitting-in-…
Browse files Browse the repository at this point in the history
…bash-completion

fix(complete): Prevent filenames splitting in bash completion
  • Loading branch information
epage authored Feb 2, 2024
2 parents 2cc81c6 + 1edffb8 commit 0582e04
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 8 deletions.
42 changes: 34 additions & 8 deletions clap_complete/src/shells/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,23 @@ fn option_details_for_path(cmd: &Command, path: &str) -> String {

if let Some(longs) = o.get_long_and_visible_aliases() {
opts.extend(longs.iter().map(|long| {
let mut v = vec![
format!("--{})", long),
format!("COMPREPLY=({})", vals_for(o)),
];
let mut v = vec![format!("--{})", long)];

if o.get_value_hint() == ValueHint::FilePath {
v.extend([
"local oldifs".to_string(),
"if [[ -v IFS ]]; then".to_string(),
r#" oldifs="$IFS""#.to_string(),
"fi".to_string(),
r#"IFS=$'\n'"#.to_string(),
format!("COMPREPLY=({})", vals_for(o)),
"if [[ -v oldifs ]]; then".to_string(),
r#" IFS="$oldifs""#.to_string(),
"fi".to_string(),
]);
} else {
v.push(format!("COMPREPLY=({})", vals_for(o)));
}

if let Some(copt) = compopt {
v.extend([
Expand All @@ -198,10 +211,23 @@ fn option_details_for_path(cmd: &Command, path: &str) -> String {

if let Some(shorts) = o.get_short_and_visible_aliases() {
opts.extend(shorts.iter().map(|short| {
let mut v = vec![
format!("-{})", short),
format!("COMPREPLY=({})", vals_for(o)),
];
let mut v = vec![format!("-{})", short)];

if o.get_value_hint() == ValueHint::FilePath {
v.extend([
"local oldifs".to_string(),
"if [[ -v IFS ]]; then".to_string(),
r#" oldifs="$IFS""#.to_string(),
"fi".to_string(),
r#"IFS=$'\n'"#.to_string(),
format!("COMPREPLY=({})", vals_for(o)),
"if [[ -v oldifs ]]; then".to_string(),
r#" IFS="$oldifs""#.to_string(),
"fi".to_string(),
]);
} else {
v.push(format!("COMPREPLY=({})", vals_for(o)));
}

if let Some(copt) = compopt {
v.extend([
Expand Down
16 changes: 16 additions & 0 deletions clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc
Original file line number Diff line number Diff line change
Expand Up @@ -556,14 +556,30 @@ _exhaustive() {
return 0
;;
--file)
local oldifs
if [[ -v IFS ]]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [[ -v oldifs ]]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
return 0
;;
-f)
local oldifs
if [[ -v IFS ]]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [[ -v oldifs ]]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
Expand Down
16 changes: 16 additions & 0 deletions clap_complete/tests/snapshots/value_hint.bash
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,30 @@ _my-app() {
return 0
;;
--file)
local oldifs
if [[ -v IFS ]]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [[ -v oldifs ]]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
return 0
;;
-f)
local oldifs
if [[ -v IFS ]]; then
oldifs="$IFS"
fi
IFS=$'\n'
COMPREPLY=($(compgen -f "${cur}"))
if [[ -v oldifs ]]; then
IFS="$oldifs"
fi
if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then
compopt -o filenames
fi
Expand Down
21 changes: 21 additions & 0 deletions clap_complete/tests/testsuite/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,27 @@ fn complete() {
);
}

// Issue 5313 (https://github.com/clap-rs/clap/issues/5313)
{
use std::fs::File;
use std::path::Path;

let testdir = snapbox::path::PathFixture::mutable_temp().unwrap();
let testdir_path = testdir.path().unwrap();

File::create(Path::new(testdir_path).join("foo bar.txt")).unwrap();
File::create(Path::new(testdir_path).join("baz\tqux.txt")).unwrap();

let input = format!(
"exhaustive hint --file {}/\t\t",
testdir_path.to_string_lossy()
);
let expected = r#"%
foo bar.txt baz^Iqux.txt "#;
let actual = runtime.complete(input.as_str(), &term).unwrap();
snapbox::assert_eq(expected, actual);
}

let input = "exhaustive hint --other \t";
let expected = "exhaustive hint --other % exhaustive hint --other ";
let actual = runtime.complete(input, &term).unwrap();
Expand Down

0 comments on commit 0582e04

Please sign in to comment.