Skip to content

Commit

Permalink
feat(complete): Dynamic fish completions
Browse files Browse the repository at this point in the history
  • Loading branch information
ModProg committed Jul 31, 2023
1 parent a3d93f4 commit 4f9cf6b
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 4 deletions.
38 changes: 38 additions & 0 deletions clap_complete/src/dynamic/shells/fish.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/// Fish completions
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Fish;

impl crate::dynamic::Completer for Fish {
fn file_name(&self, name: &str) -> String {
format!("{name}.fish")
}
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);
writeln!(
buf,
r#"complete -x -c {bin} -a "("'{completer}'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))""#
)
}
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 = args.len() - 1;
let completions = crate::dynamic::complete(cmd, args, index, current_dir)?;

for completion in completions {
writeln!(buf, "{}", completion.to_string_lossy())?;
}
Ok(())
}
}
2 changes: 2 additions & 0 deletions clap_complete/src/dynamic/shells/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! Shell support

mod bash;
mod fish;
mod shell;

pub use bash::*;
pub use fish::*;
pub use shell::*;

use std::ffi::OsString;
Expand Down
6 changes: 5 additions & 1 deletion clap_complete/src/dynamic/shells/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use clap::ValueEnum;
pub enum Shell {
/// Bourne Again SHell (bash)
Bash,
/// Friendly Interactive SHell (fish)
Fish,
}

impl Display for Shell {
Expand Down Expand Up @@ -37,12 +39,13 @@ 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::Bash, Shell::Fish]
}

fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
Some(match self {
Shell::Bash => PossibleValue::new("bash"),
Shell::Fish => PossibleValue::new("fish"),
})
}
}
Expand All @@ -51,6 +54,7 @@ impl Shell {
fn completer(&self) -> &dyn crate::dynamic::Completer {
match self {
Self::Bash => &super::Bash,
Self::Fish => &super::Fish,
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
complete -x -c exhaustive -a "("'exhaustive'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))"
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
set -U fish_greeting ""
set -U fish_autosuggestion_enabled 0
function fish_title
end
function fish_prompt
printf '%% '
end;
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ _exhaustive() {
fi
case "${prev}" in
--shell)
COMPREPLY=($(compgen -W "bash" -- "${cur}"))
COMPREPLY=($(compgen -W "bash fish" -- "${cur}"))
return 0
;;
--register)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l email -r -f
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l global -d 'everywhere'
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s h -l help -d 'Print help'
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s V -l version -d 'Print version'
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash }"
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash ,fish }"
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l register -d 'Path to write completion-registration to' -r -F
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l global -d 'everywhere'
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ _arguments "${_arguments_options[@]}" \
;;
(complete)
_arguments "${_arguments_options[@]}" \
'--shell=[Specify shell to complete for]:SHELL:(bash)' \
'--shell=[Specify shell to complete for]:SHELL:(bash fish)' \
'--register=[Path to write completion-registration to]:REGISTER:_files' \
'--global[everywhere]' \
'-h[Print help (see more with '\''--help'\'')]' \
Expand Down
1 change: 1 addition & 0 deletions clap_complete/tests/snapshots/register_dynamic.fish
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
complete -x -c my-app -a 'my-app'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token)"
25 changes: 25 additions & 0 deletions clap_complete/tests/testsuite/fish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,28 @@ alias help (Print this message or the help of the given subcommand(s)) last
let actual = runtime.complete(input, &term).unwrap();
snapbox::assert_eq(expected, actual);
}

#[cfg(all(unix, feature = "unstable-dynamic"))]
#[test]
fn register_dynamic() {
common::register_example("dynamic", "exhaustive", completest::Shell::Fish);
}

#[test]
#[cfg(all(unix, feature = "unstable-dynamic"))]
fn complete_dynamic() {
if !common::has_command("fish") {
return;
}

let term = completest::Term::new();
let mut runtime = common::load_runtime("dynamic", "exhaustive", completest::Shell::Fish);

let input = "exhaustive \t";
let expected = r#"% exhaustive
action help pacman -h --global
alias hint quote -V --help
complete last value --generate --version"#;
let actual = runtime.complete(input, &term).unwrap();
snapbox::assert_eq(expected, actual);
}

0 comments on commit 4f9cf6b

Please sign in to comment.