Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(complete)!: Put CompleteCommand behind unstable-command #5665

Merged
merged 4 commits into from
Aug 11, 2024
Merged
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
7 changes: 4 additions & 3 deletions clap_complete/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ automod = "1.0.14"

[[example]]
name = "dynamic"
required-features = ["unstable-dynamic"]
required-features = ["unstable-dynamic", "unstable-command"]

[features]
default = []
unstable-doc = ["unstable-dynamic"] # for docs.rs
unstable-dynamic = ["dep:clap_lex", "dep:shlex", "dep:unicode-xid", "clap/derive", "dep:is_executable", "dep:pathdiff", "clap/unstable-ext"]
unstable-doc = ["unstable-dynamic", "unstable-command"] # for docs.rs
unstable-dynamic = ["dep:clap_lex", "dep:is_executable", "dep:pathdiff", "clap/unstable-ext"]
unstable-command = ["unstable-dynamic", "dep:shlex", "dep:unicode-xid", "clap/derive", "dep:is_executable", "dep:pathdiff", "clap/unstable-ext"]
debug = ["clap/debug"]

[lints]
Expand Down
6 changes: 3 additions & 3 deletions clap_complete/examples/exhaustive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use clap::builder::PossibleValue;
#[cfg(feature = "unstable-dynamic")]
#[cfg(feature = "unstable-command")]
use clap::{FromArgMatches, Subcommand};
use clap_complete::{generate, Generator, Shell};

Expand All @@ -12,7 +12,7 @@ fn main() {
return;
}

#[cfg(feature = "unstable-dynamic")]
#[cfg(feature = "unstable-command")]
if let Ok(completions) = clap_complete::dynamic::CompleteCommand::from_arg_matches(&matches) {
completions.complete(&mut cli());
return;
Expand Down Expand Up @@ -195,7 +195,7 @@ fn cli() -> clap::Command {
.value_hint(clap::ValueHint::EmailAddress),
]),
]);
#[cfg(feature = "unstable-dynamic")]
#[cfg(feature = "unstable-command")]
let cli = clap_complete::dynamic::CompleteCommand::augment_subcommands(cli);
cli
}
2 changes: 1 addition & 1 deletion clap_complete/src/dynamic/candidate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::builder::StyledStr;

