Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 37 additions & 1 deletion clap_complete/src/env/shells.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@ _clap_complete_NAME() {
elif [[ $_CLAP_COMPLETE_SPACE == false ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
compopt -o nospace
fi
if [[ -n ${COMP_WORDBREAKS+x} ]]; then
# If the current word contains a word break character, we need to strip
# the prefix up to that character from each completion
local prefix
prefix="${2%"${2##*[${COMP_WORDBREAKS}]}"}"
if [[ -n "$prefix" ]]; then
COMPREPLY=("${COMPREPLY[@]#"$prefix"}")
fi
fi
}
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
complete -o nospace -o bashdefault -o nosort -F _clap_complete_NAME BIN
Expand Down Expand Up @@ -463,13 +472,40 @@ impl Zsh {
#[cfg(test)]
mod tests {
use super::*;
use snapbox::assert_data_eq;

#[test]
#[cfg(feature = "unstable-dynamic")]
fn bash_registration_handles_wordbreaks() {
let mut buf = Vec::new();
let bash = Bash;
bash.write_registration("COMPLETE", "my-app", "my-app", "my-app", &mut buf)
.expect("write_registration failed");
let script = String::from_utf8(buf).expect("Invalid UTF-8");

// The registration script must check for COMP_WORDBREAKS to handle shells
// where `=` and `:` are word-break characters. Without this, completing
// `--flag=value` would produce `--flag=--flag=value` because Bash splits
// at `=` and only replaces the part after it.
assert!(
script.contains("COMP_WORDBREAKS"),
"registration script must reference COMP_WORDBREAKS to handle word-break characters"
);

// The script must strip the prefix up to the word-break character from
// each completion entry using the `${COMPREPLY[@]#"$prefix"}` pattern.
// This is the shell-side fix that prevents double-prefixing.
assert!(
script.contains(r#"COMPREPLY=("${COMPREPLY[@]#"$prefix"}")"#),
"registration script must strip word-break prefix from COMPREPLY entries"
);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please test behavior, not implementation


// This test verifies that fish shell path quoting works with or without spaces in the path.
#[test]
#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(feature = "unstable-shell-tests")]
fn fish_env_completer_path_quoting_works() {
use snapbox::assert_data_eq;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this being added in this commit

// Returns the dynamic registration line for the fish shell, for example:
// complete --keep-order --exclusive --command my-bin --arguments "(COMPLETE=fish /path/to/my-bin ... )"
let get_fish_registration = |completer_bin: &str| {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ _clap_complete_exhaustive() {
elif [[ $_CLAP_COMPLETE_SPACE == false ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
compopt -o nospace
fi
if [[ -n ${COMP_WORDBREAKS+x} ]]; then
# If the current word contains a word break character, we need to strip
# the prefix up to that character from each completion
local prefix
prefix="${2%"${2##*[${COMP_WORDBREAKS}]}"}"
if [[ -n "$prefix" ]]; then
COMPREPLY=("${COMPREPLY[@]#"$prefix"}")
fi
fi
}
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
complete -o nospace -o bashdefault -o nosort -F _clap_complete_exhaustive exhaustive
Expand Down
Loading