diff options
Diffstat (limited to 'vendor/clap/src/output')
-rw-r--r-- | vendor/clap/src/output/fmt.rs | 158 | ||||
-rw-r--r-- | vendor/clap/src/output/help.rs | 1176 | ||||
-rw-r--r-- | vendor/clap/src/output/mod.rs | 7 | ||||
-rw-r--r-- | vendor/clap/src/output/usage.rs | 449 |
4 files changed, 0 insertions, 1790 deletions
diff --git a/vendor/clap/src/output/fmt.rs b/vendor/clap/src/output/fmt.rs deleted file mode 100644 index dc1f46e08..000000000 --- a/vendor/clap/src/output/fmt.rs +++ /dev/null @@ -1,158 +0,0 @@ -use crate::util::color::ColorChoice; - -use std::{ - fmt::{self, Display, Formatter}, - io::{self, Write}, -}; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub(crate) enum Stream { - Stdout, - Stderr, -} - -#[derive(Clone, Debug)] -pub(crate) struct Colorizer { - stream: Stream, - #[allow(unused)] - color_when: ColorChoice, - pieces: Vec<(String, Style)>, -} - -impl Colorizer { - #[inline(never)] - pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self { - Colorizer { - stream, - color_when, - pieces: vec![], - } - } - - #[inline(never)] - pub(crate) fn good(&mut self, msg: impl Into<String>) { - self.pieces.push((msg.into(), Style::Good)); - } - - #[inline(never)] - pub(crate) fn warning(&mut self, msg: impl Into<String>) { - self.pieces.push((msg.into(), Style::Warning)); - } - - #[inline(never)] - pub(crate) fn error(&mut self, msg: impl Into<String>) { - self.pieces.push((msg.into(), Style::Error)); - } - - #[inline(never)] - #[allow(dead_code)] - pub(crate) fn hint(&mut self, msg: impl Into<String>) { - self.pieces.push((msg.into(), Style::Hint)); - } - - #[inline(never)] - pub(crate) fn none(&mut self, msg: impl Into<String>) { - self.pieces.push((msg.into(), Style::Default)); - } -} - -/// Printing methods. -impl Colorizer { - #[cfg(feature = "color")] - pub(crate) fn print(&self) -> io::Result<()> { - use termcolor::{BufferWriter, ColorChoice as DepColorChoice, ColorSpec, WriteColor}; - - let color_when = match self.color_when { - ColorChoice::Always => DepColorChoice::Always, - ColorChoice::Auto if is_a_tty(self.stream) => DepColorChoice::Auto, - _ => DepColorChoice::Never, - }; - - let writer = match self.stream { - Stream::Stderr => BufferWriter::stderr(color_when), - Stream::Stdout => BufferWriter::stdout(color_when), - }; - - let mut buffer = writer.buffer(); - - for piece in &self.pieces { - let mut color = ColorSpec::new(); - match piece.1 { - Style::Good => { - color.set_fg(Some(termcolor::Color::Green)); - } - Style::Warning => { - color.set_fg(Some(termcolor::Color::Yellow)); - } - Style::Error => { - color.set_fg(Some(termcolor::Color::Red)); - color.set_bold(true); - } - Style::Hint => { - color.set_dimmed(true); - } - Style::Default => {} - } - - buffer.set_color(&color)?; - buffer.write_all(piece.0.as_bytes())?; - buffer.reset()?; - } - - writer.print(&buffer) - } - - #[cfg(not(feature = "color"))] - pub(crate) fn print(&self) -> io::Result<()> { - // [e]println can't be used here because it panics - // if something went wrong. We don't want that. - match self.stream { - Stream::Stdout => { - let stdout = std::io::stdout(); - let mut stdout = stdout.lock(); - write!(stdout, "{}", self) - } - Stream::Stderr => { - let stderr = std::io::stderr(); - let mut stderr = stderr.lock(); - write!(stderr, "{}", self) - } - } - } -} - -/// Color-unaware printing. Never uses coloring. -impl Display for Colorizer { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - for piece in &self.pieces { - Display::fmt(&piece.0, f)?; - } - - Ok(()) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Style { - Good, - Warning, - Error, - Hint, - Default, -} - -impl Default for Style { - fn default() -> Self { - Self::Default - } -} - -#[cfg(feature = "color")] -fn is_a_tty(stream: Stream) -> bool { - let stream = match stream { - Stream::Stdout => atty::Stream::Stdout, - Stream::Stderr => atty::Stream::Stderr, - }; - - atty::is(stream) -} diff --git a/vendor/clap/src/output/help.rs b/vendor/clap/src/output/help.rs deleted file mode 100644 index eb53bfa54..000000000 --- a/vendor/clap/src/output/help.rs +++ /dev/null @@ -1,1176 +0,0 @@ -// Std -use std::borrow::Cow; -use std::cmp; -use std::fmt::Write as _; -use std::io::{self, Write}; -use std::usize; - -// Internal -use crate::builder::{display_arg_val, Arg, Command}; -use crate::output::{fmt::Colorizer, Usage}; -use crate::PossibleValue; - -// Third party -use indexmap::IndexSet; -use textwrap::core::display_width; - -/// `clap` Help Writer. -/// -/// Wraps a writer stream providing different methods to generate help for `clap` objects. -pub(crate) struct Help<'help, 'cmd, 'writer> { - writer: HelpWriter<'writer>, - cmd: &'cmd Command<'help>, - usage: &'cmd Usage<'help, 'cmd>, - next_line_help: bool, - term_w: usize, - use_long: bool, -} - -// Public Functions -impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> { - #[cfg(feature = "unstable-v4")] - const DEFAULT_TEMPLATE: &'static str = "\ - {before-help}{name} {version}\n\ - {author-with-newline}{about-with-newline}\n\ - {usage-heading}\n {usage}\n\ - \n\ - {all-args}{after-help}\ - "; - #[cfg(not(feature = "unstable-v4"))] - const DEFAULT_TEMPLATE: &'static str = "\ - {before-help}{bin} {version}\n\ - {author-with-newline}{about-with-newline}\n\ - {usage-heading}\n {usage}\n\ - \n\ - {all-args}{after-help}\ - "; - - #[cfg(feature = "unstable-v4")] - const DEFAULT_NO_ARGS_TEMPLATE: &'static str = "\ - {before-help}{name} {version}\n\ - {author-with-newline}{about-with-newline}\n\ - {usage-heading}\n {usage}{after-help}\ - "; - #[cfg(not(feature = "unstable-v4"))] - const DEFAULT_NO_ARGS_TEMPLATE: &'static str = "\ - {before-help}{bin} {version}\n\ - {author-with-newline}{about-with-newline}\n\ - {usage-heading}\n {usage}{after-help}\ - "; - - /// Create a new `Help` instance. - pub(crate) fn new( - writer: HelpWriter<'writer>, - cmd: &'cmd Command<'help>, - usage: &'cmd Usage<'help, 'cmd>, - use_long: bool, - ) -> Self { - debug!("Help::new cmd={}, use_long={}", cmd.get_name(), use_long); - let term_w = match cmd.get_term_width() { - Some(0) => usize::MAX, - Some(w) => w, - None => cmp::min( - dimensions().map_or(100, |(w, _)| w), - match cmd.get_max_term_width() { - None | Some(0) => usize::MAX, - Some(mw) => mw, - }, - ), - }; - let next_line_help = cmd.is_next_line_help_set(); - - Help { - writer, - cmd, - usage, - next_line_help, - term_w, - use_long, - } - } - - /// Writes the parser help to the wrapped stream. - pub(crate) fn write_help(&mut self) -> io::Result<()> { - debug!("Help::write_help"); - - if let Some(h) = self.cmd.get_override_help() { - self.none(h)?; - } else if let Some(tmpl) = self.cmd.get_help_template() { - self.write_templated_help(tmpl)?; - } else { - let pos = self - .cmd - .get_positionals() - .any(|arg| should_show_arg(self.use_long, arg)); - let non_pos = self - .cmd - .get_non_positionals() - .any(|arg| should_show_arg(self.use_long, arg)); - let subcmds = self.cmd.has_visible_subcommands(); - - if non_pos || pos || subcmds { - self.write_templated_help(Self::DEFAULT_TEMPLATE)?; - } else { - self.write_templated_help(Self::DEFAULT_NO_ARGS_TEMPLATE)?; - } - } - - self.none("\n")?; - - Ok(()) - } -} - -macro_rules! write_method { - ($_self:ident, $msg:ident, $meth:ident) => { - match &mut $_self.writer { - HelpWriter::Buffer(c) => { - c.$meth(($msg).into()); - Ok(()) - } - HelpWriter::Normal(w) => w.write_all($msg.as_ref()), - } - }; -} - -// Methods to write Arg help. -impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> { - #[inline(never)] - fn good<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> { - write_method!(self, msg, good) - } - - #[inline(never)] - fn warning<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> { - write_method!(self, msg, warning) - } - - #[inline(never)] - fn none<T: Into<String> + AsRef<[u8]>>(&mut self, msg: T) -> io::Result<()> { - write_method!(self, msg, none) - } - - #[inline(never)] - fn spaces(&mut self, n: usize) -> io::Result<()> { - // A string with 64 consecutive spaces. - const SHORT_SPACE: &str = - " "; - if let Some(short) = SHORT_SPACE.get(..n) { - self.none(short) - } else { - self.none(" ".repeat(n)) - } - } - - /// Writes help for each argument in the order they were declared to the wrapped stream. - fn write_args_unsorted(&mut self, args: &[&Arg<'help>]) -> io::Result<()> { - debug!("Help::write_args_unsorted"); - // The shortest an arg can legally be is 2 (i.e. '-x') - let mut longest = 2; - let mut arg_v = Vec::with_capacity(10); - - for &arg in args - .iter() - .filter(|arg| should_show_arg(self.use_long, *arg)) - { - if arg.longest_filter() { - longest = longest.max(display_width(&arg.to_string())); - debug!( - "Help::write_args_unsorted: arg={:?} longest={}", - arg.get_id(), - longest - ); - } - arg_v.push(arg) - } - - let next_line_help = self.will_args_wrap(args, longest); - - let argc = arg_v.len(); - for (i, arg) in arg_v.iter().enumerate() { - self.write_arg(arg, i + 1 == argc, next_line_help, longest)?; - } - Ok(()) - } - - /// Sorts arguments by length and display order and write their help to the wrapped stream. - fn write_args(&mut self, args: &[&Arg<'help>], _category: &str) -> io::Result<()> { - debug!("Help::write_args {}", _category); - // The shortest an arg can legally be is 2 (i.e. '-x') - let mut longest = 2; - let mut ord_v = Vec::new(); - - // Determine the longest - for &arg in args.iter().filter(|arg| { - // If it's NextLineHelp we don't care to compute how long it is because it may be - // NextLineHelp on purpose simply *because* it's so long and would throw off all other - // args alignment - should_show_arg(self.use_long, *arg) - }) { - if arg.longest_filter() { - longest = longest.max(display_width(&arg.to_string())); - debug!( - "Help::write_args: arg={:?} longest={}", - arg.get_id(), - longest - ); - } - - // Formatting key like this to ensure that: - // 1. Argument has long flags are printed just after short flags. - // 2. For two args both have short flags like `-c` and `-C`, the - // `-C` arg is printed just after the `-c` arg - // 3. For args without short or long flag, print them at last(sorted - // by arg name). - // Example order: -a, -b, -B, -s, --select-file, --select-folder, -x - - let key = if let Some(x) = arg.short { - let mut s = x.to_ascii_lowercase().to_string(); - s.push(if x.is_ascii_lowercase() { '0' } else { '1' }); - s - } else if let Some(x) = arg.long { - x.to_string() - } else { - let mut s = '{'.to_string(); - s.push_str(arg.name); - s - }; - ord_v.push((arg.get_display_order(), key, arg)); - } - ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1))); - - let next_line_help = self.will_args_wrap(args, longest); - - for (i, (_, _, arg)) in ord_v.iter().enumerate() { - let last_arg = i + 1 == ord_v.len(); - self.write_arg(arg, last_arg, next_line_help, longest)?; - } - Ok(()) - } - - /// Writes help for an argument to the wrapped stream. - fn write_arg( - &mut self, - arg: &Arg<'help>, - last_arg: bool, - next_line_help: bool, - longest: usize, - ) -> io::Result<()> { - let spec_vals = &self.spec_vals(arg); - - self.short(arg)?; - self.long(arg)?; - self.val(arg)?; - self.align_to_about(arg, next_line_help, longest)?; - - let about = if self.use_long { - arg.long_help.or(arg.help).unwrap_or("") - } else { - arg.help.or(arg.long_help).unwrap_or("") - }; - - self.help(Some(arg), about, spec_vals, next_line_help, longest)?; - - if !last_arg { - self.none("\n")?; - if next_line_help { - self.none("\n")?; - } - } - Ok(()) - } - - /// Writes argument's short command to the wrapped stream. - fn short(&mut self, arg: &Arg<'help>) -> io::Result<()> { - debug!("Help::short"); - - self.none(TAB)?; - - if let Some(s) = arg.short { - self.good(format!("-{}", s)) - } else if !arg.is_positional() { - self.none(TAB) - } else { - Ok(()) - } - } - - /// Writes argument's long command to the wrapped stream. - fn long(&mut self, arg: &Arg<'help>) -> io::Result<()> { - debug!("Help::long"); - if let Some(long) = arg.long { - if arg.short.is_some() { - self.none(", ")?; - } - self.good(format!("--{}", long))?; - } - Ok(()) - } - - /// Writes argument's possible values to the wrapped stream. - fn val(&mut self, arg: &Arg<'help>) -> io::Result<()> { - debug!("Help::val: arg={}", arg.name); - let mut need_closing_bracket = false; - if arg.is_takes_value_set() && !arg.is_positional() { - let is_optional_val = arg.min_vals == Some(0); - let sep = if arg.is_require_equals_set() { - if is_optional_val { - need_closing_bracket = true; - "[=" - } else { - "=" - } - } else if is_optional_val { - need_closing_bracket = true; - " [" - } else { - " " - }; - self.none(sep)?; - } - - if arg.is_takes_value_set() || arg.is_positional() { - display_arg_val( - arg, - |s, good| if good { self.good(s) } else { self.none(s) }, - )?; - } - - if need_closing_bracket { - self.none("]")?; - } - Ok(()) - } - - /// Write alignment padding between arg's switches/values and its about message. - fn align_to_about( - &mut self, - arg: &Arg<'help>, - next_line_help: bool, - longest: usize, - ) -> io::Result<()> { - debug!( - "Help::align_to_about: arg={}, next_line_help={}, longest={}", - arg.name, next_line_help, longest - ); - if self.use_long || next_line_help { - // long help prints messages on the next line so it doesn't need to align text - debug!("Help::align_to_about: printing long help so skip alignment"); - } else if !arg.is_positional() { - let self_len = display_width(&arg.to_string()); - // Since we're writing spaces from the tab point we first need to know if we - // had a long and short, or just short - let padding = if arg.long.is_some() { - // Only account 4 after the val - 4 - } else { - // Only account for ', --' + 4 after the val - 8 - }; - let spcs = longest + padding - self_len; - debug!( - "Help::align_to_about: positional=false arg_len={}, spaces={}", - self_len, spcs - ); - - self.spaces(spcs)?; - } else { - let self_len = display_width(&arg.to_string()); - let padding = 4; - let spcs = longest + padding - self_len; - debug!( - "Help::align_to_about: positional=true arg_len={}, spaces={}", - self_len, spcs - ); - - self.spaces(spcs)?; - } - Ok(()) - } - - fn write_before_help(&mut self) -> io::Result<()> { - debug!("Help::write_before_help"); - let before_help = if self.use_long { - self.cmd - .get_before_long_help() - .or_else(|| self.cmd.get_before_help()) - } else { - self.cmd.get_before_help() - }; - if let Some(output) = before_help { - self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?; - self.none("\n\n")?; - } - Ok(()) - } - - fn write_after_help(&mut self) -> io::Result<()> { - debug!("Help::write_after_help"); - let after_help = if self.use_long { - self.cmd - .get_after_long_help() - .or_else(|| self.cmd.get_after_help()) - } else { - self.cmd.get_after_help() - }; - if let Some(output) = after_help { - self.none("\n\n")?; - self.none(text_wrapper(&output.replace("{n}", "\n"), self.term_w))?; - } - Ok(()) - } - - /// Writes argument's help to the wrapped stream. - fn help( - &mut self, - arg: Option<&Arg<'help>>, - about: &str, - spec_vals: &str, - next_line_help: bool, - longest: usize, - ) -> io::Result<()> { - debug!("Help::help"); - let mut help = String::from(about) + spec_vals; - debug!("Help::help: Next Line...{:?}", next_line_help); - - let spaces = if next_line_help { - 12 // "tab" * 3 - } else { - longest + 12 - }; - - let too_long = spaces + display_width(&help) >= self.term_w; - - // Is help on next line, if so then indent - if next_line_help { - self.none(format!("\n{}{}{}", TAB, TAB, TAB))?; - } - - debug!("Help::help: Too long..."); - if too_long && spaces <= self.term_w || help.contains("{n}") { - debug!("Yes"); - debug!("Help::help: help...{}", help); - debug!("Help::help: help width...{}", display_width(&help)); - // Determine how many newlines we need to insert - let avail_chars = self.term_w - spaces; - debug!("Help::help: Usable space...{}", avail_chars); - help = text_wrapper(&help.replace("{n}", "\n"), avail_chars); - } else { - debug!("No"); - } - if let Some(part) = help.lines().next() { - self.none(part)?; - } - - // indent of help - let spaces = if next_line_help { - TAB_WIDTH * 3 - } else if let Some(true) = arg.map(|a| a.is_positional()) { - longest + TAB_WIDTH * 2 - } else { - longest + TAB_WIDTH * 3 - }; - - for part in help.lines().skip(1) { - self.none("\n")?; - self.spaces(spaces)?; - self.none(part)?; - } - - #[cfg(feature = "unstable-v4")] - if let Some(arg) = arg { - const DASH_SPACE: usize = "- ".len(); - const COLON_SPACE: usize = ": ".len(); - let possible_vals = arg.get_possible_values2(); - if self.use_long - && !arg.is_hide_possible_values_set() - && possible_vals.iter().any(PossibleValue::should_show_help) - { - debug!("Help::help: Found possible vals...{:?}", possible_vals); - if !help.is_empty() { - self.none("\n\n")?; - self.spaces(spaces)?; - } - self.none("Possible values:")?; - let longest = possible_vals - .iter() - .filter_map(|f| f.get_visible_quoted_name().map(|name| display_width(&name))) - .max() - .expect("Only called with possible value"); - let help_longest = possible_vals - .iter() - .filter_map(|f| f.get_visible_help().map(display_width)) - .max() - .expect("Only called with possible value with help"); - // should new line - let taken = longest + spaces + DASH_SPACE; - - let possible_value_new_line = - self.term_w >= taken && self.term_w < taken + COLON_SPACE + help_longest; - - let spaces = spaces + TAB_WIDTH - DASH_SPACE; - let spaces_help = if possible_value_new_line { - spaces + DASH_SPACE - } else { - spaces + longest + DASH_SPACE + COLON_SPACE - }; - - for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) { - self.none("\n")?; - self.spaces(spaces)?; - self.none("- ")?; - self.good(pv.get_name())?; - if let Some(help) = pv.get_help() { - debug!("Help::help: Possible Value help"); - - if possible_value_new_line { - self.none(":\n")?; - self.spaces(spaces_help)?; - } else { - self.none(": ")?; - // To align help messages - self.spaces(longest - display_width(pv.get_name()))?; - } - - let avail_chars = if self.term_w > spaces_help { - self.term_w - spaces_help - } else { - usize::MAX - }; - - let help = text_wrapper(help, avail_chars); - let mut help = help.lines(); - - self.none(help.next().unwrap_or_default())?; - for part in help { - self.none("\n")?; - self.spaces(spaces_help)?; - self.none(part)?; - } - } - } - } - } - Ok(()) - } - - /// Will use next line help on writing args. - fn will_args_wrap(&self, args: &[&Arg<'help>], longest: usize) -> bool { - args.iter() - .filter(|arg| should_show_arg(self.use_long, *arg)) - .any(|arg| { - let spec_vals = &self.spec_vals(arg); - self.arg_next_line_help(arg, spec_vals, longest) - }) - } - - fn arg_next_line_help(&self, arg: &Arg<'help>, spec_vals: &str, longest: usize) -> bool { - if self.next_line_help || arg.is_next_line_help_set() || self.use_long { - // setting_next_line - true - } else { - // force_next_line - let h = arg.help.unwrap_or(""); - let h_w = display_width(h) + display_width(spec_vals); - let taken = longest + 12; - self.term_w >= taken - && (taken as f32 / self.term_w as f32) > 0.40 - && h_w > (self.term_w - taken) - } - } - - fn spec_vals(&self, a: &Arg) -> String { - debug!("Help::spec_vals: a={}", a); - let mut spec_vals = vec![]; - #[cfg(feature = "env")] - if let Some(ref env) = a.env { - if !a.is_hide_env_set() { - debug!( - "Help::spec_vals: Found environment variable...[{:?}:{:?}]", - env.0, env.1 - ); - let env_val = if !a.is_hide_env_values_set() { - format!( - "={}", - env.1 - .as_ref() - .map_or(Cow::Borrowed(""), |val| val.to_string_lossy()) - ) - } else { - String::new() - }; - let env_info = format!("[env: {}{}]", env.0.to_string_lossy(), env_val); - spec_vals.push(env_info); - } - } - if a.is_takes_value_set() && !a.is_hide_default_value_set() && !a.default_vals.is_empty() { - debug!( - "Help::spec_vals: Found default value...[{:?}]", - a.default_vals - ); - - let pvs = a - .default_vals - .iter() - .map(|&pvs| pvs.to_string_lossy()) - .map(|pvs| { - if pvs.contains(char::is_whitespace) { - Cow::from(format!("{:?}", pvs)) - } else { - pvs - } - }) - .collect::<Vec<_>>() - .join(" "); - - spec_vals.push(format!("[default: {}]", pvs)); - } - if !a.aliases.is_empty() { - debug!("Help::spec_vals: Found aliases...{:?}", a.aliases); - - let als = a - .aliases - .iter() - .filter(|&als| als.1) // visible - .map(|&als| als.0) // name - .collect::<Vec<_>>() - .join(", "); - - if !als.is_empty() { - spec_vals.push(format!("[aliases: {}]", als)); - } - } - - if !a.short_aliases.is_empty() { - debug!( - "Help::spec_vals: Found short aliases...{:?}", - a.short_aliases - ); - - let als = a - .short_aliases - .iter() - .filter(|&als| als.1) // visible - .map(|&als| als.0.to_string()) // name - .collect::<Vec<_>>() - .join(", "); - - if !als.is_empty() { - spec_vals.push(format!("[short aliases: {}]", als)); - } - } - - let possible_vals = a.get_possible_values2(); - if !(a.is_hide_possible_values_set() - || possible_vals.is_empty() - || cfg!(feature = "unstable-v4") - && self.use_long - && possible_vals.iter().any(PossibleValue::should_show_help)) - { - debug!("Help::spec_vals: Found possible vals...{:?}", possible_vals); - - let pvs = possible_vals - .iter() - .filter_map(PossibleValue::get_visible_quoted_name) - .collect::<Vec<_>>() - .join(", "); - - spec_vals.push(format!("[possible values: {}]", pvs)); - } - let connector = if self.use_long { "\n" } else { " " }; - let prefix = if !spec_vals.is_empty() && !a.get_help().unwrap_or("").is_empty() { - if self.use_long { - "\n\n" - } else { - " " - } - } else { - "" - }; - prefix.to_string() + &spec_vals.join(connector) - } - - fn write_about(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> { - let about = if self.use_long { - self.cmd.get_long_about().or_else(|| self.cmd.get_about()) - } else { - self.cmd.get_about() - }; - if let Some(output) = about { - if before_new_line { - self.none("\n")?; - } - self.none(text_wrapper(output, self.term_w))?; - if after_new_line { - self.none("\n")?; - } - } - Ok(()) - } - - fn write_author(&mut self, before_new_line: bool, after_new_line: bool) -> io::Result<()> { - if let Some(author) = self.cmd.get_author() { - if before_new_line { - self.none("\n")?; - } - self.none(text_wrapper(author, self.term_w))?; - if after_new_line { - self.none("\n")?; - } - } - Ok(()) - } - - fn write_version(&mut self) -> io::Result<()> { - let version = self - .cmd - .get_version() - .or_else(|| self.cmd.get_long_version()); - if let Some(output) = version { - self.none(text_wrapper(output, self.term_w))?; - } - Ok(()) - } -} - -/// Methods to write a single subcommand -impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> { - fn write_subcommand( - &mut self, - sc_str: &str, - cmd: &Command<'help>, - next_line_help: bool, - longest: usize, - ) -> io::Result<()> { - debug!("Help::write_subcommand"); - - let spec_vals = &self.sc_spec_vals(cmd); - - let about = cmd - .get_about() - .or_else(|| cmd.get_long_about()) - .unwrap_or(""); - - self.subcmd(sc_str, next_line_help, longest)?; - self.help(None, about, spec_vals, next_line_help, longest) - } - - fn sc_spec_vals(&self, a: &Command) -> String { - debug!("Help::sc_spec_vals: a={}", a.get_name()); - let mut spec_vals = vec![]; - if 0 < a.get_all_aliases().count() || 0 < a.get_all_short_flag_aliases().count() { - debug!( - "Help::spec_vals: Found aliases...{:?}", - a.get_all_aliases().collect::<Vec<_>>() - ); - debug!( - "Help::spec_vals: Found short flag aliases...{:?}", - a.get_all_short_flag_aliases().collect::<Vec<_>>() - ); - - let mut short_als = a - .get_visible_short_flag_aliases() - .map(|a| format!("-{}", a)) - .collect::<Vec<_>>(); - - let als = a.get_visible_aliases().map(|s| s.to_string()); - - short_als.extend(als); - - let all_als = short_als.join(", "); - - if !all_als.is_empty() { - spec_vals.push(format!(" [aliases: {}]", all_als)); - } - } - spec_vals.join(" ") - } - - fn subcommand_next_line_help( - &self, - cmd: &Command<'help>, - spec_vals: &str, - longest: usize, - ) -> bool { - if self.next_line_help | self.use_long { - // setting_next_line - true - } else { - // force_next_line - let h = cmd.get_about().unwrap_or(""); - let h_w = display_width(h) + display_width(spec_vals); - let taken = longest + 12; - self.term_w >= taken - && (taken as f32 / self.term_w as f32) > 0.40 - && h_w > (self.term_w - taken) - } - } - - /// Writes subcommand to the wrapped stream. - fn subcmd(&mut self, sc_str: &str, next_line_help: bool, longest: usize) -> io::Result<()> { - self.none(TAB)?; - self.good(sc_str)?; - if !next_line_help { - let width = display_width(sc_str); - self.spaces(width.max(longest + 4) - width)?; - } - Ok(()) - } -} - -// Methods to write Parser help. -impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> { - /// Writes help for all arguments (options, flags, args, subcommands) - /// including titles of a Parser Object to the wrapped stream. - pub(crate) fn write_all_args(&mut self) -> io::Result<()> { - debug!("Help::write_all_args"); - let pos = self - .cmd - .get_positionals_with_no_heading() - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::<Vec<_>>(); - let non_pos = self - .cmd - .get_non_positionals_with_no_heading() - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::<Vec<_>>(); - let subcmds = self.cmd.has_visible_subcommands(); - - let custom_headings = self - .cmd - .get_arguments() - .filter_map(|arg| arg.get_help_heading()) - .collect::<IndexSet<_>>(); - - let mut first = if !pos.is_empty() { - // Write positional args if any - self.warning("ARGS:\n")?; - self.write_args_unsorted(&pos)?; - false - } else { - true - }; - - if !non_pos.is_empty() { - if !first { - self.none("\n\n")?; - } - self.warning("OPTIONS:\n")?; - self.write_args(&non_pos, "OPTIONS")?; - first = false; - } - if !custom_headings.is_empty() { - for heading in custom_headings { - let args = self - .cmd - .get_arguments() - .filter(|a| { - if let Some(help_heading) = a.get_help_heading() { - return help_heading == heading; - } - false - }) - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::<Vec<_>>(); - - if !args.is_empty() { - if !first { - self.none("\n\n")?; - } - self.warning(format!("{}:\n", heading))?; - self.write_args(&args, heading)?; - first = false - } - } - } - - if subcmds { - if !first { - self.none("\n\n")?; - } - - self.warning( - self.cmd - .get_subcommand_help_heading() - .unwrap_or("SUBCOMMANDS"), - )?; - self.warning(":\n")?; - - self.write_subcommands(self.cmd)?; - } - - Ok(()) - } - - /// Will use next line help on writing subcommands. - fn will_subcommands_wrap<'a>( - &self, - subcommands: impl IntoIterator<Item = &'a Command<'help>>, - longest: usize, - ) -> bool - where - 'help: 'a, - { - subcommands - .into_iter() - .filter(|&subcommand| should_show_subcommand(subcommand)) - .any(|subcommand| { - let spec_vals = &self.sc_spec_vals(subcommand); - self.subcommand_next_line_help(subcommand, spec_vals, longest) - }) - } - - /// Writes help for subcommands of a Parser Object to the wrapped stream. - fn write_subcommands(&mut self, cmd: &Command<'help>) -> io::Result<()> { - debug!("Help::write_subcommands"); - // The shortest an arg can legally be is 2 (i.e. '-x') - let mut longest = 2; - let mut ord_v = Vec::new(); - for subcommand in cmd - .get_subcommands() - .filter(|subcommand| should_show_subcommand(subcommand)) - { - let mut sc_str = String::new(); - sc_str.push_str(subcommand.get_name()); - if let Some(short) = subcommand.get_short_flag() { - write!(sc_str, " -{}", short).unwrap(); - } - if let Some(long) = subcommand.get_long_flag() { - write!(sc_str, " --{}", long).unwrap(); - } - longest = longest.max(display_width(&sc_str)); - ord_v.push((subcommand.get_display_order(), sc_str, subcommand)); - } - ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1))); - - debug!("Help::write_subcommands longest = {}", longest); - - let next_line_help = self.will_subcommands_wrap(cmd.get_subcommands(), longest); - - let mut first = true; - for (_, sc_str, sc) in &ord_v { - if first { - first = false; - } else { - self.none("\n")?; - } - self.write_subcommand(sc_str, sc, next_line_help, longest)?; - } - Ok(()) - } - - /// Writes binary name of a Parser Object to the wrapped stream. - fn write_display_name(&mut self) -> io::Result<()> { - debug!("Help::write_display_name"); - - let display_name = text_wrapper( - &self - .cmd - .get_display_name() - .unwrap_or_else(|| self.cmd.get_name()) - .replace("{n}", "\n"), - self.term_w, - ); - self.good(&display_name)?; - Ok(()) - } - - /// Writes binary name of a Parser Object to the wrapped stream. - fn write_bin_name(&mut self) -> io::Result<()> { - debug!("Help::write_bin_name"); - - let bin_name = if let Some(bn) = self.cmd.get_bin_name() { - if bn.contains(' ') { - // In case we're dealing with subcommands i.e. git mv is translated to git-mv - bn.replace(' ', "-") - } else { - text_wrapper(&self.cmd.get_name().replace("{n}", "\n"), self.term_w) - } - } else { - text_wrapper(&self.cmd.get_name().replace("{n}", "\n"), self.term_w) - }; - self.good(&bin_name)?; - Ok(()) - } -} - -// Methods to write Parser help using templates. -impl<'help, 'cmd, 'writer> Help<'help, 'cmd, 'writer> { - /// Write help to stream for the parser in the format defined by the template. - /// - /// For details about the template language see [`Command::help_template`]. - /// - /// [`Command::help_template`]: Command::help_template() - fn write_templated_help(&mut self, template: &str) -> io::Result<()> { - debug!("Help::write_templated_help"); - - // The strategy is to copy the template from the reader to wrapped stream - // until a tag is found. Depending on its value, the appropriate content is copied - // to the wrapped stream. - // The copy from template is then resumed, repeating this sequence until reading - // the complete template. - - macro_rules! tags { - ( - match $part:ident { - $( $tag:expr => $action:stmt )* - } - ) => { - match $part { - $( - part if part.starts_with(concat!($tag, "}")) => { - $action - let rest = &part[$tag.len()+1..]; - self.none(rest)?; - } - )* - - // Unknown tag, write it back. - part => { - self.none("{")?; - self.none(part)?; - } - } - }; - } - - let mut parts = template.split('{'); - if let Some(first) = parts.next() { - self.none(first)?; - } - - for part in parts { - tags! { - match part { - "name" => { - self.write_display_name()?; - } - "bin" => { - self.write_bin_name()?; - } - "version" => { - self.write_version()?; - } - "author" => { - self.write_author(false, false)?; - } - "author-with-newline" => { - self.write_author(false, true)?; - } - "author-section" => { - self.write_author(true, true)?; - } - "about" => { - self.write_about(false, false)?; - } - "about-with-newline" => { - self.write_about(false, true)?; - } - "about-section" => { - self.write_about(true, true)?; - } - "usage-heading" => { - self.warning("USAGE:")?; - } - "usage" => { - self.none(self.usage.create_usage_no_title(&[]))?; - } - "all-args" => { - self.write_all_args()?; - } - "options" => { - // Include even those with a heading as we don't have a good way of - // handling help_heading in the template. - self.write_args(&self.cmd.get_non_positionals().collect::<Vec<_>>(), "options")?; - } - "positionals" => { - self.write_args(&self.cmd.get_positionals().collect::<Vec<_>>(), "positionals")?; - } - "subcommands" => { - self.write_subcommands(self.cmd)?; - } - "after-help" => { - self.write_after_help()?; - } - "before-help" => { - self.write_before_help()?; - } - } - } - } - - Ok(()) - } -} - -pub(crate) fn dimensions() -> Option<(usize, usize)> { - #[cfg(not(feature = "wrap_help"))] - return None; - - #[cfg(feature = "wrap_help")] - terminal_size::terminal_size().map(|(w, h)| (w.0.into(), h.0.into())) -} - -const TAB: &str = " "; -const TAB_WIDTH: usize = 4; - -pub(crate) enum HelpWriter<'writer> { - Normal(&'writer mut dyn Write), - Buffer(&'writer mut Colorizer), -} - -fn should_show_arg(use_long: bool, arg: &Arg) -> bool { - debug!("should_show_arg: use_long={:?}, arg={}", use_long, arg.name); - if arg.is_hide_set() { - return false; - } - (!arg.is_hide_long_help_set() && use_long) - || (!arg.is_hide_short_help_set() && !use_long) - || arg.is_next_line_help_set() -} - -fn should_show_subcommand(subcommand: &Command) -> bool { - !subcommand.is_hide_set() -} - -fn text_wrapper(help: &str, width: usize) -> String { - let wrapper = textwrap::Options::new(width) - .break_words(false) - .word_splitter(textwrap::WordSplitter::NoHyphenation); - help.lines() - .map(|line| textwrap::fill(line, &wrapper)) - .collect::<Vec<String>>() - .join("\n") -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn wrap_help_last_word() { - let help = String::from("foo bar baz"); - assert_eq!(text_wrapper(&help, 5), "foo\nbar\nbaz"); - } - - #[test] - fn display_width_handles_non_ascii() { - // Popular Danish tongue-twister, the name of a fruit dessert. - let text = "rødgrød med fløde"; - assert_eq!(display_width(text), 17); - // Note that the string width is smaller than the string - // length. This is due to the precomposed non-ASCII letters: - assert_eq!(text.len(), 20); - } - - #[test] - fn display_width_handles_emojis() { - let text = "😂"; - // There is a single `char`... - assert_eq!(text.chars().count(), 1); - // but it is double-width: - assert_eq!(display_width(text), 2); - // This is much less than the byte length: - assert_eq!(text.len(), 4); - } -} diff --git a/vendor/clap/src/output/mod.rs b/vendor/clap/src/output/mod.rs deleted file mode 100644 index e32aac26a..000000000 --- a/vendor/clap/src/output/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod help; -mod usage; - -pub(crate) mod fmt; - -pub(crate) use self::help::{Help, HelpWriter}; -pub(crate) use self::usage::Usage; diff --git a/vendor/clap/src/output/usage.rs b/vendor/clap/src/output/usage.rs deleted file mode 100644 index 6f7a2cad4..000000000 --- a/vendor/clap/src/output/usage.rs +++ /dev/null @@ -1,449 +0,0 @@ -use indexmap::IndexSet; - -// Internal -use crate::builder::AppSettings as AS; -use crate::builder::{Arg, ArgPredicate, Command}; -use crate::parser::ArgMatcher; -use crate::util::ChildGraph; -use crate::util::Id; -use crate::INTERNAL_ERROR_MSG; - -pub(crate) struct Usage<'help, 'cmd> { - cmd: &'cmd Command<'help>, - required: Option<&'cmd ChildGraph<Id>>, -} - -impl<'help, 'cmd> Usage<'help, 'cmd> { - pub(crate) fn new(cmd: &'cmd Command<'help>) -> Self { - Usage { - cmd, - required: None, - } - } - - pub(crate) fn required(mut self, required: &'cmd ChildGraph<Id>) -> Self { - self.required = Some(required); - self - } - - // Creates a usage string for display. This happens just after all arguments were parsed, but before - // any subcommands have been parsed (so as to give subcommands their own usage recursively) - pub(crate) fn create_usage_with_title(&self, used: &[Id]) -> String { - debug!("Usage::create_usage_with_title"); - let mut usage = String::with_capacity(75); - usage.push_str("USAGE:\n "); - usage.push_str(&*self.create_usage_no_title(used)); - usage - } - - // Creates a usage string (*without title*) if one was not provided by the user manually. - pub(crate) fn create_usage_no_title(&self, used: &[Id]) -> String { - debug!("Usage::create_usage_no_title"); - if let Some(u) = self.cmd.get_override_usage() { - String::from(&*u) - } else if used.is_empty() { - self.create_help_usage(true) - } else { - self.create_smart_usage(used) - } - } - - // Creates a usage string for display in help messages (i.e. not for errors) - fn create_help_usage(&self, incl_reqs: bool) -> String { - debug!("Usage::create_help_usage; incl_reqs={:?}", incl_reqs); - let mut usage = String::with_capacity(75); - let name = self - .cmd - .get_usage_name() - .or_else(|| self.cmd.get_bin_name()) - .unwrap_or_else(|| self.cmd.get_name()); - usage.push_str(name); - let req_string = if incl_reqs { - self.get_required_usage_from(&[], None, false) - .iter() - .fold(String::new(), |a, s| a + " " + s) - } else { - String::new() - }; - - if self.needs_options_tag() { - usage.push_str(" [OPTIONS]"); - } - - let allow_missing_positional = self.cmd.is_allow_missing_positional_set(); - if !allow_missing_positional { - usage.push_str(&req_string); - } - - let has_last = self.cmd.get_positionals().any(|p| p.is_last_set()); - // places a '--' in the usage string if there are args and options - // supporting multiple values - if self - .cmd - .get_non_positionals() - .any(|o| o.is_multiple_values_set()) - && self.cmd.get_positionals().any(|p| !p.is_required_set()) - && !(self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set()) - && !has_last - { - usage.push_str(" [--]"); - } - let not_req_or_hidden = - |p: &Arg| (!p.is_required_set() || p.is_last_set()) && !p.is_hide_set(); - if self.cmd.get_positionals().any(not_req_or_hidden) { - if let Some(args_tag) = self.get_args_tag(incl_reqs) { - usage.push_str(&*args_tag); - } else { - usage.push_str(" [ARGS]"); - } - if has_last && incl_reqs { - let pos = self - .cmd - .get_positionals() - .find(|p| p.is_last_set()) - .expect(INTERNAL_ERROR_MSG); - debug!("Usage::create_help_usage: '{}' has .last(true)", pos.name); - let req = pos.is_required_set(); - if req && self.cmd.get_positionals().any(|p| !p.is_required_set()) { - usage.push_str(" -- <"); - } else if req { - usage.push_str(" [--] <"); - } else { - usage.push_str(" [-- <"); - } - usage.push_str(&*pos.name_no_brackets()); - usage.push('>'); - usage.push_str(pos.multiple_str()); - if !req { - usage.push(']'); - } - } - } - - if allow_missing_positional { - usage.push_str(&req_string); - } - - // incl_reqs is only false when this function is called recursively - if self.cmd.has_visible_subcommands() && incl_reqs - || self.cmd.is_allow_external_subcommands_set() - { - let placeholder = self.cmd.get_subcommand_value_name().unwrap_or("SUBCOMMAND"); - #[allow(deprecated)] - if self.cmd.is_subcommand_negates_reqs_set() - || self.cmd.is_args_conflicts_with_subcommands_set() - { - usage.push_str("\n "); - if !self.cmd.is_args_conflicts_with_subcommands_set() { - usage.push_str(&*self.create_help_usage(false)); - } else { - usage.push_str(&*name); - } - usage.push_str(" <"); - usage.push_str(placeholder); - usage.push('>'); - } else if self.cmd.is_subcommand_required_set() - || self.cmd.is_set(AS::SubcommandRequiredElseHelp) - { - usage.push_str(" <"); - usage.push_str(placeholder); - usage.push('>'); - } else { - usage.push_str(" ["); - usage.push_str(placeholder); - usage.push(']'); - } - } - let usage = usage.trim().to_owned(); - debug!("Usage::create_help_usage: usage={}", usage); - usage - } - - // Creates a context aware usage string, or "smart usage" from currently used - // args, and requirements - fn create_smart_usage(&self, used: &[Id]) -> String { - debug!("Usage::create_smart_usage"); - let mut usage = String::with_capacity(75); - - let r_string = self - .get_required_usage_from(used, None, true) - .iter() - .fold(String::new(), |acc, s| acc + " " + s); - - usage.push_str( - self.cmd - .get_usage_name() - .or_else(|| self.cmd.get_bin_name()) - .unwrap_or_else(|| self.cmd.get_name()), - ); - usage.push_str(&*r_string); - if self.cmd.is_subcommand_required_set() { - usage.push_str(" <"); - usage.push_str(self.cmd.get_subcommand_value_name().unwrap_or("SUBCOMMAND")); - usage.push('>'); - } - usage.shrink_to_fit(); - usage - } - - // Gets the `[ARGS]` tag for the usage string - fn get_args_tag(&self, incl_reqs: bool) -> Option<String> { - debug!("Usage::get_args_tag; incl_reqs = {:?}", incl_reqs); - let mut count = 0; - for pos in self - .cmd - .get_positionals() - .filter(|pos| !pos.is_required_set()) - .filter(|pos| !pos.is_hide_set()) - .filter(|pos| !pos.is_last_set()) - { - debug!("Usage::get_args_tag:iter:{}", pos.name); - let required = self.cmd.groups_for_arg(&pos.id).any(|grp_s| { - debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s); - // if it's part of a required group we don't want to count it - self.cmd.get_groups().any(|g| g.required && (g.id == grp_s)) - }); - if !required { - count += 1; - debug!( - "Usage::get_args_tag:iter: {} Args not required or hidden", - count - ); - } - } - - if !self.cmd.is_dont_collapse_args_in_usage_set() && count > 1 { - debug!("Usage::get_args_tag:iter: More than one, returning [ARGS]"); - - // [ARGS] - None - } else if count == 1 && incl_reqs { - let pos = self - .cmd - .get_positionals() - .find(|pos| { - !pos.is_required_set() - && !pos.is_hide_set() - && !pos.is_last_set() - && !self.cmd.groups_for_arg(&pos.id).any(|grp_s| { - debug!("Usage::get_args_tag:iter:{:?}:iter:{:?}", pos.name, grp_s); - // if it's part of a required group we don't want to count it - self.cmd.get_groups().any(|g| g.required && (g.id == grp_s)) - }) - }) - .expect(INTERNAL_ERROR_MSG); - - debug!( - "Usage::get_args_tag:iter: Exactly one, returning '{}'", - pos.name - ); - - Some(format!( - " [{}]{}", - pos.name_no_brackets(), - pos.multiple_str() - )) - } else if self.cmd.is_dont_collapse_args_in_usage_set() - && self.cmd.has_positionals() - && incl_reqs - { - debug!("Usage::get_args_tag:iter: Don't collapse returning all"); - Some( - self.cmd - .get_positionals() - .filter(|pos| !pos.is_required_set()) - .filter(|pos| !pos.is_hide_set()) - .filter(|pos| !pos.is_last_set()) - .map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())) - .collect::<Vec<_>>() - .join(""), - ) - } else if !incl_reqs { - debug!("Usage::get_args_tag:iter: incl_reqs=false, building secondary usage string"); - let highest_req_pos = self - .cmd - .get_positionals() - .filter_map(|pos| { - if pos.is_required_set() && !pos.is_last_set() { - Some(pos.index) - } else { - None - } - }) - .max() - .unwrap_or_else(|| Some(self.cmd.get_positionals().count())); - Some( - self.cmd - .get_positionals() - .filter(|pos| pos.index <= highest_req_pos) - .filter(|pos| !pos.is_required_set()) - .filter(|pos| !pos.is_hide_set()) - .filter(|pos| !pos.is_last_set()) - .map(|pos| format!(" [{}]{}", pos.name_no_brackets(), pos.multiple_str())) - .collect::<Vec<_>>() - .join(""), - ) - } else { - Some("".into()) - } - } - - // Determines if we need the `[OPTIONS]` tag in the usage string - fn needs_options_tag(&self) -> bool { - debug!("Usage::needs_options_tag"); - 'outer: for f in self.cmd.get_non_positionals() { - debug!("Usage::needs_options_tag:iter: f={}", f.name); - - // Don't print `[OPTIONS]` just for help or version - if f.long == Some("help") || f.long == Some("version") { - debug!("Usage::needs_options_tag:iter Option is built-in"); - continue; - } - - if f.is_hide_set() { - debug!("Usage::needs_options_tag:iter Option is hidden"); - continue; - } - if f.is_required_set() { - debug!("Usage::needs_options_tag:iter Option is required"); - continue; - } - for grp_s in self.cmd.groups_for_arg(&f.id) { - debug!("Usage::needs_options_tag:iter:iter: grp_s={:?}", grp_s); - if self.cmd.get_groups().any(|g| g.id == grp_s && g.required) { - debug!("Usage::needs_options_tag:iter:iter: Group is required"); - continue 'outer; - } - } - - debug!("Usage::needs_options_tag:iter: [OPTIONS] required"); - return true; - } - - debug!("Usage::needs_options_tag: [OPTIONS] not required"); - false - } - - // Returns the required args in usage string form by fully unrolling all groups - // `incl_last`: should we include args that are Arg::Last? (i.e. `prog [foo] -- [last]). We - // can't do that for required usages being built for subcommands because it would look like: - // `prog [foo] -- [last] <subcommand>` which is totally wrong. - pub(crate) fn get_required_usage_from( - &self, - incls: &[Id], - matcher: Option<&ArgMatcher>, - incl_last: bool, - ) -> IndexSet<String> { - debug!( - "Usage::get_required_usage_from: incls={:?}, matcher={:?}, incl_last={:?}", - incls, - matcher.is_some(), - incl_last - ); - let mut ret_val = IndexSet::new(); - - let mut unrolled_reqs = IndexSet::new(); - - let required_owned; - let required = if let Some(required) = self.required { - required - } else { - required_owned = self.cmd.required_graph(); - &required_owned - }; - - for a in required.iter() { - let is_relevant = |(val, req_arg): &(ArgPredicate<'_>, Id)| -> Option<Id> { - let required = match val { - ArgPredicate::Equals(_) => { - if let Some(matcher) = matcher { - matcher.check_explicit(a, *val) - } else { - false - } - } - ArgPredicate::IsPresent => true, - }; - required.then(|| req_arg.clone()) - }; - - for aa in self.cmd.unroll_arg_requires(is_relevant, a) { - // if we don't check for duplicates here this causes duplicate error messages - // see https://github.com/clap-rs/clap/issues/2770 - unrolled_reqs.insert(aa); - } - // always include the required arg itself. it will not be enumerated - // by unroll_requirements_for_arg. - unrolled_reqs.insert(a.clone()); - } - - debug!( - "Usage::get_required_usage_from: unrolled_reqs={:?}", - unrolled_reqs - ); - - let mut required_groups_members = IndexSet::new(); - let mut required_opts = IndexSet::new(); - let mut required_groups = IndexSet::new(); - let mut required_positionals = Vec::new(); - for req in unrolled_reqs.iter().chain(incls.iter()) { - if let Some(arg) = self.cmd.find(req) { - let is_present = matcher - .map(|m| m.check_explicit(req, ArgPredicate::IsPresent)) - .unwrap_or(false); - debug!( - "Usage::get_required_usage_from:iter:{:?} arg is_present={}", - req, is_present - ); - if !is_present { - if arg.is_positional() { - if incl_last || !arg.is_last_set() { - required_positionals.push((arg.index.unwrap(), arg.to_string())); - } - } else { - required_opts.insert(arg.to_string()); - } - } - } else { - debug_assert!(self.cmd.find_group(req).is_some()); - let group_members = self.cmd.unroll_args_in_group(req); - let is_present = matcher - .map(|m| { - group_members - .iter() - .any(|arg| m.check_explicit(arg, ArgPredicate::IsPresent)) - }) - .unwrap_or(false); - debug!( - "Usage::get_required_usage_from:iter:{:?} group is_present={}", - req, is_present - ); - if !is_present { - let elem = self.cmd.format_group(req); - required_groups.insert(elem); - required_groups_members.extend( - group_members - .iter() - .flat_map(|id| self.cmd.find(id)) - .map(|arg| arg.to_string()), - ); - } - } - } - - required_opts.retain(|arg| !required_groups_members.contains(arg)); - ret_val.extend(required_opts); - - ret_val.extend(required_groups); - - required_positionals.sort_by_key(|(ind, _)| *ind); // sort by index - for (_, p) in required_positionals { - if !required_groups_members.contains(&p) { - ret_val.insert(p); - } - } - - debug!("Usage::get_required_usage_from: ret_val={:?}", ret_val); - ret_val - } -} |