Skip to content

Commit 40650fa

Browse files
authored
Merge pull request #5048 from ModProg/fish-dynamic-completions-v3
feat(completions): Dynamic fish completions
2 parents a3d93f4 + 4f9cf6b commit 40650fa

File tree

10 files changed

+82
-4
lines changed

10 files changed

+82
-4
lines changed
+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/// Fish completions
2+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
3+
pub struct Fish;
4+
5+
impl crate::dynamic::Completer for Fish {
6+
fn file_name(&self, name: &str) -> String {
7+
format!("{name}.fish")
8+
}
9+
fn write_registration(
10+
&self,
11+
_name: &str,
12+
bin: &str,
13+
completer: &str,
14+
buf: &mut dyn std::io::Write,
15+
) -> Result<(), std::io::Error> {
16+
let bin = shlex::quote(bin);
17+
let completer = shlex::quote(completer);
18+
writeln!(
19+
buf,
20+
r#"complete -x -c {bin} -a "("'{completer}'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))""#
21+
)
22+
}
23+
fn write_complete(
24+
&self,
25+
cmd: &mut clap::Command,
26+
args: Vec<std::ffi::OsString>,
27+
current_dir: Option<&std::path::Path>,
28+
buf: &mut dyn std::io::Write,
29+
) -> Result<(), std::io::Error> {
30+
let index = args.len() - 1;
31+
let completions = crate::dynamic::complete(cmd, args, index, current_dir)?;
32+
33+
for completion in completions {
34+
writeln!(buf, "{}", completion.to_string_lossy())?;
35+
}
36+
Ok(())
37+
}
38+
}

clap_complete/src/dynamic/shells/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
//! Shell support
22
33
mod bash;
4+
mod fish;
45
mod shell;
56

67
pub use bash::*;
8+
pub use fish::*;
79
pub use shell::*;
810

911
use std::ffi::OsString;

clap_complete/src/dynamic/shells/shell.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ use clap::ValueEnum;
1010
pub enum Shell {
1111
/// Bourne Again SHell (bash)
1212
Bash,
13+
/// Friendly Interactive SHell (fish)
14+
Fish,
1315
}
1416

1517
impl Display for Shell {
@@ -37,12 +39,13 @@ impl FromStr for Shell {
3739
// Hand-rolled so it can work even when `derive` feature is disabled
3840
impl ValueEnum for Shell {
3941
fn value_variants<'a>() -> &'a [Self] {
40-
&[Shell::Bash]
42+
&[Shell::Bash, Shell::Fish]
4143
}
4244

4345
fn to_possible_value<'a>(&self) -> Option<PossibleValue> {
4446
Some(match self {
4547
Shell::Bash => PossibleValue::new("bash"),
48+
Shell::Fish => PossibleValue::new("fish"),
4649
})
4750
}
4851
}
@@ -51,6 +54,7 @@ impl Shell {
5154
fn completer(&self) -> &dyn crate::dynamic::Completer {
5255
match self {
5356
Self::Bash => &super::Bash,
57+
Self::Fish => &super::Fish,
5458
}
5559
}
5660
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complete -x -c exhaustive -a "("'exhaustive'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token))"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
set -U fish_greeting ""
2+
set -U fish_autosuggestion_enabled 0
3+
function fish_title
4+
end
5+
function fish_prompt
6+
printf '%% '
7+
end;

clap_complete/tests/snapshots/home/static/exhaustive/bash/.bashrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ _exhaustive() {
236236
fi
237237
case "${prev}" in
238238
--shell)
239-
COMPREPLY=($(compgen -W "bash" -- "${cur}"))
239+
COMPREPLY=($(compgen -W "bash fish" -- "${cur}"))
240240
return 0
241241
;;
242242
--register)

clap_complete/tests/snapshots/home/static/exhaustive/fish/fish/completions/exhaustive.fish

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l email -r -f
104104
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -l global -d 'everywhere'
105105
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s h -l help -d 'Print help'
106106
complete -c exhaustive -n "__fish_seen_subcommand_from hint" -s V -l version -d 'Print version'
107-
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash }"
107+
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l shell -d 'Specify shell to complete for' -r -f -a "{bash ,fish }"
108108
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l register -d 'Path to write completion-registration to' -r -F
109109
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -l global -d 'everywhere'
110110
complete -c exhaustive -n "__fish_seen_subcommand_from complete" -s h -l help -d 'Print help (see more with \'--help\')'

clap_complete/tests/snapshots/home/static/exhaustive/zsh/zsh/_exhaustive

+1-1
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ _arguments "${_arguments_options[@]}" \
309309
;;
310310
(complete)
311311
_arguments "${_arguments_options[@]}" \
312-
'--shell=[Specify shell to complete for]:SHELL:(bash)' \
312+
'--shell=[Specify shell to complete for]:SHELL:(bash fish)' \
313313
'--register=[Path to write completion-registration to]:REGISTER:_files' \
314314
'--global[everywhere]' \
315315
'-h[Print help (see more with '\''--help'\'')]' \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
complete -x -c my-app -a 'my-app'" complete --shell fish -- (commandline --current-process --tokenize --cut-at-cursor) (commandline --current-token)"

clap_complete/tests/testsuite/fish.rs

+25
Original file line numberDiff line numberDiff line change
@@ -143,3 +143,28 @@ alias help (Print this message or the help of the given subcommand(s)) last
143143
let actual = runtime.complete(input, &term).unwrap();
144144
snapbox::assert_eq(expected, actual);
145145
}
146+
147+
#[cfg(all(unix, feature = "unstable-dynamic"))]
148+
#[test]
149+
fn register_dynamic() {
150+
common::register_example("dynamic", "exhaustive", completest::Shell::Fish);
151+
}
152+
153+
#[test]
154+
#[cfg(all(unix, feature = "unstable-dynamic"))]
155+
fn complete_dynamic() {
156+
if !common::has_command("fish") {
157+
return;
158+
}
159+
160+
let term = completest::Term::new();
161+
let mut runtime = common::load_runtime("dynamic", "exhaustive", completest::Shell::Fish);
162+
163+
let input = "exhaustive \t";
164+
let expected = r#"% exhaustive
165+
action help pacman -h --global
166+
alias hint quote -V --help
167+
complete last value --generate --version"#;
168+
let actual = runtime.complete(input, &term).unwrap();
169+
snapbox::assert_eq(expected, actual);
170+
}

0 commit comments

Comments
 (0)