diff options
Diffstat (limited to 'vendor/clap_builder/src/output')
-rw-r--r-- | vendor/clap_builder/src/output/fmt.rs | 83 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/help.rs | 39 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/help_template.rs | 1198 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/mod.rs | 23 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/textwrap/core.rs | 158 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/textwrap/mod.rs | 122 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/textwrap/word_separators.rs | 92 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs | 63 | ||||
-rw-r--r-- | vendor/clap_builder/src/output/usage.rs | 529 |
9 files changed, 0 insertions, 2307 deletions
diff --git a/vendor/clap_builder/src/output/fmt.rs b/vendor/clap_builder/src/output/fmt.rs deleted file mode 100644 index 0c9a24f..0000000 --- a/vendor/clap_builder/src/output/fmt.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::builder::StyledStr; -use crate::util::color::ColorChoice; - -#[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, - content: StyledStr, -} - -impl Colorizer { - pub(crate) fn new(stream: Stream, color_when: ColorChoice) -> Self { - Colorizer { - stream, - color_when, - content: Default::default(), - } - } - - pub(crate) fn with_content(mut self, content: StyledStr) -> Self { - self.content = content; - self - } -} - -/// Printing methods. -impl Colorizer { - #[cfg(feature = "color")] - pub(crate) fn print(&self) -> std::io::Result<()> { - let color_when = match self.color_when { - ColorChoice::Always => anstream::ColorChoice::Always, - ColorChoice::Auto => anstream::ColorChoice::Auto, - ColorChoice::Never => anstream::ColorChoice::Never, - }; - - let mut stdout; - let mut stderr; - let writer: &mut dyn std::io::Write = match self.stream { - Stream::Stderr => { - stderr = anstream::AutoStream::new(std::io::stderr().lock(), color_when); - &mut stderr - } - Stream::Stdout => { - stdout = anstream::AutoStream::new(std::io::stdout().lock(), color_when); - &mut stdout - } - }; - - self.content.write_to(writer) - } - - #[cfg(not(feature = "color"))] - pub(crate) fn print(&self) -> std::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(); - self.content.write_to(&mut stdout) - } - Stream::Stderr => { - let stderr = std::io::stderr(); - let mut stderr = stderr.lock(); - self.content.write_to(&mut stderr) - } - } - } -} - -/// Color-unaware printing. Never uses coloring. -impl std::fmt::Display for Colorizer { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - self.content.fmt(f) - } -} diff --git a/vendor/clap_builder/src/output/help.rs b/vendor/clap_builder/src/output/help.rs deleted file mode 100644 index a5073a9..0000000 --- a/vendor/clap_builder/src/output/help.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![cfg_attr(not(feature = "help"), allow(unused_variables))] - -// Internal -use crate::builder::Command; -use crate::builder::StyledStr; -use crate::output::Usage; - -/// Writes the parser help to the wrapped stream. -pub(crate) fn write_help(writer: &mut StyledStr, cmd: &Command, usage: &Usage<'_>, use_long: bool) { - debug!("write_help"); - - if let Some(h) = cmd.get_override_help() { - writer.push_styled(h); - } else { - #[cfg(feature = "help")] - { - use super::AutoHelp; - use super::HelpTemplate; - if let Some(tmpl) = cmd.get_help_template() { - HelpTemplate::new(writer, cmd, usage, use_long) - .write_templated_help(tmpl.as_styled_str()); - } else { - AutoHelp::new(writer, cmd, usage, use_long).write_help(); - } - } - - #[cfg(not(feature = "help"))] - { - debug!("write_help: no help, `Command::override_help` and `help` is missing"); - } - } - - // Remove any lines from unused sections - writer.trim_start_lines(); - // Remove any whitespace caused by book keeping - writer.trim_end(); - // Ensure there is still a trailing newline - writer.push_str("\n"); -} diff --git a/vendor/clap_builder/src/output/help_template.rs b/vendor/clap_builder/src/output/help_template.rs deleted file mode 100644 index dff15ff..0000000 --- a/vendor/clap_builder/src/output/help_template.rs +++ /dev/null @@ -1,1198 +0,0 @@ -// HACK: for rust 1.64 (1.68 doesn't need this since this is in lib.rs) -// -// Wanting consistency in our calls -#![allow(clippy::write_with_newline)] - -// Std -use std::borrow::Cow; -use std::cmp; -use std::usize; - -// Internal -use crate::builder::PossibleValue; -use crate::builder::Str; -use crate::builder::StyledStr; -use crate::builder::Styles; -use crate::builder::{Arg, Command}; -use crate::output::display_width; -use crate::output::wrap; -use crate::output::Usage; -use crate::output::TAB; -use crate::output::TAB_WIDTH; -use crate::util::FlatSet; - -/// `clap` auto-generated help writer -pub(crate) struct AutoHelp<'cmd, 'writer> { - template: HelpTemplate<'cmd, 'writer>, -} - -// Public Functions -impl<'cmd, 'writer> AutoHelp<'cmd, 'writer> { - /// Create a new `HelpTemplate` instance. - pub(crate) fn new( - writer: &'writer mut StyledStr, - cmd: &'cmd Command, - usage: &'cmd Usage<'cmd>, - use_long: bool, - ) -> Self { - Self { - template: HelpTemplate::new(writer, cmd, usage, use_long), - } - } - - pub(crate) fn write_help(&mut self) { - let pos = self - .template - .cmd - .get_positionals() - .any(|arg| should_show_arg(self.template.use_long, arg)); - let non_pos = self - .template - .cmd - .get_non_positionals() - .any(|arg| should_show_arg(self.template.use_long, arg)); - let subcmds = self.template.cmd.has_visible_subcommands(); - - let template = if non_pos || pos || subcmds { - DEFAULT_TEMPLATE - } else { - DEFAULT_NO_ARGS_TEMPLATE - }; - self.template.write_templated_help(template); - } -} - -const DEFAULT_TEMPLATE: &str = "\ -{before-help}{about-with-newline} -{usage-heading} {usage} - -{all-args}{after-help}\ - "; - -const DEFAULT_NO_ARGS_TEMPLATE: &str = "\ -{before-help}{about-with-newline} -{usage-heading} {usage}{after-help}\ - "; - -/// `clap` HelpTemplate Writer. -/// -/// Wraps a writer stream providing different methods to generate help for `clap` objects. -pub(crate) struct HelpTemplate<'cmd, 'writer> { - writer: &'writer mut StyledStr, - cmd: &'cmd Command, - styles: &'cmd Styles, - usage: &'cmd Usage<'cmd>, - next_line_help: bool, - term_w: usize, - use_long: bool, -} - -// Public Functions -impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> { - /// Create a new `HelpTemplate` instance. - pub(crate) fn new( - writer: &'writer mut StyledStr, - cmd: &'cmd Command, - usage: &'cmd Usage<'cmd>, - use_long: bool, - ) -> Self { - debug!( - "HelpTemplate::new cmd={}, use_long={}", - cmd.get_name(), - use_long - ); - let term_w = Self::term_w(cmd); - let next_line_help = cmd.is_next_line_help_set(); - - HelpTemplate { - writer, - cmd, - styles: cmd.get_styles(), - usage, - next_line_help, - term_w, - use_long, - } - } - - #[cfg(not(feature = "unstable-v5"))] - fn term_w(cmd: &'cmd Command) -> usize { - match cmd.get_term_width() { - Some(0) => usize::MAX, - Some(w) => w, - None => { - let (current_width, _h) = dimensions(); - let current_width = current_width.unwrap_or(100); - let max_width = match cmd.get_max_term_width() { - None | Some(0) => usize::MAX, - Some(mw) => mw, - }; - cmp::min(current_width, max_width) - } - } - } - - #[cfg(feature = "unstable-v5")] - fn term_w(cmd: &'cmd Command) -> usize { - let term_w = match cmd.get_term_width() { - Some(0) => usize::MAX, - Some(w) => w, - None => { - let (current_width, _h) = dimensions(); - current_width.unwrap_or(usize::MAX) - } - }; - - let max_term_w = match cmd.get_max_term_width() { - Some(0) => usize::MAX, - Some(mw) => mw, - None => 100, - }; - - cmp::min(term_w, max_term_w) - } - - /// 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() - pub(crate) fn write_templated_help(&mut self, template: &str) { - debug!("HelpTemplate::write_templated_help"); - use std::fmt::Write as _; - - let mut parts = template.split('{'); - if let Some(first) = parts.next() { - self.writer.push_str(first); - } - for part in parts { - if let Some((tag, rest)) = part.split_once('}') { - match tag { - "name" => { - self.write_display_name(); - } - #[cfg(not(feature = "unstable-v5"))] - "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" => { - let _ = write!( - self.writer, - "{}Usage:{}", - self.styles.get_usage().render(), - self.styles.get_usage().render_reset() - ); - } - "usage" => { - self.writer.push_styled( - &self.usage.create_usage_no_title(&[]).unwrap_or_default(), - ); - } - "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", - option_sort_key, - ); - } - "positionals" => { - self.write_args( - &self.cmd.get_positionals().collect::<Vec<_>>(), - "positionals", - positional_sort_key, - ); - } - "subcommands" => { - self.write_subcommands(self.cmd); - } - "tab" => { - self.writer.push_str(TAB); - } - "after-help" => { - self.write_after_help(); - } - "before-help" => { - self.write_before_help(); - } - _ => { - let _ = write!(self.writer, "{{{tag}}}"); - } - } - self.writer.push_str(rest); - } - } - } -} - -/// Basic template methods -impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> { - /// Writes binary name of a Parser Object to the wrapped stream. - fn write_display_name(&mut self) { - debug!("HelpTemplate::write_display_name"); - - let display_name = wrap( - &self - .cmd - .get_display_name() - .unwrap_or_else(|| self.cmd.get_name()) - .replace("{n}", "\n"), - self.term_w, - ); - self.writer.push_string(display_name); - } - - /// Writes binary name of a Parser Object to the wrapped stream. - #[cfg(not(feature = "unstable-v5"))] - fn write_bin_name(&mut self) { - debug!("HelpTemplate::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 { - wrap(&self.cmd.get_name().replace("{n}", "\n"), self.term_w) - } - } else { - wrap(&self.cmd.get_name().replace("{n}", "\n"), self.term_w) - }; - self.writer.push_string(bin_name); - } - - fn write_version(&mut self) { - let version = self - .cmd - .get_version() - .or_else(|| self.cmd.get_long_version()); - if let Some(output) = version { - self.writer.push_string(wrap(output, self.term_w)); - } - } - - fn write_author(&mut self, before_new_line: bool, after_new_line: bool) { - if let Some(author) = self.cmd.get_author() { - if before_new_line { - self.writer.push_str("\n"); - } - self.writer.push_string(wrap(author, self.term_w)); - if after_new_line { - self.writer.push_str("\n"); - } - } - } - - fn write_about(&mut self, before_new_line: bool, after_new_line: bool) { - 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.writer.push_str("\n"); - } - let mut output = output.clone(); - output.replace_newline_var(); - output.wrap(self.term_w); - self.writer.push_styled(&output); - if after_new_line { - self.writer.push_str("\n"); - } - } - } - - fn write_before_help(&mut self) { - debug!("HelpTemplate::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 { - let mut output = output.clone(); - output.replace_newline_var(); - output.wrap(self.term_w); - self.writer.push_styled(&output); - self.writer.push_str("\n\n"); - } - } - - fn write_after_help(&mut self) { - debug!("HelpTemplate::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.writer.push_str("\n\n"); - let mut output = output.clone(); - output.replace_newline_var(); - output.wrap(self.term_w); - self.writer.push_styled(&output); - } - } -} - -/// Arg handling -impl<'cmd, 'writer> HelpTemplate<'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) { - debug!("HelpTemplate::write_all_args"); - use std::fmt::Write as _; - let header = &self.styles.get_header(); - - let pos = self - .cmd - .get_positionals() - .filter(|a| a.get_help_heading().is_none()) - .filter(|arg| should_show_arg(self.use_long, arg)) - .collect::<Vec<_>>(); - let non_pos = self - .cmd - .get_non_positionals() - .filter(|a| a.get_help_heading().is_none()) - .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::<FlatSet<_>>(); - - let flatten = self.cmd.is_flatten_help_set(); - - let mut first = true; - - if subcmds && !flatten { - if !first { - self.writer.push_str("\n\n"); - } - first = false; - let default_help_heading = Str::from("Commands"); - let help_heading = self - .cmd - .get_subcommand_help_heading() - .unwrap_or(&default_help_heading); - let _ = write!( - self.writer, - "{}{help_heading}:{}\n", - header.render(), - header.render_reset() - ); - - self.write_subcommands(self.cmd); - } - - if !pos.is_empty() { - if !first { - self.writer.push_str("\n\n"); - } - first = false; - // Write positional args if any - let help_heading = "Arguments"; - let _ = write!( - self.writer, - "{}{help_heading}:{}\n", - header.render(), - header.render_reset() - ); - self.write_args(&pos, "Arguments", positional_sort_key); - } - - if !non_pos.is_empty() { - if !first { - self.writer.push_str("\n\n"); - } - first = false; - let help_heading = "Options"; - let _ = write!( - self.writer, - "{}{help_heading}:{}\n", - header.render(), - header.render_reset() - ); - self.write_args(&non_pos, "Options", option_sort_key); - } - 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.writer.push_str("\n\n"); - } - first = false; - let _ = write!( - self.writer, - "{}{heading}:{}\n", - header.render(), - header.render_reset() - ); - self.write_args(&args, heading, option_sort_key); - } - } - } - if subcmds && flatten { - let mut cmd = self.cmd.clone(); - cmd.build(); - self.write_flat_subcommands(&cmd, &mut first); - } - } - - /// Sorts arguments by length and display order and write their help to the wrapped stream. - fn write_args(&mut self, args: &[&Arg], _category: &str, sort_key: ArgSortKey) { - debug!("HelpTemplate::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 longest_filter(arg) { - longest = longest.max(display_width(&arg.to_string())); - debug!( - "HelpTemplate::write_args: arg={:?} longest={}", - arg.get_id(), - longest - ); - } - - let key = (sort_key)(arg); - ord_v.push((key, arg)); - } - ord_v.sort_by(|a, b| a.0.cmp(&b.0)); - - let next_line_help = self.will_args_wrap(args, longest); - - for (i, (_, arg)) in ord_v.iter().enumerate() { - if i != 0 { - self.writer.push_str("\n"); - if next_line_help && self.use_long { - self.writer.push_str("\n"); - } - } - self.write_arg(arg, next_line_help, longest); - } - } - - /// Writes help for an argument to the wrapped stream. - fn write_arg(&mut self, arg: &Arg, next_line_help: bool, longest: usize) { - let spec_vals = &self.spec_vals(arg); - - self.writer.push_str(TAB); - self.short(arg); - self.long(arg); - self.writer - .push_styled(&arg.stylize_arg_suffix(self.styles, None)); - self.align_to_about(arg, next_line_help, longest); - - let about = if self.use_long { - arg.get_long_help() - .or_else(|| arg.get_help()) - .unwrap_or_default() - } else { - arg.get_help() - .or_else(|| arg.get_long_help()) - .unwrap_or_default() - }; - - self.help(Some(arg), about, spec_vals, next_line_help, longest); - } - - /// Writes argument's short command to the wrapped stream. - fn short(&mut self, arg: &Arg) { - debug!("HelpTemplate::short"); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - - if let Some(s) = arg.get_short() { - let _ = write!( - self.writer, - "{}-{s}{}", - literal.render(), - literal.render_reset() - ); - } else if arg.get_long().is_some() { - self.writer.push_str(" "); - } - } - - /// Writes argument's long command to the wrapped stream. - fn long(&mut self, arg: &Arg) { - debug!("HelpTemplate::long"); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - - if let Some(long) = arg.get_long() { - if arg.get_short().is_some() { - self.writer.push_str(", "); - } - let _ = write!( - self.writer, - "{}--{long}{}", - literal.render(), - literal.render_reset() - ); - } - } - - /// Write alignment padding between arg's switches/values and its about message. - fn align_to_about(&mut self, arg: &Arg, next_line_help: bool, longest: usize) { - debug!( - "HelpTemplate::align_to_about: arg={}, next_line_help={}, longest={}", - arg.get_id(), - next_line_help, - longest - ); - let padding = if self.use_long || next_line_help { - // long help prints messages on the next line so it doesn't need to align text - debug!("HelpTemplate::align_to_about: printing long help so skip alignment"); - 0 - } 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.get_long().is_some() { - // Only account 4 after the val - TAB_WIDTH - } else { - // Only account for ', --' + 4 after the val - TAB_WIDTH + 4 - }; - let spcs = longest + padding - self_len; - debug!( - "HelpTemplate::align_to_about: positional=false arg_len={self_len}, spaces={spcs}" - ); - - spcs - } else { - let self_len = display_width(&arg.to_string()); - let padding = TAB_WIDTH; - let spcs = longest + padding - self_len; - debug!( - "HelpTemplate::align_to_about: positional=true arg_len={self_len}, spaces={spcs}", - ); - - spcs - }; - - self.write_padding(padding); - } - - /// Writes argument's help to the wrapped stream. - fn help( - &mut self, - arg: Option<&Arg>, - about: &StyledStr, - spec_vals: &str, - next_line_help: bool, - longest: usize, - ) { - debug!("HelpTemplate::help"); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - - // Is help on next line, if so then indent - if next_line_help { - debug!("HelpTemplate::help: Next Line...{next_line_help:?}"); - self.writer.push_str("\n"); - self.writer.push_str(TAB); - self.writer.push_str(NEXT_LINE_INDENT); - } - - let spaces = if next_line_help { - TAB.len() + NEXT_LINE_INDENT.len() - } else if let Some(true) = arg.map(|a| a.is_positional()) { - longest + TAB_WIDTH * 2 - } else { - longest + TAB_WIDTH * 2 + 4 // See `fn short` for the 4 - }; - let trailing_indent = spaces; // Don't indent any further than the first line is indented - let trailing_indent = self.get_spaces(trailing_indent); - - let mut help = about.clone(); - help.replace_newline_var(); - if !spec_vals.is_empty() { - if !help.is_empty() { - let sep = if self.use_long && arg.is_some() { - "\n\n" - } else { - " " - }; - help.push_str(sep); - } - help.push_str(spec_vals); - } - let avail_chars = self.term_w.saturating_sub(spaces); - debug!( - "HelpTemplate::help: help_width={}, spaces={}, avail={}", - spaces, - help.display_width(), - avail_chars - ); - help.wrap(avail_chars); - help.indent("", &trailing_indent); - let help_is_empty = help.is_empty(); - self.writer.push_styled(&help); - if let Some(arg) = arg { - if !arg.is_hide_possible_values_set() && self.use_long_pv(arg) { - const DASH_SPACE: usize = "- ".len(); - let possible_vals = arg.get_possible_values(); - if !possible_vals.is_empty() { - debug!("HelpTemplate::help: Found possible vals...{possible_vals:?}"); - let longest = possible_vals - .iter() - .filter(|f| !f.is_hide_set()) - .map(|f| display_width(f.get_name())) - .max() - .expect("Only called with possible value"); - - let spaces = spaces + TAB_WIDTH - DASH_SPACE; - let trailing_indent = spaces + DASH_SPACE; - let trailing_indent = self.get_spaces(trailing_indent); - - if !help_is_empty { - let _ = write!(self.writer, "\n\n{:spaces$}", ""); - } - self.writer.push_str("Possible values:"); - for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) { - let name = pv.get_name(); - - let mut descr = StyledStr::new(); - let _ = write!( - &mut descr, - "{}{name}{}", - literal.render(), - literal.render_reset() - ); - if let Some(help) = pv.get_help() { - debug!("HelpTemplate::help: Possible Value help"); - // To align help messages - let padding = longest - display_width(name); - let _ = write!(&mut descr, ": {:padding$}", ""); - descr.push_styled(help); - } - - let avail_chars = if self.term_w > trailing_indent.len() { - self.term_w - trailing_indent.len() - } else { - usize::MAX - }; - descr.replace_newline_var(); - descr.wrap(avail_chars); - descr.indent("", &trailing_indent); - - let _ = write!(self.writer, "\n{:spaces$}- ", "",); - self.writer.push_styled(&descr); - } - } - } - } - } - - /// Will use next line help on writing args. - fn will_args_wrap(&self, args: &[&Arg], 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, 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.get_help().unwrap_or_default(); - let h_w = h.display_width() + display_width(spec_vals); - let taken = if arg.is_positional() { - longest + TAB_WIDTH * 2 - } else { - longest + TAB_WIDTH * 2 + 4 // See `fn short` for the 4 - }; - 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!("HelpTemplate::spec_vals: a={a}"); - let mut spec_vals = Vec::new(); - #[cfg(feature = "env")] - if let Some(ref env) = a.env { - if !a.is_hide_env_set() { - debug!( - "HelpTemplate::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(|s| s.to_string_lossy()) - .unwrap_or_default() - ) - } else { - Default::default() - }; - 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!( - "HelpTemplate::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}]")); - } - - let als = a - .aliases - .iter() - .filter(|&als| als.1) // visible - .map(|als| als.0.as_str()) // name - .collect::<Vec<_>>() - .join(", "); - if !als.is_empty() { - debug!("HelpTemplate::spec_vals: Found aliases...{:?}", a.aliases); - spec_vals.push(format!("[aliases: {als}]")); - } - - 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() { - debug!( - "HelpTemplate::spec_vals: Found short aliases...{:?}", - a.short_aliases - ); - spec_vals.push(format!("[short aliases: {als}]")); - } - - if !a.is_hide_possible_values_set() && !self.use_long_pv(a) { - let possible_vals = a.get_possible_values(); - if !possible_vals.is_empty() { - debug!("HelpTemplate::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 { " " }; - spec_vals.join(connector) - } - - fn get_spaces(&self, n: usize) -> String { - " ".repeat(n) - } - - fn write_padding(&mut self, amount: usize) { - use std::fmt::Write as _; - let _ = write!(self.writer, "{:amount$}", ""); - } - - fn use_long_pv(&self, arg: &Arg) -> bool { - self.use_long - && arg - .get_possible_values() - .iter() - .any(PossibleValue::should_show_help) - } -} - -/// Subcommand handling -impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> { - /// Writes help for subcommands of a Parser Object to the wrapped stream. - fn write_flat_subcommands(&mut self, cmd: &Command, first: &mut bool) { - debug!( - "HelpTemplate::write_flat_subcommands, cmd={}, first={}", - cmd.get_name(), - *first - ); - use std::fmt::Write as _; - let header = &self.styles.get_header(); - - let mut ord_v = Vec::new(); - for subcommand in cmd - .get_subcommands() - .filter(|subcommand| should_show_subcommand(subcommand)) - { - ord_v.push(( - subcommand.get_display_order(), - subcommand.get_name(), - subcommand, - )); - } - ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1))); - for (_, _, subcommand) in ord_v { - if !*first { - self.writer.push_str("\n\n"); - } - *first = false; - - let heading = subcommand.get_usage_name_fallback(); - let about = subcommand - .get_about() - .or_else(|| subcommand.get_long_about()) - .unwrap_or_default(); - - let _ = write!( - self.writer, - "{}{heading}:{}\n", - header.render(), - header.render_reset() - ); - if !about.is_empty() { - let _ = write!(self.writer, "{about}\n",); - } - - let mut sub_help = HelpTemplate { - writer: self.writer, - cmd: subcommand, - styles: self.styles, - usage: self.usage, - next_line_help: self.next_line_help, - term_w: self.term_w, - use_long: self.use_long, - }; - let args = subcommand - .get_arguments() - .filter(|arg| should_show_arg(self.use_long, arg) && !arg.is_global_set()) - .collect::<Vec<_>>(); - sub_help.write_args(&args, heading, option_sort_key); - if subcommand.is_flatten_help_set() { - sub_help.write_flat_subcommands(subcommand, first); - } - } - } - - /// Writes help for subcommands of a Parser Object to the wrapped stream. - fn write_subcommands(&mut self, cmd: &Command) { - debug!("HelpTemplate::write_subcommands"); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - - // 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 styled = StyledStr::new(); - let name = subcommand.get_name(); - let _ = write!( - styled, - "{}{name}{}", - literal.render(), - literal.render_reset() - ); - if let Some(short) = subcommand.get_short_flag() { - let _ = write!( - styled, - ", {}-{short}{}", - literal.render(), - literal.render_reset() - ); - } - if let Some(long) = subcommand.get_long_flag() { - let _ = write!( - styled, - ", {}--{long}{}", - literal.render(), - literal.render_reset() - ); - } - longest = longest.max(styled.display_width()); - ord_v.push((subcommand.get_display_order(), styled, subcommand)); - } - ord_v.sort_by(|a, b| (a.0, &a.1).cmp(&(b.0, &b.1))); - - debug!("HelpTemplate::write_subcommands longest = {longest}"); - - let next_line_help = self.will_subcommands_wrap(cmd.get_subcommands(), longest); - - for (i, (_, sc_str, sc)) in ord_v.into_iter().enumerate() { - if 0 < i { - self.writer.push_str("\n"); - } - self.write_subcommand(sc_str, sc, next_line_help, longest); - } - } - - /// Will use next line help on writing subcommands. - fn will_subcommands_wrap<'a>( - &self, - subcommands: impl IntoIterator<Item = &'a Command>, - longest: usize, - ) -> bool { - 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) - }) - } - - fn write_subcommand( - &mut self, - sc_str: StyledStr, - cmd: &Command, - next_line_help: bool, - longest: usize, - ) { - debug!("HelpTemplate::write_subcommand"); - - let spec_vals = &self.sc_spec_vals(cmd); - - let about = cmd - .get_about() - .or_else(|| cmd.get_long_about()) - .unwrap_or_default(); - - 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!("HelpTemplate::sc_spec_vals: a={}", a.get_name()); - let mut spec_vals = 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() { - debug!( - "HelpTemplate::spec_vals: Found aliases...{:?}", - a.get_all_aliases().collect::<Vec<_>>() - ); - debug!( - "HelpTemplate::spec_vals: Found short flag aliases...{:?}", - a.get_all_short_flag_aliases().collect::<Vec<_>>() - ); - spec_vals.push(format!("[aliases: {all_als}]")); - } - - spec_vals.join(" ") - } - - fn subcommand_next_line_help(&self, cmd: &Command, spec_vals: &str, longest: usize) -> bool { - // Ignore `self.use_long` since subcommands are only shown as short help - if self.next_line_help { - // setting_next_line - true - } else { - // force_next_line - let h = cmd.get_about().unwrap_or_default(); - let h_w = h.display_width() + display_width(spec_vals); - let taken = longest + TAB_WIDTH * 2; - 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: StyledStr, next_line_help: bool, longest: usize) { - self.writer.push_str(TAB); - self.writer.push_styled(&sc_str); - if !next_line_help { - let width = sc_str.display_width(); - let padding = longest + TAB_WIDTH - width; - self.write_padding(padding); - } - } -} - -const NEXT_LINE_INDENT: &str = " "; - -type ArgSortKey = fn(arg: &Arg) -> (usize, String); - -fn positional_sort_key(arg: &Arg) -> (usize, String) { - (arg.get_index().unwrap_or(0), String::new()) -} - -fn option_sort_key(arg: &Arg) -> (usize, String) { - // 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.get_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.get_long() { - x.to_string() - } else { - let mut s = '{'.to_string(); - s.push_str(arg.get_id().as_str()); - s - }; - (arg.get_display_order(), key) -} - -pub(crate) fn dimensions() -> (Option<usize>, Option<usize>) { - #[cfg(not(feature = "wrap_help"))] - return (None, None); - - #[cfg(feature = "wrap_help")] - terminal_size::terminal_size() - .map(|(w, h)| (Some(w.0.into()), Some(h.0.into()))) - .unwrap_or_else(|| (parse_env("COLUMNS"), parse_env("LINES"))) -} - -#[cfg(feature = "wrap_help")] -fn parse_env(var: &str) -> Option<usize> { - some!(some!(std::env::var_os(var)).to_str()) - .parse::<usize>() - .ok() -} - -fn should_show_arg(use_long: bool, arg: &Arg) -> bool { - debug!( - "should_show_arg: use_long={:?}, arg={}", - use_long, - arg.get_id() - ); - 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 longest_filter(arg: &Arg) -> bool { - arg.is_takes_value_set() || arg.get_long().is_some() || arg.get_short().is_none() -} - -#[cfg(test)] -mod test { - #[test] - #[cfg(feature = "wrap_help")] - fn wrap_help_last_word() { - use super::*; - - let help = String::from("foo bar baz"); - assert_eq!(wrap(&help, 5), "foo\nbar\nbaz"); - } - - #[test] - #[cfg(feature = "unicode")] - fn display_width_handles_non_ascii() { - use super::*; - - // 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] - #[cfg(feature = "unicode")] - fn display_width_handles_emojis() { - use super::*; - - 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_builder/src/output/mod.rs b/vendor/clap_builder/src/output/mod.rs deleted file mode 100644 index b358711..0000000 --- a/vendor/clap_builder/src/output/mod.rs +++ /dev/null @@ -1,23 +0,0 @@ -mod help; -#[cfg(feature = "help")] -mod help_template; -mod usage; - -pub(crate) mod fmt; -#[cfg(feature = "help")] -pub(crate) mod textwrap; - -pub(crate) use self::help::write_help; -#[cfg(feature = "help")] -pub(crate) use self::help_template::AutoHelp; -#[cfg(feature = "help")] -pub(crate) use self::help_template::HelpTemplate; -#[cfg(feature = "help")] -pub(crate) use self::textwrap::core::display_width; -#[cfg(feature = "help")] -pub(crate) use self::textwrap::wrap; -pub(crate) use self::usage::Usage; - -pub(crate) const TAB: &str = " "; -#[cfg(feature = "help")] -pub(crate) const TAB_WIDTH: usize = TAB.len(); diff --git a/vendor/clap_builder/src/output/textwrap/core.rs b/vendor/clap_builder/src/output/textwrap/core.rs deleted file mode 100644 index 2f6004c..0000000 --- a/vendor/clap_builder/src/output/textwrap/core.rs +++ /dev/null @@ -1,158 +0,0 @@ -/// Compute the display width of `text` -/// -/// # Examples -/// -/// **Note:** When the `unicode` Cargo feature is disabled, all characters are presumed to take up -/// 1 width. With the feature enabled, function will correctly deal with [combining characters] in -/// their decomposed form (see [Unicode equivalence]). -/// -/// An example of a decomposed character is “é”, which can be decomposed into: “e” followed by a -/// combining acute accent: “◌́”. Without the `unicode` Cargo feature, every `char` has a width of -/// 1. This includes the combining accent: -/// -/// ## Emojis and CJK Characters -/// -/// Characters such as emojis and [CJK characters] used in the -/// Chinese, Japanese, and Korean languages are seen as double-width, -/// even if the `unicode-width` feature is disabled: -/// -/// # Limitations -/// -/// The displayed width of a string cannot always be computed from the -/// string alone. This is because the width depends on the rendering -/// engine used. This is particularly visible with [emoji modifier -/// sequences] where a base emoji is modified with, e.g., skin tone or -/// hair color modifiers. It is up to the rendering engine to detect -/// this and to produce a suitable emoji. -/// -/// A simple example is “❤️”, which consists of “❤” (U+2764: Black -/// Heart Symbol) followed by U+FE0F (Variation Selector-16). By -/// itself, “❤” is a black heart, but if you follow it with the -/// variant selector, you may get a wider red heart. -/// -/// A more complex example would be “👨🦰” which should depict a man -/// with red hair. Here the computed width is too large — and the -/// width differs depending on the use of the `unicode-width` feature: -/// -/// This happens because the grapheme consists of three code points: -/// “👨” (U+1F468: Man), Zero Width Joiner (U+200D), and “🦰” -/// (U+1F9B0: Red Hair). You can see them above in the test. With -/// `unicode-width` enabled, the ZWJ is correctly seen as having zero -/// width, without it is counted as a double-width character. -/// -/// ## Terminal Support -/// -/// Modern browsers typically do a great job at combining characters -/// as shown above, but terminals often struggle more. As an example, -/// Gnome Terminal version 3.38.1, shows “❤️” as a big red heart, but -/// shows "👨🦰" as “👨🦰”. -/// -/// [combining characters]: https://en.wikipedia.org/wiki/Combining_character -/// [Unicode equivalence]: https://en.wikipedia.org/wiki/Unicode_equivalence -/// [CJK characters]: https://en.wikipedia.org/wiki/CJK_characters -/// [emoji modifier sequences]: https://unicode.org/emoji/charts/full-emoji-modifiers.html -#[inline(never)] -pub(crate) fn display_width(text: &str) -> usize { - let mut width = 0; - - let mut control_sequence = false; - let control_terminate: char = 'm'; - - for ch in text.chars() { - if ch.is_ascii_control() { - control_sequence = true; - } else if control_sequence && ch == control_terminate { - control_sequence = false; - continue; - } - - if !control_sequence { - width += ch_width(ch); - } - } - width -} - -#[cfg(feature = "unicode")] -fn ch_width(ch: char) -> usize { - unicode_width::UnicodeWidthChar::width(ch).unwrap_or(0) -} - -#[cfg(not(feature = "unicode"))] -fn ch_width(_: char) -> usize { - 1 -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "unicode")] - use unicode_width::UnicodeWidthChar; - - #[test] - fn emojis_have_correct_width() { - use unic_emoji_char::is_emoji; - - // Emojis in the Basic Latin (ASCII) and Latin-1 Supplement - // blocks all have a width of 1 column. This includes - // characters such as '#' and '©'. - for ch in '\u{1}'..'\u{FF}' { - if is_emoji(ch) { - let desc = format!("{:?} U+{:04X}", ch, ch as u32); - - #[cfg(feature = "unicode")] - assert_eq!(ch.width().unwrap(), 1, "char: {desc}"); - - #[cfg(not(feature = "unicode"))] - assert_eq!(ch_width(ch), 1, "char: {desc}"); - } - } - - // Emojis in the remaining blocks of the Basic Multilingual - // Plane (BMP), in the Supplementary Multilingual Plane (SMP), - // and in the Supplementary Ideographic Plane (SIP), are all 1 - // or 2 columns wide when unicode-width is used, and always 2 - // columns wide otherwise. This includes all of our favorite - // emojis such as 😊. - for ch in '\u{FF}'..'\u{2FFFF}' { - if is_emoji(ch) { - let desc = format!("{:?} U+{:04X}", ch, ch as u32); - - #[cfg(feature = "unicode")] - assert!(ch.width().unwrap() <= 2, "char: {desc}"); - - #[cfg(not(feature = "unicode"))] - assert_eq!(ch_width(ch), 1, "char: {desc}"); - } - } - - // The remaining planes contain almost no assigned code points - // and thus also no emojis. - } - - #[test] - #[cfg(feature = "unicode")] - fn display_width_works() { - assert_eq!("Café Plain".len(), 11); // “é” is two bytes - assert_eq!(display_width("Café Plain"), 10); - } - - #[test] - #[cfg(feature = "unicode")] - fn display_width_narrow_emojis() { - assert_eq!(display_width("⁉"), 1); - } - - #[test] - #[cfg(feature = "unicode")] - fn display_width_narrow_emojis_variant_selector() { - assert_eq!(display_width("⁉\u{fe0f}"), 1); - } - - #[test] - #[cfg(feature = "unicode")] - fn display_width_emojis() { - assert_eq!(display_width("😂😭🥺🤣✨😍🙏🥰😊🔥"), 20); - } -} diff --git a/vendor/clap_builder/src/output/textwrap/mod.rs b/vendor/clap_builder/src/output/textwrap/mod.rs deleted file mode 100644 index fe8139f..0000000 --- a/vendor/clap_builder/src/output/textwrap/mod.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Fork of `textwrap` crate -//! -//! Benefits of forking: -//! - Pull in only what we need rather than relying on the compiler to remove what we don't need -//! - `LineWrapper` is able to incrementally wrap which will help with `StyledStr - -pub(crate) mod core; -#[cfg(feature = "wrap_help")] -pub(crate) mod word_separators; -#[cfg(feature = "wrap_help")] -pub(crate) mod wrap_algorithms; - -#[cfg(feature = "wrap_help")] -pub(crate) fn wrap(content: &str, hard_width: usize) -> String { - let mut wrapper = wrap_algorithms::LineWrapper::new(hard_width); - let mut total = Vec::new(); - for line in content.split_inclusive('\n') { - wrapper.reset(); - let line = word_separators::find_words_ascii_space(line).collect::<Vec<_>>(); - total.extend(wrapper.wrap(line)); - } - total.join("") -} - -#[cfg(not(feature = "wrap_help"))] -pub(crate) fn wrap(content: &str, _hard_width: usize) -> String { - content.to_owned() -} - -#[cfg(test)] -#[cfg(feature = "wrap_help")] -mod test { - /// Compatibility shim to keep textwrap's tests - fn wrap(content: &str, hard_width: usize) -> Vec<String> { - super::wrap(content, hard_width) - .trim_end() - .split('\n') - .map(|s| s.to_owned()) - .collect::<Vec<_>>() - } - - #[test] - fn no_wrap() { - assert_eq!(wrap("foo", 10), vec!["foo"]); - } - - #[test] - fn wrap_simple() { - assert_eq!(wrap("foo bar baz", 5), vec!["foo", "bar", "baz"]); - } - - #[test] - fn to_be_or_not() { - assert_eq!( - wrap("To be, or not to be, that is the question.", 10), - vec!["To be, or", "not to be,", "that is", "the", "question."] - ); - } - - #[test] - fn multiple_words_on_first_line() { - assert_eq!(wrap("foo bar baz", 10), vec!["foo bar", "baz"]); - } - - #[test] - fn long_word() { - assert_eq!(wrap("foo", 0), vec!["foo"]); - } - - #[test] - fn long_words() { - assert_eq!(wrap("foo bar", 0), vec!["foo", "bar"]); - } - - #[test] - fn max_width() { - assert_eq!(wrap("foo bar", usize::MAX), vec!["foo bar"]); - - let text = "Hello there! This is some English text. \ - It should not be wrapped given the extents below."; - assert_eq!(wrap(text, usize::MAX), vec![text]); - } - - #[test] - fn leading_whitespace() { - assert_eq!(wrap(" foo bar", 6), vec![" foo", " bar"]); - } - - #[test] - fn leading_whitespace_empty_first_line() { - // If there is no space for the first word, the first line - // will be empty. This is because the string is split into - // words like [" ", "foobar ", "baz"], which puts "foobar " on - // the second line. We never output trailing whitespace - assert_eq!(wrap(" foobar baz", 6), vec!["", " foobar", " baz"]); - } - - #[test] - fn trailing_whitespace() { - // Whitespace is only significant inside a line. After a line - // gets too long and is broken, the first word starts in - // column zero and is not indented. - assert_eq!(wrap("foo bar baz ", 5), vec!["foo", "bar", "baz"]); - } - - #[test] - fn issue_99() { - // We did not reset the in_whitespace flag correctly and did - // not handle single-character words after a line break. - assert_eq!( - wrap("aaabbbccc x yyyzzzwww", 9), - vec!["aaabbbccc", "x", "yyyzzzwww"] - ); - } - - #[test] - fn issue_129() { - // The dash is an em-dash which takes up four bytes. We used - // to panic since we tried to index into the character. - assert_eq!(wrap("x – x", 1), vec!["x", "–", "x"]); - } -} diff --git a/vendor/clap_builder/src/output/textwrap/word_separators.rs b/vendor/clap_builder/src/output/textwrap/word_separators.rs deleted file mode 100644 index cb8250b..0000000 --- a/vendor/clap_builder/src/output/textwrap/word_separators.rs +++ /dev/null @@ -1,92 +0,0 @@ -pub(crate) fn find_words_ascii_space(line: &str) -> impl Iterator<Item = &'_ str> + '_ { - let mut start = 0; - let mut in_whitespace = false; - let mut char_indices = line.char_indices(); - - std::iter::from_fn(move || { - for (idx, ch) in char_indices.by_ref() { - let next_whitespace = ch == ' '; - if in_whitespace && !next_whitespace { - let word = &line[start..idx]; - start = idx; - in_whitespace = next_whitespace; - return Some(word); - } - - in_whitespace = next_whitespace; - } - - if start < line.len() { - let word = &line[start..]; - start = line.len(); - return Some(word); - } - - None - }) -} - -#[cfg(test)] -mod tests { - use super::*; - - macro_rules! test_find_words { - ($ascii_name:ident, - $([ $line:expr, $ascii_words:expr ]),+) => { - #[test] - fn $ascii_name() { - $( - let expected_words: Vec<&str> = $ascii_words.to_vec(); - let actual_words = find_words_ascii_space($line) - .collect::<Vec<_>>(); - assert_eq!(actual_words, expected_words, "Line: {:?}", $line); - )+ - } - }; - } - - test_find_words!(ascii_space_empty, ["", []]); - - test_find_words!(ascii_single_word, ["foo", ["foo"]]); - - test_find_words!(ascii_two_words, ["foo bar", ["foo ", "bar"]]); - - test_find_words!( - ascii_multiple_words, - ["foo bar", ["foo ", "bar"]], - ["x y z", ["x ", "y ", "z"]] - ); - - test_find_words!(ascii_only_whitespace, [" ", [" "]], [" ", [" "]]); - - test_find_words!( - ascii_inter_word_whitespace, - ["foo bar", ["foo ", "bar"]] - ); - - test_find_words!(ascii_trailing_whitespace, ["foo ", ["foo "]]); - - test_find_words!(ascii_leading_whitespace, [" foo", [" ", "foo"]]); - - test_find_words!( - ascii_multi_column_char, - ["\u{1f920}", ["\u{1f920}"]] // cowboy emoji 🤠 - ); - - test_find_words!( - ascii_hyphens, - ["foo-bar", ["foo-bar"]], - ["foo- bar", ["foo- ", "bar"]], - ["foo - bar", ["foo ", "- ", "bar"]], - ["foo -bar", ["foo ", "-bar"]] - ); - - test_find_words!(ascii_newline, ["foo\nbar", ["foo\nbar"]]); - - test_find_words!(ascii_tab, ["foo\tbar", ["foo\tbar"]]); - - test_find_words!( - ascii_non_breaking_space, - ["foo\u{00A0}bar", ["foo\u{00A0}bar"]] - ); -} diff --git a/vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs b/vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs deleted file mode 100644 index 34b4fd2..0000000 --- a/vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::core::display_width; - -#[derive(Debug)] -pub(crate) struct LineWrapper<'w> { - hard_width: usize, - line_width: usize, - carryover: Option<&'w str>, -} - -impl<'w> LineWrapper<'w> { - pub(crate) fn new(hard_width: usize) -> Self { - Self { - hard_width, - line_width: 0, - carryover: None, - } - } - - pub(crate) fn reset(&mut self) { - self.line_width = 0; - self.carryover = None; - } - - pub(crate) fn wrap(&mut self, mut words: Vec<&'w str>) -> Vec<&'w str> { - if self.carryover.is_none() { - if let Some(word) = words.first() { - if word.trim().is_empty() { - self.carryover = Some(*word); - } else { - self.carryover = Some(""); - } - } - } - - let mut i = 0; - while i < words.len() { - let word = &words[i]; - let trimmed = word.trim_end(); - let word_width = display_width(trimmed); - let trimmed_delta = word.len() - trimmed.len(); - if i != 0 && self.hard_width < self.line_width + word_width { - if 0 < i { - let last = i - 1; - let trimmed = words[last].trim_end(); - words[last] = trimmed; - } - - self.line_width = 0; - words.insert(i, "\n"); - i += 1; - if let Some(carryover) = self.carryover { - words.insert(i, carryover); - self.line_width += carryover.len(); - i += 1; - } - } - self.line_width += word_width + trimmed_delta; - - i += 1; - } - words - } -} diff --git a/vendor/clap_builder/src/output/usage.rs b/vendor/clap_builder/src/output/usage.rs deleted file mode 100644 index d75b704..0000000 --- a/vendor/clap_builder/src/output/usage.rs +++ /dev/null @@ -1,529 +0,0 @@ -#![cfg_attr(not(feature = "usage"), allow(unused_imports))] -#![cfg_attr(not(feature = "usage"), allow(unused_variables))] -#![cfg_attr(not(feature = "usage"), allow(clippy::manual_map))] -#![cfg_attr(not(feature = "usage"), allow(dead_code))] - -// Internal -use crate::builder::ArgAction; -use crate::builder::StyledStr; -use crate::builder::Styles; -use crate::builder::{ArgPredicate, Command}; -use crate::parser::ArgMatcher; -use crate::util::ChildGraph; -use crate::util::FlatSet; -use crate::util::Id; - -static DEFAULT_SUB_VALUE_NAME: &str = "COMMAND"; -const USAGE_SEP: &str = "\n "; - -pub(crate) struct Usage<'cmd> { - cmd: &'cmd Command, - styles: &'cmd Styles, - required: Option<&'cmd ChildGraph<Id>>, -} - -impl<'cmd> Usage<'cmd> { - pub(crate) fn new(cmd: &'cmd Command) -> Self { - Usage { - cmd, - styles: cmd.get_styles(), - 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]) -> Option<StyledStr> { - debug!("Usage::create_usage_with_title"); - use std::fmt::Write as _; - let mut styled = StyledStr::new(); - let _ = write!( - styled, - "{}Usage:{} ", - self.styles.get_usage().render(), - self.styles.get_usage().render_reset() - ); - if self.write_usage_no_title(&mut styled, used) { - styled.trim_end(); - } else { - return None; - } - debug!("Usage::create_usage_with_title: usage={styled}"); - Some(styled) - } - - // 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]) -> Option<StyledStr> { - debug!("Usage::create_usage_no_title"); - - let mut styled = StyledStr::new(); - if self.write_usage_no_title(&mut styled, used) { - styled.trim_end(); - debug!("Usage::create_usage_no_title: usage={styled}"); - Some(styled) - } else { - None - } - } - - // Creates a usage string (*without title*) if one was not provided by the user manually. - fn write_usage_no_title(&self, styled: &mut StyledStr, used: &[Id]) -> bool { - debug!("Usage::create_usage_no_title"); - if let Some(u) = self.cmd.get_override_usage() { - styled.push_styled(u); - true - } else { - #[cfg(feature = "usage")] - { - if used.is_empty() { - self.write_help_usage(styled); - } else { - self.write_smart_usage(styled, used); - } - true - } - - #[cfg(not(feature = "usage"))] - { - false - } - } - } -} - -#[cfg(feature = "usage")] -impl<'cmd> Usage<'cmd> { - // Creates a usage string for display in help messages (i.e. not for errors) - fn write_help_usage(&self, styled: &mut StyledStr) { - debug!("Usage::write_help_usage"); - use std::fmt::Write; - - if self.cmd.has_visible_subcommands() && self.cmd.is_flatten_help_set() { - if !self.cmd.is_subcommand_required_set() - || self.cmd.is_args_conflicts_with_subcommands_set() - { - self.write_arg_usage(styled, &[], true); - styled.trim_end(); - let _ = write!(styled, "{}", USAGE_SEP); - } - let mut cmd = self.cmd.clone(); - cmd.build(); - for (i, sub) in cmd - .get_subcommands() - .filter(|c| !c.is_hide_set()) - .enumerate() - { - if i != 0 { - styled.trim_end(); - let _ = write!(styled, "{}", USAGE_SEP); - } - Usage::new(sub).write_usage_no_title(styled, &[]); - } - } else { - self.write_arg_usage(styled, &[], true); - self.write_subcommand_usage(styled); - } - } - - // Creates a context aware usage string, or "smart usage" from currently used - // args, and requirements - fn write_smart_usage(&self, styled: &mut StyledStr, used: &[Id]) { - debug!("Usage::create_smart_usage"); - use std::fmt::Write; - let placeholder = &self.styles.get_placeholder(); - - self.write_arg_usage(styled, used, true); - - if self.cmd.is_subcommand_required_set() { - let value_name = self - .cmd - .get_subcommand_value_name() - .unwrap_or(DEFAULT_SUB_VALUE_NAME); - let _ = write!( - styled, - "{}<{value_name}>{}", - placeholder.render(), - placeholder.render_reset() - ); - } - } - - fn write_arg_usage(&self, styled: &mut StyledStr, used: &[Id], incl_reqs: bool) { - debug!("Usage::write_arg_usage; incl_reqs={incl_reqs:?}"); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - let placeholder = &self.styles.get_placeholder(); - - let bin_name = self.cmd.get_usage_name_fallback(); - if !bin_name.is_empty() { - // the trim won't properly remove a leading space due to the formatting - let _ = write!( - styled, - "{}{bin_name}{} ", - literal.render(), - literal.render_reset() - ); - } - - if used.is_empty() && self.needs_options_tag() { - let _ = write!( - styled, - "{}[OPTIONS]{} ", - placeholder.render(), - placeholder.render_reset() - ); - } - - self.write_args(styled, used, !incl_reqs); - } - - fn write_subcommand_usage(&self, styled: &mut StyledStr) { - debug!("Usage::write_subcommand_usage"); - use std::fmt::Write as _; - - // incl_reqs is only false when this function is called recursively - if self.cmd.has_visible_subcommands() || self.cmd.is_allow_external_subcommands_set() { - let literal = &self.styles.get_literal(); - let placeholder = &self.styles.get_placeholder(); - let value_name = self - .cmd - .get_subcommand_value_name() - .unwrap_or(DEFAULT_SUB_VALUE_NAME); - if self.cmd.is_subcommand_negates_reqs_set() - || self.cmd.is_args_conflicts_with_subcommands_set() - { - styled.trim_end(); - let _ = write!(styled, "{}", USAGE_SEP); - if self.cmd.is_args_conflicts_with_subcommands_set() { - let bin_name = self.cmd.get_usage_name_fallback(); - // Short-circuit full usage creation since no args will be relevant - let _ = write!( - styled, - "{}{bin_name}{} ", - literal.render(), - literal.render_reset() - ); - } else { - self.write_arg_usage(styled, &[], false); - } - let _ = write!( - styled, - "{}<{value_name}>{}", - placeholder.render(), - placeholder.render_reset() - ); - } else if self.cmd.is_subcommand_required_set() { - let _ = write!( - styled, - "{}<{value_name}>{}", - placeholder.render(), - placeholder.render_reset() - ); - } else { - let _ = write!( - styled, - "{}[{value_name}]{}", - placeholder.render(), - placeholder.render_reset() - ); - } - } - } - - // 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.get_id()); - - // Don't print `[OPTIONS]` just for help or version - if f.get_long() == Some("help") || f.get_long() == Some("version") { - debug!("Usage::needs_options_tag:iter Option is built-in"); - continue; - } - match f.get_action() { - ArgAction::Set - | ArgAction::Append - | ArgAction::SetTrue - | ArgAction::SetFalse - | ArgAction::Count => {} - ArgAction::Help - | ArgAction::HelpShort - | ArgAction::HelpLong - | ArgAction::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.get_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 - pub(crate) fn write_args(&self, styled: &mut StyledStr, incls: &[Id], force_optional: bool) { - debug!("Usage::write_args: incls={incls:?}",); - use std::fmt::Write as _; - let literal = &self.styles.get_literal(); - - let required_owned; - let required = if let Some(required) = self.required { - required - } else { - required_owned = self.cmd.required_graph(); - &required_owned - }; - - let mut unrolled_reqs = Vec::new(); - for a in required.iter() { - let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> { - let required = match val { - ArgPredicate::Equals(_) => 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.push(aa); - } - // always include the required arg itself. it will not be enumerated - // by unroll_requirements_for_arg. - unrolled_reqs.push(a.clone()); - } - debug!("Usage::get_args: unrolled_reqs={unrolled_reqs:?}"); - - let mut required_groups_members = FlatSet::new(); - let mut required_groups = FlatSet::new(); - for req in unrolled_reqs.iter().chain(incls.iter()) { - if self.cmd.find_group(req).is_some() { - let group_members = self.cmd.unroll_args_in_group(req); - let elem = self.cmd.format_group(req); - required_groups.insert(elem); - required_groups_members.extend(group_members); - } else { - debug_assert!(self.cmd.find(req).is_some()); - } - } - - let mut required_opts = FlatSet::new(); - let mut required_positionals = Vec::new(); - for req in unrolled_reqs.iter().chain(incls.iter()) { - if let Some(arg) = self.cmd.find(req) { - if required_groups_members.contains(arg.get_id()) { - continue; - } - - let stylized = arg.stylized(self.styles, Some(!force_optional)); - if let Some(index) = arg.get_index() { - let new_len = index + 1; - if required_positionals.len() < new_len { - required_positionals.resize(new_len, None); - } - required_positionals[index] = Some(stylized); - } else { - required_opts.insert(stylized); - } - } else { - debug_assert!(self.cmd.find_group(req).is_some()); - } - } - - for pos in self.cmd.get_positionals() { - if pos.is_hide_set() { - continue; - } - if required_groups_members.contains(pos.get_id()) { - continue; - } - - let index = pos.get_index().unwrap(); - let new_len = index + 1; - if required_positionals.len() < new_len { - required_positionals.resize(new_len, None); - } - if required_positionals[index].is_some() { - if pos.is_last_set() { - let styled = required_positionals[index].take().unwrap(); - let mut new = StyledStr::new(); - let _ = write!(new, "{}--{} ", literal.render(), literal.render_reset()); - new.push_styled(&styled); - required_positionals[index] = Some(new); - } - } else { - let mut styled; - if pos.is_last_set() { - styled = StyledStr::new(); - let _ = write!(styled, "{}[--{} ", literal.render(), literal.render_reset()); - styled.push_styled(&pos.stylized(self.styles, Some(true))); - let _ = write!(styled, "{}]{}", literal.render(), literal.render_reset()); - } else { - styled = pos.stylized(self.styles, Some(false)); - } - required_positionals[index] = Some(styled); - } - if pos.is_last_set() && force_optional { - required_positionals[index] = None; - } - } - - if !force_optional { - for arg in required_opts { - styled.push_styled(&arg); - styled.push_str(" "); - } - for arg in required_groups { - styled.push_styled(&arg); - styled.push_str(" "); - } - } - for arg in required_positionals.into_iter().flatten() { - styled.push_styled(&arg); - styled.push_str(" "); - } - } - - pub(crate) fn get_required_usage_from( - &self, - incls: &[Id], - matcher: Option<&ArgMatcher>, - incl_last: bool, - ) -> Vec<StyledStr> { - debug!( - "Usage::get_required_usage_from: incls={:?}, matcher={:?}, incl_last={:?}", - incls, - matcher.is_some(), - incl_last - ); - - let required_owned; - let required = if let Some(required) = self.required { - required - } else { - required_owned = self.cmd.required_graph(); - &required_owned - }; - - let mut unrolled_reqs = Vec::new(); - 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.push(aa); - } - // always include the required arg itself. it will not be enumerated - // by unroll_requirements_for_arg. - unrolled_reqs.push(a.clone()); - } - debug!("Usage::get_required_usage_from: unrolled_reqs={unrolled_reqs:?}"); - - let mut required_groups_members = FlatSet::new(); - let mut required_groups = FlatSet::new(); - for req in unrolled_reqs.iter().chain(incls.iter()) { - if 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:{req:?} group is_present={is_present}"); - if is_present { - continue; - } - - let elem = self.cmd.format_group(req); - required_groups.insert(elem); - required_groups_members.extend(group_members); - } else { - debug_assert!(self.cmd.find(req).is_some(), "`{req}` must exist"); - } - } - - let mut required_opts = FlatSet::new(); - let mut required_positionals = Vec::new(); - for req in unrolled_reqs.iter().chain(incls.iter()) { - if let Some(arg) = self.cmd.find(req) { - if required_groups_members.contains(arg.get_id()) { - continue; - } - - let is_present = matcher - .map(|m| m.check_explicit(req, &ArgPredicate::IsPresent)) - .unwrap_or(false); - debug!("Usage::get_required_usage_from:iter:{req:?} arg is_present={is_present}"); - if is_present { - continue; - } - - let stylized = arg.stylized(self.styles, Some(true)); - if let Some(index) = arg.get_index() { - if !arg.is_last_set() || incl_last { - let new_len = index + 1; - if required_positionals.len() < new_len { - required_positionals.resize(new_len, None); - } - required_positionals[index] = Some(stylized); - } - } else { - required_opts.insert(stylized); - } - } else { - debug_assert!(self.cmd.find_group(req).is_some()); - } - } - - let mut ret_val = Vec::new(); - ret_val.extend(required_opts); - ret_val.extend(required_groups); - for pos in required_positionals.into_iter().flatten() { - ret_val.push(pos); - } - - debug!("Usage::get_required_usage_from: ret_val={ret_val:?}"); - ret_val - } -} |