/// A shell-agnostic completion candidate
///
/// [`ShellCompleter`][crate::dynamic::shells::ShellCompleter] will adapt what it can to the
/// [`Shell`][crate::dynamic::shells::Shell] will adapt what it can to the
/// current shell.
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CompletionCandidate {
Expand Down
2 changes: 1 addition & 1 deletion clap_complete/src/dynamic/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use super::CompletionCandidate;
///
/// For integration with clap and shells, see [`CompleteCommand`][crate::dynamic::shells::CompleteCommand].
///
/// This is generally called by a [`ShellCompleter`][crate::dynamic::shells::ShellCompleter] which
/// This is generally called by a [`Shell`][crate::dynamic::shells::Shell] which
/// handles the shell-specific logic.
pub fn complete(
cmd: &mut clap::Command,
Expand Down
2 changes: 2 additions & 0 deletions clap_complete/src/dynamic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ pub use custom::ArgValueCompleter;
pub use custom::CustomCompleter;

// These live in `shells` because they are tightly coupled with the `ShellCompleter`s
#[cfg(feature = "unstable-command")]
pub use shells::CompleteArgs;
#[cfg(feature = "unstable-command")]
pub use shells::CompleteCommand;
57 changes: 47 additions & 10 deletions clap_complete/src/dynamic/shells/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ use super::Shell;
#[allow(missing_docs)]
#[derive(Clone, Debug)]
#[command(about = None, long_about = None)]
#[cfg(feature = "unstable-command")]
pub enum CompleteCommand {
/// Register shell completions for this program
#[command(hide = true)]
Expand Down Expand Up @@ -173,6 +174,7 @@ impl CompleteCommand {
/// ```
#[derive(clap::Args, Clone, Debug)]
#[command(about = None, long_about = None)]
#[cfg(feature = "unstable-command")]
pub struct CompleteArgs {
/// Specify shell to complete for
#[arg(value_name = "NAME")]
Expand Down Expand Up @@ -229,15 +231,16 @@ impl CompleteArgs {
/// This will generally be called by [`CompleteCommand`] or [`CompleteArgs`].
///
/// This handles adapting between the shell and [`completer`][crate::dynamic::complete()].
/// A `ShellCompleter` can choose how much of that lives within the registration script and or
/// lives in [`ShellCompleter::write_complete`].
pub trait ShellCompleter {
/// A `CommandCompleter` can choose how much of that lives within the registration script and or
/// lives in [`CommandCompleter::write_complete`].
#[cfg(feature = "unstable-command")]
pub trait CommandCompleter {
/// The recommended file name for the registration code
fn file_name(&self, name: &str) -> String;
/// Register for completions
///
/// Write the `buf` the logic needed for calling into `<cmd> complete`, passing needed
/// arguments to [`ShellCompleter::write_complete`] through the environment.
/// arguments to [`CommandCompleter::write_complete`] through the environment.
fn write_registration(
&self,
name: &str,
Expand All @@ -247,7 +250,7 @@ pub trait ShellCompleter {
) -> Result<(), std::io::Error>;
/// Complete the given command
///
/// Adapt information from arguments and [`ShellCompleter::write_registration`]-defined env
/// Adapt information from arguments and [`CommandCompleter::write_registration`]-defined env
/// variables to what is needed for [`completer`][crate::dynamic::complete()].
///
/// Write out the [`CompletionCandidate`][crate::dynamic::CompletionCandidate]s in a way the shell will understand.
Expand All @@ -260,7 +263,41 @@ pub trait ShellCompleter {
) -> Result<(), std::io::Error>;
}

impl ShellCompleter for super::Bash {
impl CommandCompleter for Shell {
fn file_name(&self, name: &str) -> String {
shell_completer(self).file_name(name)
}
fn write_registration(
&self,
name: &str,
bin: &str,
completer: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
shell_completer(self).write_registration(name, bin, completer, buf)
}
fn write_complete(
&self,
cmd: &mut clap::Command,
args: Vec<OsString>,
current_dir: Option<&std::path::Path>,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
shell_completer(self).write_complete(cmd, args, current_dir, buf)
}
}

fn shell_completer(shell: &Shell) -> &dyn CommandCompleter {
match shell {
Shell::Bash => &super::Bash,
Shell::Elvish => &super::Elvish,
Shell::Fish => &super::Fish,
Shell::Powershell => &super::Powershell,
Shell::Zsh => &super::Zsh,
}
}

impl CommandCompleter for super::Bash {
fn file_name(&self, name: &str) -> String {
format!("{name}.bash")
}
Expand Down Expand Up @@ -380,7 +417,7 @@ impl Default for CompType {
Self::Normal
}
}
impl ShellCompleter for super::Elvish {
impl CommandCompleter for super::Elvish {
fn file_name(&self, name: &str) -> String {
format!("{name}.elv")
}
Expand Down Expand Up @@ -436,7 +473,7 @@ set edit:completion:arg-completer[BIN] = { |@words|
}
}

impl ShellCompleter for super::Fish {
impl CommandCompleter for super::Fish {
fn file_name(&self, name: &str) -> String {
format!("{name}.fish")
}
Expand Down Expand Up @@ -481,7 +518,7 @@ impl ShellCompleter for super::Fish {
}
}

impl ShellCompleter for super::Powershell {
impl CommandCompleter for super::Powershell {
fn file_name(&self, name: &str) -> String {
format!("{name}.ps1")
}
Expand Down Expand Up @@ -547,7 +584,7 @@ Register-ArgumentCompleter -Native -CommandName {bin} -ScriptBlock {{
}
}

impl ShellCompleter for super::Zsh {
impl CommandCompleter for super::Zsh {
fn file_name(&self, name: &str) -> String {
format!("{name}.zsh")
}
Expand Down
49 changes: 7 additions & 42 deletions clap_complete/src/dynamic/shells/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Shell completion support, see [`CompleteCommand`] for more details

#[cfg(feature = "unstable-command")]
mod command;

#[cfg(feature = "unstable-command")]
pub use command::*;

use std::fmt::Display;
Expand Down Expand Up @@ -132,59 +134,22 @@ impl ValueEnum for Shell {
}
}

impl Shell {
fn completer(&self) -> &dyn ShellCompleter {
match self {
Self::Bash => &Bash,
Self::Elvish => &Elvish,
Self::Fish => &Fish,
Self::Powershell => &Powershell,
Self::Zsh => &Zsh,
}
}
}

impl ShellCompleter for Shell {
fn file_name(&self, name: &str) -> String {
self.completer().file_name(name)
}
fn write_registration(
&self,
name: &str,
bin: &str,
completer: &str,
buf: &mut dyn std::io::Write,
) -> Result<(), std::io::Error> {
self.completer()
.write_registration(name, bin, completer, buf)
}
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> {
self.completer().write_complete(cmd, args, current_dir, buf)
}
}

/// A [`ShellCompleter`] for Bash
/// Bash completion adapter
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Bash;

/// A [`ShellCompleter`] for Elvish
/// Elvish completion adapter
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Elvish;

/// A [`ShellCompleter`] for Fish
/// Fish completion adapter
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Fish;

/// A [`ShellCompleter`] for Powershell
/// Powershell completion adapter
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Powershell;

/// A [`ShellCompleter`] for zsh
/// Zsh completion adapter
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Zsh;
4 changes: 2 additions & 2 deletions clap_complete/tests/testsuite/bash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,10 @@ fn value_terminator() {
);
}

#[cfg(feature = "unstable-dynamic")]
#[cfg(feature = "unstable-command")]
#[test]
fn register_minimal() {
use clap_complete::dynamic::shells::ShellCompleter as _;
use clap_complete::dynamic::shells::CommandCompleter as _;

let name = "my-app";
let bin = name;
Expand Down
2 changes: 2 additions & 0 deletions clap_complete/tests/testsuite/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ pub(crate) fn register_example<R: completest::RuntimeBuilder>(context: &str, nam
// Unconditionally include to avoid completion file tests failing based on the how
// `cargo test` is invoked
"--features=unstable-dynamic",
"--features=unstable-command",
],
)
.unwrap();
Expand Down Expand Up @@ -379,6 +380,7 @@ where
// Unconditionally include to avoid completion file tests failing based on the how
// `cargo test` is invoked
"--features=unstable-dynamic",
"--features=unstable-command",
],
)
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions clap_complete/tests/testsuite/elvish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,14 +175,14 @@ value value
assert_data_eq!(actual, expected);
}

#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
#[test]
fn register_dynamic() {
common::register_example::<completest_pty::ElvishRuntimeBuilder>("dynamic", "exhaustive");
}

#[test]
#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
fn complete_dynamic() {
if !common::has_command("elvish") {
return;
Expand Down
4 changes: 2 additions & 2 deletions clap_complete/tests/testsuite/fish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,14 @@ bash (bash (shell)) fish (fish shell) zsh (zsh shell)"#;
assert_data_eq!(actual, expected);
}

#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
#[test]
fn register_dynamic() {
common::register_example::<completest_pty::FishRuntimeBuilder>("dynamic", "exhaustive");
}

#[test]
#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
fn complete_dynamic() {
if !common::has_command("fish") {
return;
Expand Down
4 changes: 2 additions & 2 deletions clap_complete/tests/testsuite/zsh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,14 +163,14 @@ pacman action alias value quote hint last --
assert_data_eq!(actual, expected);
}

#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
#[test]
fn register_dynamic() {
common::register_example::<completest_pty::ZshRuntimeBuilder>("dynamic", "exhaustive");
}

#[test]
#[cfg(all(unix, feature = "unstable-dynamic"))]
#[cfg(all(unix, feature = "unstable-command"))]
fn complete_dynamic() {
if !common::has_command("zsh") {
return;
Expand Down
Loading