mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 06:42:33 +00:00
Merge pull request #5544 from shannmu/elvish_glue
feat(clap_complete): add native completion support for elvish
This commit is contained in:
commit
ff204809a5
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
|
||||
|
||||
mod bash;
|
||||
mod elvish;
|
||||
mod fish;
|
||||
mod shell;
|
||||
mod zsh;
|
||||
|
||||
pub use bash::*;
|
||||
pub use elvish::*;
|
||||
pub use fish::*;
|
||||
pub use shell::*;
|
||||
pub use zsh::*;
|
||||
|
|
|
@ -14,6 +14,8 @@ pub enum Shell {
|
|||
Fish,
|
||||
/// Z shell (zsh)
|
||||
Zsh,
|
||||
/// Elf `SHell` (elvish)
|
||||
Elvish,
|
||||
}
|
||||
|
||||
impl Display for Shell {
|
||||
|
@ -41,7 +43,7 @@ impl FromStr for Shell {
|
|||
// Hand-rolled so it can work even when `derive` feature is disabled
|
||||
impl ValueEnum for Shell {
|
||||
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> {
|
||||
|
@ -49,6 +51,7 @@ impl ValueEnum for Shell {
|
|||
Shell::Bash => PossibleValue::new("bash"),
|
||||
Shell::Fish => PossibleValue::new("fish"),
|
||||
Shell::Zsh => PossibleValue::new("zsh"),
|
||||
Shell::Elvish => PossibleValue::new("elvish"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +62,7 @@ impl Shell {
|
|||
Self::Bash => &super::Bash,
|
||||
Self::Fish => &super::Fish,
|
||||
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
|
||||
case "${prev}" in
|
||||
--shell)
|
||||
COMPREPLY=($(compgen -W "bash fish zsh" -- "${cur}"))
|
||||
COMPREPLY=($(compgen -W "bash fish zsh elvish" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--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" -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 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 global -d 'everywhere'
|
||||
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)
|
||||
_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' \
|
||||
'--global[everywhere]' \
|
||||
'-h[Print help (see more with '\''--help'\'')]' \
|
||||
|
|
|
@ -174,3 +174,43 @@ value value
|
|||
let actual = runtime.complete(input, &term).unwrap();
|
||||
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