summaryrefslogtreecommitdiffstats
path: root/vendor/clap_complete/src/dynamic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap_complete/src/dynamic.rs')
-rw-r--r--vendor/clap_complete/src/dynamic.rs549
1 files changed, 0 insertions, 549 deletions
diff --git a/vendor/clap_complete/src/dynamic.rs b/vendor/clap_complete/src/dynamic.rs
deleted file mode 100644
index f25b4a48d..000000000
--- a/vendor/clap_complete/src/dynamic.rs
+++ /dev/null
@@ -1,549 +0,0 @@
-//! Complete commands within shells
-
-/// Complete commands within bash
-pub mod bash {
- use std::ffi::OsStr;
- use std::ffi::OsString;
- use std::io::Write;
-
- use clap_lex::OsStrExt as _;
- use unicode_xid::UnicodeXID;
-
- #[derive(clap::Subcommand)]
- #[command(hide = true)]
- #[allow(missing_docs)]
- #[derive(Clone, Debug)]
- pub enum CompleteCommand {
- /// Register shell completions for this program
- Complete(CompleteArgs),
- }
-
- #[derive(clap::Args)]
- #[command(group = clap::ArgGroup::new("complete").multiple(true).conflicts_with("register"))]
- #[allow(missing_docs)]
- #[derive(Clone, Debug)]
- pub struct CompleteArgs {
- /// Path to write completion-registration to
- #[arg(long, required = true)]
- register: Option<std::path::PathBuf>,
-
- #[arg(
- long,
- required = true,
- value_name = "COMP_CWORD",
- hide_short_help = true,
- group = "complete"
- )]
- index: Option<usize>,
-
- #[arg(long, hide_short_help = true, group = "complete")]
- ifs: Option<String>,
-
- #[arg(
- long = "type",
- required = true,
- hide_short_help = true,
- group = "complete"
- )]
- comp_type: Option<CompType>,
-
- #[arg(long, hide_short_help = true, group = "complete")]
- space: bool,
-
- #[arg(
- long,
- conflicts_with = "space",
- hide_short_help = true,
- group = "complete"
- )]
- no_space: bool,
-
- #[arg(raw = true, hide_short_help = true, group = "complete")]
- comp_words: Vec<OsString>,
- }
-
- impl CompleteCommand {
- /// Process the completion request
- pub fn complete(&self, cmd: &mut clap::Command) -> std::convert::Infallible {
- self.try_complete(cmd).unwrap_or_else(|e| e.exit());
- std::process::exit(0)
- }
-
- /// Process the completion request
- pub fn try_complete(&self, cmd: &mut clap::Command) -> clap::error::Result<()> {
- debug!("CompleteCommand::try_complete: {self:?}");
- let CompleteCommand::Complete(args) = self;
- if let Some(out_path) = args.register.as_deref() {
- let mut buf = Vec::new();
- let name = cmd.get_name();
- let bin = cmd.get_bin_name().unwrap_or_else(|| cmd.get_name());
- register(name, [bin], bin, &Behavior::default(), &mut buf)?;
- if out_path == std::path::Path::new("-") {
- std::io::stdout().write_all(&buf)?;
- } else if out_path.is_dir() {
- let out_path = out_path.join(file_name(name));
- std::fs::write(out_path, buf)?;
- } else {
- std::fs::write(out_path, buf)?;
- }
- } else {
- let index = args.index.unwrap_or_default();
- let comp_type = args.comp_type.unwrap_or_default();
- let space = match (args.space, args.no_space) {
- (true, false) => Some(true),
- (false, true) => Some(false),
- (true, true) => {
- unreachable!("`--space` and `--no-space` set, clap should prevent this")
- }
- (false, false) => None,
- }
- .unwrap();
- let current_dir = std::env::current_dir().ok();
- let completions = complete(
- cmd,
- args.comp_words.clone(),
- index,
- comp_type,
- space,
- current_dir.as_deref(),
- )?;
-
- let mut buf = Vec::new();
- for (i, completion) in completions.iter().enumerate() {
- if i != 0 {
- write!(&mut buf, "{}", args.ifs.as_deref().unwrap_or("\n"))?;
- }
- write!(&mut buf, "{}", completion.to_string_lossy())?;
- }
- std::io::stdout().write_all(&buf)?;
- }
-
- Ok(())
- }
- }
-
- /// The recommended file name for the registration code
- pub fn file_name(name: &str) -> String {
- format!("{name}.bash")
- }
-
- /// Define the completion behavior
- pub enum Behavior {
- /// Bare bones behavior
- Minimal,
- /// Fallback to readline behavior when no matches are generated
- Readline,
- /// Customize bash's completion behavior
- Custom(String),
- }
-
- impl Default for Behavior {
- fn default() -> Self {
- Self::Readline
- }
- }
-
- /// Generate code to register the dynamic completion
- pub fn register(
- name: &str,
- executables: impl IntoIterator<Item = impl AsRef<str>>,
- completer: &str,
- behavior: &Behavior,
- buf: &mut dyn Write,
- ) -> Result<(), std::io::Error> {
- let escaped_name = name.replace('-', "_");
- debug_assert!(
- escaped_name.chars().all(|c| c.is_xid_continue()),
- "`name` must be an identifier, got `{escaped_name}`"
- );
- let mut upper_name = escaped_name.clone();
- upper_name.make_ascii_uppercase();
-
- let executables = executables
- .into_iter()
- .map(|s| shlex::quote(s.as_ref()).into_owned())
- .collect::<Vec<_>>()
- .join(" ");
-
- let options = match behavior {
- Behavior::Minimal => "-o nospace -o bashdefault",
- Behavior::Readline => "-o nospace -o default -o bashdefault",
- Behavior::Custom(c) => c.as_str(),
- };
-
- let completer = shlex::quote(completer);
-
- let script = r#"
-_clap_complete_NAME() {
- local IFS=$'\013'
- local SUPPRESS_SPACE=0
- if compopt +o nospace 2> /dev/null; then
- SUPPRESS_SPACE=1
- fi
- if [[ ${SUPPRESS_SPACE} == 1 ]]; then
- SPACE_ARG="--no-space"
- else
- SPACE_ARG="--space"
- fi
- COMPREPLY=( $("COMPLETER" complete --index ${COMP_CWORD} --type ${COMP_TYPE} ${SPACE_ARG} --ifs="$IFS" -- "${COMP_WORDS[@]}") )
- if [[ $? != 0 ]]; then
- unset COMPREPLY
- elif [[ $SUPPRESS_SPACE == 1 ]] && [[ "${COMPREPLY-}" =~ [=/:]$ ]]; then
- compopt -o nospace
- fi
-}
-complete OPTIONS -F _clap_complete_NAME EXECUTABLES
-"#
- .replace("NAME", &escaped_name)
- .replace("EXECUTABLES", &executables)
- .replace("OPTIONS", options)
- .replace("COMPLETER", &completer)
- .replace("UPPER", &upper_name);
-
- writeln!(buf, "{script}")?;
- Ok(())
- }
-
- /// Type of completion attempted that caused a completion function to be called
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- #[non_exhaustive]
- pub enum CompType {
- /// Normal completion
- Normal,
- /// List completions after successive tabs
- Successive,
- /// List alternatives on partial word completion
- Alternatives,
- /// List completions if the word is not unmodified
- Unmodified,
- /// Menu completion
- Menu,
- }
-
- impl clap::ValueEnum for CompType {
- fn value_variants<'a>() -> &'a [Self] {
- &[
- Self::Normal,
- Self::Successive,
- Self::Alternatives,
- Self::Unmodified,
- Self::Menu,
- ]
- }
- fn to_possible_value(&self) -> ::std::option::Option<clap::builder::PossibleValue> {
- match self {
- Self::Normal => {
- let value = "9";
- debug_assert_eq!(b'\t'.to_string(), value);
- Some(
- clap::builder::PossibleValue::new(value)
- .alias("normal")
- .help("Normal completion"),
- )
- }
- Self::Successive => {
- let value = "63";
- debug_assert_eq!(b'?'.to_string(), value);
- Some(
- clap::builder::PossibleValue::new(value)
- .alias("successive")
- .help("List completions after successive tabs"),
- )
- }
- Self::Alternatives => {
- let value = "33";
- debug_assert_eq!(b'!'.to_string(), value);
- Some(
- clap::builder::PossibleValue::new(value)
- .alias("alternatives")
- .help("List alternatives on partial word completion"),
- )
- }
- Self::Unmodified => {
- let value = "64";
- debug_assert_eq!(b'@'.to_string(), value);
- Some(
- clap::builder::PossibleValue::new(value)
- .alias("unmodified")
- .help("List completions if the word is not unmodified"),
- )
- }
- Self::Menu => {
- let value = "37";
- debug_assert_eq!(b'%'.to_string(), value);
- Some(
- clap::builder::PossibleValue::new(value)
- .alias("menu")
- .help("Menu completion"),
- )
- }
- }
- }
- }
-
- impl Default for CompType {
- fn default() -> Self {
- Self::Normal
- }
- }
-
- /// Complete the command specified
- pub fn complete(
- cmd: &mut clap::Command,
- args: Vec<std::ffi::OsString>,
- arg_index: usize,
- _comp_type: CompType,
- _trailing_space: bool,
- current_dir: Option<&std::path::Path>,
- ) -> Result<Vec<std::ffi::OsString>, std::io::Error> {
- cmd.build();
-
- let raw_args = clap_lex::RawArgs::new(args.into_iter());
- let mut cursor = raw_args.cursor();
- let mut target_cursor = raw_args.cursor();
- raw_args.seek(
- &mut target_cursor,
- clap_lex::SeekFrom::Start(arg_index as u64),
- );
- // As we loop, `cursor` will always be pointing to the next item
- raw_args.next_os(&mut target_cursor);
-
- // TODO: Multicall support
- if !cmd.is_no_binary_name_set() {
- raw_args.next_os(&mut cursor);
- }
-
- let mut current_cmd = &*cmd;
- let mut pos_index = 1;
- let mut is_escaped = false;
- while let Some(arg) = raw_args.next(&mut cursor) {
- if cursor == target_cursor {
- return complete_arg(&arg, current_cmd, current_dir, pos_index, is_escaped);
- }
-
- debug!("complete::next: Begin parsing '{:?}'", arg.to_value_os(),);
-
- if let Ok(value) = arg.to_value() {
- if let Some(next_cmd) = current_cmd.find_subcommand(value) {
- current_cmd = next_cmd;
- pos_index = 0;
- continue;
- }
- }
-
- if is_escaped {
- pos_index += 1;
- } else if arg.is_escape() {
- is_escaped = true;
- } else if let Some(_long) = arg.to_long() {
- } else if let Some(_short) = arg.to_short() {
- } else {
- pos_index += 1;
- }
- }
-
- Err(std::io::Error::new(
- std::io::ErrorKind::Other,
- "No completion generated",
- ))
- }
-
- fn complete_arg(
- arg: &clap_lex::ParsedArg<'_>,
- cmd: &clap::Command,
- current_dir: Option<&std::path::Path>,
- pos_index: usize,
- is_escaped: bool,
- ) -> Result<Vec<std::ffi::OsString>, std::io::Error> {
- debug!(
- "complete_arg: arg={:?}, cmd={:?}, current_dir={:?}, pos_index={}, is_escaped={}",
- arg,
- cmd.get_name(),
- current_dir,
- pos_index,
- is_escaped
- );
- let mut completions = Vec::new();
-
- if !is_escaped {
- if let Some((flag, value)) = arg.to_long() {
- if let Ok(flag) = flag {
- if let Some(value) = value {
- if let Some(arg) = cmd.get_arguments().find(|a| a.get_long() == Some(flag))
- {
- completions.extend(
- complete_arg_value(value.to_str().ok_or(value), arg, current_dir)
- .into_iter()
- .map(|os| {
- // HACK: Need better `OsStr` manipulation
- format!("--{}={}", flag, os.to_string_lossy()).into()
- }),
- )
- }
- } else {
- completions.extend(
- crate::generator::utils::longs_and_visible_aliases(cmd)
- .into_iter()
- .filter_map(|f| {
- f.starts_with(flag).then(|| format!("--{f}").into())
- }),
- );
- }
- }
- } else if arg.is_escape() || arg.is_stdio() || arg.is_empty() {
- // HACK: Assuming knowledge of is_escape / is_stdio
- completions.extend(
- crate::generator::utils::longs_and_visible_aliases(cmd)
- .into_iter()
- .map(|f| format!("--{f}").into()),
- );
- }
-
- if arg.is_empty() || arg.is_stdio() || arg.is_short() {
- // HACK: Assuming knowledge of is_stdio
- completions.extend(
- crate::generator::utils::shorts_and_visible_aliases(cmd)
- .into_iter()
- // HACK: Need better `OsStr` manipulation
- .map(|f| format!("{}{}", arg.to_value_os().to_string_lossy(), f).into()),
- );
- }
- }
-
- if let Some(positional) = cmd
- .get_positionals()
- .find(|p| p.get_index() == Some(pos_index))
- {
- completions.extend(complete_arg_value(arg.to_value(), positional, current_dir));
- }
-
- if let Ok(value) = arg.to_value() {
- completions.extend(complete_subcommand(value, cmd));
- }
-
- Ok(completions)
- }
-
- fn complete_arg_value(
- value: Result<&str, &OsStr>,
- arg: &clap::Arg,
- current_dir: Option<&std::path::Path>,
- ) -> Vec<OsString> {
- let mut values = Vec::new();
- debug!("complete_arg_value: arg={arg:?}, value={value:?}");
-
- if let Some(possible_values) = crate::generator::utils::possible_values(arg) {
- if let Ok(value) = value {
- values.extend(possible_values.into_iter().filter_map(|p| {
- let name = p.get_name();
- name.starts_with(value).then(|| name.into())
- }));
- }
- } else {
- let value_os = match value {
- Ok(value) => OsStr::new(value),
- Err(value_os) => value_os,
- };
- match arg.get_value_hint() {
- clap::ValueHint::Other => {
- // Should not complete
- }
- clap::ValueHint::Unknown | clap::ValueHint::AnyPath => {
- values.extend(complete_path(value_os, current_dir, |_| true));
- }
- clap::ValueHint::FilePath => {
- values.extend(complete_path(value_os, current_dir, |p| p.is_file()));
- }
- clap::ValueHint::DirPath => {
- values.extend(complete_path(value_os, current_dir, |p| p.is_dir()));
- }
- clap::ValueHint::ExecutablePath => {
- use is_executable::IsExecutable;
- values.extend(complete_path(value_os, current_dir, |p| p.is_executable()));
- }
- clap::ValueHint::CommandName
- | clap::ValueHint::CommandString
- | clap::ValueHint::CommandWithArguments
- | clap::ValueHint::Username
- | clap::ValueHint::Hostname
- | clap::ValueHint::Url
- | clap::ValueHint::EmailAddress => {
- // No completion implementation
- }
- _ => {
- // Safe-ish fallback
- values.extend(complete_path(value_os, current_dir, |_| true));
- }
- }
- values.sort();
- }
-
- values
- }
-
- fn complete_path(
- value_os: &OsStr,
- current_dir: Option<&std::path::Path>,
- is_wanted: impl Fn(&std::path::Path) -> bool,
- ) -> Vec<OsString> {
- let mut completions = Vec::new();
-
- let current_dir = match current_dir {
- Some(current_dir) => current_dir,
- None => {
- // Can't complete without a `current_dir`
- return Vec::new();
- }
- };
- let (existing, prefix) = value_os
- .split_once("\\")
- .unwrap_or((OsStr::new(""), value_os));
- let root = current_dir.join(existing);
- debug!("complete_path: root={root:?}, prefix={prefix:?}");
- let prefix = prefix.to_string_lossy();
-
- for entry in std::fs::read_dir(&root)
- .ok()
- .into_iter()
- .flatten()
- .filter_map(Result::ok)
- {
- let raw_file_name = OsString::from(entry.file_name());
- if !raw_file_name.starts_with(&prefix) {
- continue;
- }
-
- if entry.metadata().map(|m| m.is_dir()).unwrap_or(false) {
- let path = entry.path();
- let mut suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
- suggestion.push(""); // Ensure trailing `/`
- completions.push(suggestion.as_os_str().to_owned());
- } else {
- let path = entry.path();
- if is_wanted(&path) {
- let suggestion = pathdiff::diff_paths(&path, current_dir).unwrap_or(path);
- completions.push(suggestion.as_os_str().to_owned());
- }
- }
- }
-
- completions
- }
-
- fn complete_subcommand(value: &str, cmd: &clap::Command) -> Vec<OsString> {
- debug!(
- "complete_subcommand: cmd={:?}, value={:?}",
- cmd.get_name(),
- value
- );
-
- let mut scs = crate::generator::utils::all_subcommands(cmd)
- .into_iter()
- .filter(|x| x.0.starts_with(value))
- .map(|x| OsString::from(&x.0))
- .collect::<Vec<_>>();
- scs.sort();
- scs.dedup();
- scs
- }
-}