mirror of
https://github.com/clap-rs/clap
synced 2024-12-15 07:12:32 +00:00
feat(clap_complete): Add elvish support for native completion
This commit is contained in:
parent
4a8d6806d9
commit
697b88e28f
8 changed files with 122 additions and 4 deletions
58
clap_complete/src/dynamic/shells/elvish.rs
Normal file
58
clap_complete/src/dynamic/shells/elvish.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
/// Completion support for Bash
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Elvish;
|
||||||
|
|
||||||
|
impl crate::dynamic::Completer for Elvish {
|
||||||
|
fn file_name(&self, name: &str) -> String {
|
||||||
|
format!("{name}.elv")
|
||||||
|
}
|
||||||
|
fn write_registration(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
bin: &str,
|
||||||
|
completer: &str,
|
||||||
|
buf: &mut dyn std::io::Write,
|
||||||
|
) -> Result<(), std::io::Error> {
|
||||||
|
let bin = shlex::quote(bin);
|
||||||
|
let completer = shlex::quote(completer);
|
||||||
|
|
||||||
|
let script = r#"
|
||||||
|
set edit:completion:arg-completer[BIN] = { |@words|
|
||||||
|
set E:_CLAP_IFS = "\n"
|
||||||
|
|
||||||
|
var index = (count $words)
|
||||||
|
set index = (- $index 1)
|
||||||
|
set E:_CLAP_COMPLETE_INDEX = (to-string $index)
|
||||||
|
|
||||||
|
put (COMPLETER complete --shell elvish -- $@words) | to-lines
|
||||||
|
}
|
||||||
|
"#
|
||||||
|
.replace("COMPLETER", &completer)
|
||||||
|
.replace("BIN", &bin);
|
||||||
|
|
||||||
|
writeln!(buf, "{script}")?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn write_complete(
|
||||||
|
&self,
|
||||||
|
cmd: &mut clap::Command,
|
||||||
|
args: Vec<std::ffi::OsString>,
|
||||||
|
current_dir: Option<&std::path::Path>,
|
||||||
|
buf: &mut dyn std::io::Write,
|
||||||
|
) -> Result<(), std::io::Error> {
|
||||||
|
let index: usize = std::env::var("_CLAP_COMPLETE_INDEX")
|
||||||
|
.ok()
|
||||||
|
.and_then(|i| i.parse().ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
let ifs: Option<String> = std::env::var("_CLAP_IFS").ok().and_then(|i| i.parse().ok());
|
||||||
|
let completions = crate::dynamic::complete(cmd, args, index, current_dir)?;
|
||||||
|
|
||||||
|
for (i, (completion, _)) in completions.iter().enumerate() {
|
||||||
|
if i != 0 {
|
||||||
|
write!(buf, "{}", ifs.as_deref().unwrap_or("\n"))?;
|
||||||
|
}
|
||||||
|
write!(buf, "{}", completion.to_string_lossy())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,13 @@
|
||||||
//! Shell support
|
//! Shell support
|
||||||
|
|
||||||
mod bash;
|
mod bash;
|
||||||
|
mod elvish;
|
||||||
mod fish;
|
mod fish;
|
||||||
mod shell;
|
mod shell;
|
||||||
mod zsh;
|
mod zsh;
|
||||||
|
|
||||||
pub use bash::*;
|
pub use bash::*;
|
||||||
|
pub use elvish::*;
|
||||||
pub use fish::*;
|
pub use fish::*;
|
||||||
pub use shell::*;
|
pub use shell::*;
|
||||||
pub use zsh::*;
|
pub use zsh::*;
|
||||||
|
|
|
@ -14,6 +14,8 @@ pub enum Shell {
|
||||||
Fish,
|
Fish,
|
||||||
/// Z shell (zsh)
|
/// Z shell (zsh)
|
||||||
Zsh,
|
Zsh,
|
||||||
|
/// Elf `SHell` (elvish)
|
||||||
|
Elvish,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Shell {
|
impl Display for Shell {
|
||||||
|
@ -41,7 +43,7 @@ impl FromStr for Shell {
|
||||||
// Hand-rolled so it can work even when `derive` feature is disabled
|
// Hand-rolled so it can work even when `derive` feature is disabled
|
||||||
impl ValueEnum for Shell {
|
impl ValueEnum for Shell {
|
||||||
fn value_variants<'a>() -> &'a [Self] {
|
fn value_variants<'a>() -> &'a [Self] {
|
||||||
&[Shell::Bash, Shell::Fish, Shell::Zsh]
|
&[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::Elvish]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||||
|
@ -49,6 +51,7 @@ impl ValueEnum for Shell {
|
||||||
Shell::Bash => PossibleValue::new("bash"),
|
Shell::Bash => PossibleValue::new("bash"),
|
||||||
Shell::Fish => PossibleValue::new("fish"),
|
Shell::Fish => PossibleValue::new("fish"),
|
||||||
Shell::Zsh => PossibleValue::new("zsh"),
|
Shell::Zsh => PossibleValue::new("zsh"),
|
||||||
|
Shell::Elvish => PossibleValue::new("elvish"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,6 +62,7 @@ impl Shell {
|
||||||
Self::Bash => &super::Bash,
|
Self::Bash => &super::Bash,
|
||||||
Self::Fish => &super::Fish,
|
Self::Fish => &super::Fish,
|
||||||
Self::Zsh => &super::Zsh,
|
Self::Zsh => &super::Zsh,
|
||||||
|
Self::Elvish => &super::Elvish,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
set edit:rprompt = (constantly "")
|
||||||
|
set edit:prompt = (constantly "% ")
|
||||||
|
|
||||||
|
set edit:completion:arg-completer[exhaustive] = { |@words|
|
||||||
|
set E:_CLAP_IFS = "\n"
|
||||||
|
|
||||||
|
var index = (count $words)
|
||||||
|
set index = (- $index 1)
|
||||||
|
set E:_CLAP_COMPLETE_INDEX = (to-string $index)
|
||||||
|
|
||||||
|
put (exhaustive complete --shell elvish -- $@words) | to-lines
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ _exhaustive() {
|
||||||
fi
|
fi
|
||||||
case "${prev}" in
|
case "${prev}" in
|
||||||
--shell)
|
--shell)
|
||||||
COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}"))
|
COMPREPLY=($(compgen -W "bash fish zsh elvish" -- "${cur}"))
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
--register)
|
--register)
|
||||||
|
|
|
@ -136,7 +136,7 @@ complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -l email -r
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -l global -d 'everywhere'
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -l global -d 'everywhere'
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s h -l help -d 'Print help'
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s h -l help -d 'Print help'
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s V -l version -d 'Print version'
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand hint" -s V -l version -d 'Print version'
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash\t'',fish\t'',zsh\t''}"
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash\t'',fish\t'',zsh\t'',elvish\t''}"
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l register -d 'Path to write completion-registration to' -r -F
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l register -d 'Path to write completion-registration to' -r -F
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l global -d 'everywhere'
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -l global -d 'everywhere'
|
||||||
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -s h -l help -d 'Print help (see more with \'--help\')'
|
complete -c exhaustive -n "__fish_exhaustive_using_subcommand complete" -s h -l help -d 'Print help (see more with \'--help\')'
|
||||||
|
|
|
@ -325,7 +325,7 @@ _arguments "${_arguments_options[@]}" : \
|
||||||
;;
|
;;
|
||||||
(complete)
|
(complete)
|
||||||
_arguments "${_arguments_options[@]}" : \
|
_arguments "${_arguments_options[@]}" : \
|
||||||
'--shell=[Specify shell to complete for]:SHELL:(bash fish zsh)' \
|
'--shell=[Specify shell to complete for]:SHELL:(bash fish zsh elvish)' \
|
||||||
'--register=[Path to write completion-registration to]:REGISTER:_files' \
|
'--register=[Path to write completion-registration to]:REGISTER:_files' \
|
||||||
'--global[everywhere]' \
|
'--global[everywhere]' \
|
||||||
'-h[Print help (see more with '\''--help'\'')]' \
|
'-h[Print help (see more with '\''--help'\'')]' \
|
||||||
|
|
|
@ -174,3 +174,43 @@ value value
|
||||||
let actual = runtime.complete(input, &term).unwrap();
|
let actual = runtime.complete(input, &term).unwrap();
|
||||||
assert_data_eq!(actual, expected);
|
assert_data_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "unstable-dynamic"))]
|
||||||
|
#[test]
|
||||||
|
fn register_dynamic() {
|
||||||
|
common::register_example::<completest_pty::ElvishRuntimeBuilder>("dynamic", "exhaustive");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(all(unix, feature = "unstable-dynamic"))]
|
||||||
|
fn complete_dynamic() {
|
||||||
|
if !common::has_command("elvish") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let term = completest::Term::new();
|
||||||
|
let mut runtime =
|
||||||
|
common::load_runtime::<completest_pty::ElvishRuntimeBuilder>("dynamic", "exhaustive");
|
||||||
|
|
||||||
|
let input = "exhaustive \t";
|
||||||
|
let expected = snapbox::str![
|
||||||
|
r#"% exhaustive --generate
|
||||||
|
COMPLETING argument
|
||||||
|
--generate --help -V action complete hint pacman value
|
||||||
|
--global --version -h alias help last quote "#
|
||||||
|
];
|
||||||
|
let actual = runtime.complete(input, &term).unwrap();
|
||||||
|
assert_data_eq!(actual, expected);
|
||||||
|
|
||||||
|
let input = "exhaustive quote \t";
|
||||||
|
let expected = snapbox::str![
|
||||||
|
r#"% exhaustive quote --backslash
|
||||||
|
COMPLETING argument
|
||||||
|
--backslash --double-quotes --single-quotes cmd-backslash cmd-expansions
|
||||||
|
--backticks --expansions --version cmd-backticks cmd-single-quotes
|
||||||
|
--brackets --global -V cmd-brackets escape-help
|
||||||
|
--choice --help -h cmd-double-quotes help "#
|
||||||
|
];
|
||||||
|
let actual = runtime.complete(input, &term).unwrap();
|
||||||
|
assert_data_eq!(actual, expected);
|
||||||
|
}
|
Loading…
Reference in a new issue