Skip to content
Closed
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
28 changes: 27 additions & 1 deletion clap_complete/src/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

mod shells;

use std::collections::HashSet;
use std::ffi::OsString;
use std::io::Write as _;

Expand Down Expand Up @@ -104,6 +105,7 @@ pub struct CompleteEnv<'s, F> {
var: &'static str,
bin: Option<String>,
completer: Option<String>,
skip_wordbreaks: HashSet<char>,
shells: Shells<'s>,
}

Expand Down Expand Up @@ -152,6 +154,7 @@ impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
var: "COMPLETE",
bin: None,
completer: None,
skip_wordbreaks: HashSet::from(['=']),
shells: Shells::builtins(),
}
}
Expand Down Expand Up @@ -185,6 +188,27 @@ impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
}
}

impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
/// Adds individual characters from `wordbreaks` to the set of wordbreaks to skip.
pub fn allow_wordbreak(mut self, wordbreak: char) -> Self {
self.skip_wordbreaks.insert(wordbreak);
self
}

/// Sets the entire set of wordbreaks to skip, replacing any existing ones.
/// The input `wordbreaks` string is interpreted as a sequence of individual characters.
pub fn allow_wordbreaks(mut self, wordbreaks: &str) -> Self {
self.skip_wordbreaks.extend(wordbreaks.chars());
self
}

/// Clears all existing wordbreaks to skip.
pub fn clear_allowed_wordbreaks(mut self) -> Self {
self.skip_wordbreaks.clear();
self
}
}

impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
/// Process the completion request and exit
///
Expand Down Expand Up @@ -288,6 +312,7 @@ impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let name = cmd.get_name();
let skip_wordbreaks: String = self.skip_wordbreaks.iter().collect();
let bin = self
.bin
.as_deref()
Expand All @@ -305,7 +330,7 @@ impl<'s, F: Fn() -> clap::Command> CompleteEnv<'s, F> {
completer.to_string_lossy().into_owned()
};

shell.write_registration(self.var, name, bin, &completer, buf)?;
shell.write_registration(self.var, name, bin, &completer, &skip_wordbreaks, buf)?;

Ok(())
}
Expand Down Expand Up @@ -379,6 +404,7 @@ pub trait EnvCompleter {
name: &str,
bin: &str,
completer: &str,
skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error>;
/// Complete the given command
Expand Down
18 changes: 15 additions & 3 deletions clap_complete/src/env/shells.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,19 @@ impl EnvCompleter for Bash {
name: &str,
bin: &str,
completer: &str,
skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let escaped_name = name.replace('-', "_");

let completer =
shlex::try_quote(completer).unwrap_or(std::borrow::Cow::Borrowed(completer));

let comp_wordbreaks = match skip_wordbreaks {
"" => "",
s => &format!("COMP_WORDBREAKS=${{COMP_WORDBREAKS//[{}]/}} ", s)
};

let script = r#"
_clap_complete_NAME() {
local IFS=$'\013'
Expand Down Expand Up @@ -56,15 +62,16 @@ _clap_complete_NAME() {
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
SKIPScomplete -o nospace -o bashdefault -o nosort -F _clap_complete_NAME BIN
else
complete -o nospace -o bashdefault -F _clap_complete_NAME BIN
SKIPScomplete -o nospace -o bashdefault -F _clap_complete_NAME BIN
fi
"#
.replace("NAME", &escaped_name)
.replace("BIN", bin)
.replace("COMPLETER", &completer)
.replace("VAR", var);
.replace("VAR", var)
.replace("SKIPS", comp_wordbreaks);

writeln!(buf, "{script}")?;
Ok(())
Expand Down Expand Up @@ -149,6 +156,7 @@ impl EnvCompleter for Elvish {
_name: &str,
bin: &str,
completer: &str,
_skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin));
Expand Down Expand Up @@ -211,6 +219,7 @@ impl EnvCompleter for Fish {
_name: &str,
bin: &str,
completer: &str,
_skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin));
Expand Down Expand Up @@ -264,6 +273,7 @@ impl EnvCompleter for Powershell {
_name: &str,
bin: &str,
completer: &str,
_skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let bin = shlex::try_quote(bin).unwrap_or(std::borrow::Cow::Borrowed(bin));
Expand Down Expand Up @@ -356,6 +366,7 @@ impl EnvCompleter for Zsh {
name: &str,
bin: &str,
completer: &str,
_skip_wordbreaks: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
let escaped_name = name.replace('-', "_");
Expand Down Expand Up @@ -480,6 +491,7 @@ mod tests {
"ignored-name",
"/ignored/bin",
completer_bin,
"",
&mut buf,
)
.expect("write_registration failed");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ _clap_complete_exhaustive() {
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
COMP_WORDBREAKS=${COMP_WORDBREAKS//[=]/} complete -o nospace -o bashdefault -o nosort -F _clap_complete_exhaustive exhaustive
else
complete -o nospace -o bashdefault -F _clap_complete_exhaustive exhaustive
COMP_WORDBREAKS=${COMP_WORDBREAKS//[=]/} complete -o nospace -o bashdefault -F _clap_complete_exhaustive exhaustive
fi


Loading