From 3a222def2221ef379033eab22840745cb50b8a7f Mon Sep 17 00:00:00 2001 From: sudotac Date: Sun, 3 Dec 2023 17:13:57 +0900 Subject: [PATCH] fix(complete): Fix path completion in bash Fix #5239 --- clap_complete/src/shells/bash.rs | 51 +++++++++++++------ .../home/static/exhaustive/bash/.bashrc | 6 +++ clap_complete/tests/snapshots/value_hint.bash | 6 +++ clap_complete/tests/testsuite/bash.rs | 2 +- 4 files changed, 48 insertions(+), 17 deletions(-) diff --git a/clap_complete/src/shells/bash.rs b/clap_complete/src/shells/bash.rs index 726078ab366..8c2755f68d7 100644 --- a/clap_complete/src/shells/bash.rs +++ b/clap_complete/src/shells/bash.rs @@ -168,29 +168,48 @@ fn option_details_for_path(cmd: &Command, path: &str) -> String { let mut opts = vec![String::new()]; for o in p.get_opts() { + let compopt = match o.get_value_hint() { + ValueHint::FilePath => Some("compopt -o filenames"), + _ => None, + }; + if let Some(longs) = o.get_long_and_visible_aliases() { opts.extend(longs.iter().map(|long| { - format!( - "--{}) - COMPREPLY=({}) - return 0 - ;;", - long, - vals_for(o) - ) + let mut v = vec![ + format!("--{})", long), + format!("COMPREPLY=({})", vals_for(o)), + ]; + + if let Some(copt) = compopt { + v.extend([ + r#"if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then"#.to_string(), + format!(" {}", copt), + "fi".to_string(), + ]); + } + + v.extend(["return 0", ";;"].iter().map(|s| s.to_string())); + v.join("\n ") })); } if let Some(shorts) = o.get_short_and_visible_aliases() { opts.extend(shorts.iter().map(|short| { - format!( - "-{}) - COMPREPLY=({}) - return 0 - ;;", - short, - vals_for(o) - ) + let mut v = vec![ + format!("-{})", short), + format!("COMPREPLY=({})", vals_for(o)), + ]; + + if let Some(copt) = compopt { + v.extend([ + r#"if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then"#.to_string(), + format!(" {}", copt), + "fi".to_string(), + ]); + } + + v.extend(["return 0", ";;"].iter().map(|s| s.to_string())); + v.join("\n ") })); } } diff --git a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc index 490fcbf3c1d..42621a2db84 100644 --- a/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc +++ b/clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc @@ -554,10 +554,16 @@ _exhaustive() { ;; --file) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; -f) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --dir) diff --git a/clap_complete/tests/snapshots/value_hint.bash b/clap_complete/tests/snapshots/value_hint.bash index 61e2f61e96e..ca042c541e4 100644 --- a/clap_complete/tests/snapshots/value_hint.bash +++ b/clap_complete/tests/snapshots/value_hint.bash @@ -47,10 +47,16 @@ _my-app() { ;; --file) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; -f) COMPREPLY=($(compgen -f "${cur}")) + if [[ "${BASH_VERSINFO[0]}" -ge 4 ]]; then + compopt -o filenames + fi return 0 ;; --dir) diff --git a/clap_complete/tests/testsuite/bash.rs b/clap_complete/tests/testsuite/bash.rs index 23d9353324f..66a6e4c54ce 100644 --- a/clap_complete/tests/testsuite/bash.rs +++ b/clap_complete/tests/testsuite/bash.rs @@ -164,7 +164,7 @@ fn complete() { // Issue 5239 (https://github.com/clap-rs/clap/issues/5239) let input = "exhaustive hint --file test\t"; - let expected = "exhaustive hint --file test % exhaustive hint --file tests "; + let expected = "exhaustive hint --file test % exhaustive hint --file tests/"; let actual = runtime.complete(input, &term).unwrap(); snapbox::assert_eq(expected, actual);