summaryrefslogtreecommitdiffstats
path: root/vendor/clap/src/output
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap/src/output')
-rw-r--r--vendor/clap/src/output/fmt.rs90
-rw-r--r--vendor/clap/src/output/help.rs43
-rw-r--r--vendor/clap/src/output/help_template.rs1065
-rw-r--r--vendor/clap/src/output/mod.rs23
-rw-r--r--vendor/clap/src/output/textwrap/core.rs158
-rw-r--r--vendor/clap/src/output/textwrap/mod.rs122
-rw-r--r--vendor/clap/src/output/textwrap/word_separators.rs91
-rw-r--r--vendor/clap/src/output/textwrap/wrap_algorithms.rs44
-rw-r--r--vendor/clap/src/output/usage.rs441
9 files changed, 2077 insertions, 0 deletions
diff --git a/vendor/clap/src/output/fmt.rs b/vendor/clap/src/output/fmt.rs
new file mode 100644
index 000000000..b5d0153f1
--- /dev/null
+++ b/vendor/clap/src/output/fmt.rs
@@ -0,0 +1,90 @@
+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<()> {
+ use termcolor::{BufferWriter, ColorChoice as DepColorChoice};
+
+ 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();
+ ok!(self.content.write_colored(&mut buffer));
+ writer.print(&buffer)
+ }
+
+ #[cfg(not(feature = "color"))]
+ pub(crate) fn print(&self) -> std::io::Result<()> {
+ use std::io::Write;
+
+ // [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 std::fmt::Display for Colorizer {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+ self.content.fmt(f)
+ }
+}
+
+#[cfg(feature = "color")]
+fn is_a_tty(stream: Stream) -> bool {
+ use is_terminal::IsTerminal;
+ match stream {
+ Stream::Stdout => std::io::stdout().is_terminal(),
+ Stream::Stderr => std::io::stderr().is_terminal(),
+ }
+}
diff --git a/vendor/clap/src/output/help.rs b/vendor/clap/src/output/help.rs
new file mode 100644
index 000000000..4e4fdbfdc
--- /dev/null
+++ b/vendor/clap/src/output/help.rs
@@ -0,0 +1,43 @@
+#![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.extend(h.iter());
+ } else {
+ #[cfg(feature = "help")]
+ {
+ use super::AutoHelp;
+ use super::HelpTemplate;
+ if let Some(tmpl) = cmd.get_help_template() {
+ for (style, content) in tmpl.iter() {
+ if style.is_none() {
+ HelpTemplate::new(writer, cmd, usage, use_long)
+ .write_templated_help(content);
+ } else {
+ writer.stylize(style, content);
+ }
+ }
+ } 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 extra lines caused by book keeping
+ writer.trim();
+ // Ensure there is still a trailing newline
+ writer.none("\n");
+}
diff --git a/vendor/clap/src/output/help_template.rs b/vendor/clap/src/output/help_template.rs
new file mode 100644
index 000000000..6fe9db1b4
--- /dev/null
+++ b/vendor/clap/src/output/help_template.rs
@@ -0,0 +1,1065 @@
+// 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::{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,
+ 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 = 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)
+ }
+ };
+ let next_line_help = cmd.is_next_line_help_set();
+
+ HelpTemplate {
+ writer,
+ cmd,
+ usage,
+ next_line_help,
+ term_w,
+ use_long,
+ }
+ }
+
+ /// 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");
+
+ let mut parts = template.split('{');
+ if let Some(first) = parts.next() {
+ self.none(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" => {
+ self.header("Usage:");
+ }
+ "usage" => {
+ self.writer.extend(
+ self.usage
+ .create_usage_no_title(&[])
+ .unwrap_or_default()
+ .into_iter(),
+ );
+ }
+ "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.none(TAB);
+ }
+ "after-help" => {
+ self.write_after_help();
+ }
+ "before-help" => {
+ self.write_before_help();
+ }
+ _ => {
+ self.none("{");
+ self.none(tag);
+ self.none("}");
+ }
+ }
+ self.none(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.none(&display_name);
+ }
+
+ /// Writes binary name of a Parser Object to the wrapped stream.
+ 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.none(&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.none(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.none("\n");
+ }
+ self.none(wrap(author, self.term_w));
+ if after_new_line {
+ self.none("\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.none("\n");
+ }
+ let mut output = output.clone();
+ replace_newline_var(&mut output);
+ output.wrap(self.term_w);
+ self.writer.extend(output.into_iter());
+ if after_new_line {
+ self.none("\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();
+ replace_newline_var(&mut output);
+ output.wrap(self.term_w);
+ self.writer.extend(output.into_iter());
+ self.none("\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.none("\n\n");
+ let mut output = output.clone();
+ replace_newline_var(&mut output);
+ output.wrap(self.term_w);
+ self.writer.extend(output.into_iter());
+ }
+ }
+}
+
+/// 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");
+ 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 mut first = true;
+
+ if subcmds {
+ if !first {
+ self.none("\n\n");
+ }
+ first = false;
+ let default_help_heading = Str::from("Commands");
+ self.header(
+ self.cmd
+ .get_subcommand_help_heading()
+ .unwrap_or(&default_help_heading),
+ );
+ self.header(":\n");
+
+ self.write_subcommands(self.cmd);
+ }
+
+ if !pos.is_empty() {
+ if !first {
+ self.none("\n\n");
+ }
+ first = false;
+ // Write positional args if any
+ self.header("Arguments:\n");
+ self.write_args(&pos, "Arguments", positional_sort_key);
+ }
+
+ if !non_pos.is_empty() {
+ if !first {
+ self.none("\n\n");
+ }
+ first = false;
+ self.header("Options:\n");
+ 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.none("\n\n");
+ }
+ first = false;
+ self.header(format!("{}:\n", heading));
+ self.write_args(&args, heading, option_sort_key);
+ }
+ }
+ }
+ }
+ /// 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.none("\n");
+ if next_line_help && self.use_long {
+ self.none("\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.none(TAB);
+ self.short(arg);
+ self.long(arg);
+ self.writer.extend(arg.stylize_arg_suffix(None).into_iter());
+ 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");
+
+ if let Some(s) = arg.get_short() {
+ self.literal(format!("-{}", s));
+ } else if arg.get_long().is_some() {
+ self.none(" ");
+ }
+ }
+
+ /// Writes argument's long command to the wrapped stream.
+ fn long(&mut self, arg: &Arg) {
+ debug!("HelpTemplate::long");
+ if let Some(long) = arg.get_long() {
+ if arg.get_short().is_some() {
+ self.none(", ");
+ }
+ self.literal(format!("--{}", long));
+ }
+ }
+
+ /// 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
+ );
+ 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");
+ } 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={}, spaces={}",
+ self_len, spcs
+ );
+
+ self.spaces(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={}, spaces={}",
+ self_len, spcs
+ );
+
+ self.spaces(spcs);
+ }
+ }
+
+ /// 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");
+
+ // Is help on next line, if so then indent
+ if next_line_help {
+ debug!("HelpTemplate::help: Next Line...{:?}", next_line_help);
+ self.none("\n");
+ self.none(TAB);
+ self.none(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();
+ replace_newline_var(&mut help);
+ if !spec_vals.is_empty() {
+ if !help.is_empty() {
+ let sep = if self.use_long && arg.is_some() {
+ "\n\n"
+ } else {
+ " "
+ };
+ help.none(sep);
+ }
+ help.none(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.extend(help.into_iter());
+ if let Some(arg) = arg {
+ const DASH_SPACE: usize = "- ".len();
+ const COLON_SPACE: usize = ": ".len();
+ let possible_vals = arg.get_possible_values();
+ if self.use_long
+ && !arg.is_hide_possible_values_set()
+ && possible_vals.iter().any(PossibleValue::should_show_help)
+ {
+ debug!(
+ "HelpTemplate::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(|h| h.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 trailing_indent = if possible_value_new_line {
+ spaces + DASH_SPACE
+ } else {
+ spaces + longest + DASH_SPACE + COLON_SPACE
+ };
+ let trailing_indent = self.get_spaces(trailing_indent);
+
+ for pv in possible_vals.iter().filter(|pv| !pv.is_hide_set()) {
+ self.none("\n");
+ self.spaces(spaces);
+ self.none("- ");
+ self.literal(pv.get_name());
+ if let Some(help) = pv.get_help() {
+ debug!("HelpTemplate::help: Possible Value help");
+
+ if possible_value_new_line {
+ self.none(":\n");
+ self.spaces(trailing_indent.len());
+ } else {
+ self.none(": ");
+ // To align help messages
+ self.spaces(longest - display_width(pv.get_name()));
+ }
+
+ let avail_chars = if self.term_w > trailing_indent.len() {
+ self.term_w - trailing_indent.len()
+ } else {
+ usize::MAX
+ };
+
+ let mut help = help.clone();
+ replace_newline_var(&mut help);
+ help.wrap(avail_chars);
+ help.indent("", &trailing_indent);
+ self.writer.extend(help.into_iter());
+ }
+ }
+ }
+ }
+ }
+
+ /// 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));
+ }
+
+ let possible_vals = a.get_possible_values();
+ if !(a.is_hide_possible_values_set()
+ || possible_vals.is_empty()
+ || self.use_long && possible_vals.iter().any(PossibleValue::should_show_help))
+ {
+ 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 header<T: Into<String>>(&mut self, msg: T) {
+ self.writer.header(msg);
+ }
+
+ fn literal<T: Into<String>>(&mut self, msg: T) {
+ self.writer.literal(msg);
+ }
+
+ fn none<T: Into<String>>(&mut self, msg: T) {
+ self.writer.none(msg);
+ }
+
+ fn get_spaces(&self, n: usize) -> String {
+ " ".repeat(n)
+ }
+
+ fn spaces(&mut self, n: usize) {
+ self.none(self.get_spaces(n));
+ }
+}
+
+/// Subcommand handling
+impl<'cmd, 'writer> HelpTemplate<'cmd, 'writer> {
+ /// Writes help for subcommands of a Parser Object to the wrapped stream.
+ fn write_subcommands(&mut self, cmd: &Command) {
+ debug!("HelpTemplate::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 styled = StyledStr::new();
+ styled.literal(subcommand.get_name());
+ if let Some(short) = subcommand.get_short_flag() {
+ styled.none(", ");
+ styled.literal(format!("-{}", short));
+ }
+ if let Some(long) = subcommand.get_long_flag() {
+ styled.none(", ");
+ styled.literal(format!("--{}", long));
+ }
+ 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);
+
+ 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);
+ }
+ }
+
+ /// 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 {
+ if self.next_line_help | self.use_long {
+ // 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) {
+ let width = sc_str.display_width();
+
+ self.none(TAB);
+ self.writer.extend(sc_str.into_iter());
+ if !next_line_help {
+ self.spaces(longest + TAB_WIDTH - width);
+ }
+ }
+}
+
+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 replace_newline_var(styled: &mut StyledStr) {
+ for (_, content) in styled.iter_mut() {
+ *content = content.replace("{n}", "\n");
+ }
+}
+
+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/src/output/mod.rs b/vendor/clap/src/output/mod.rs
new file mode 100644
index 000000000..b3587116f
--- /dev/null
+++ b/vendor/clap/src/output/mod.rs
@@ -0,0 +1,23 @@
+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/src/output/textwrap/core.rs b/vendor/clap/src/output/textwrap/core.rs
new file mode 100644
index 000000000..b890c6c7b
--- /dev/null
+++ b/vendor/clap/src/output/textwrap/core.rs
@@ -0,0 +1,158 @@
+/// 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/src/output/textwrap/mod.rs b/vendor/clap/src/output/textwrap/mod.rs
new file mode 100644
index 000000000..d14d3fe7f
--- /dev/null
+++ b/vendor/clap/src/output/textwrap/mod.rs
@@ -0,0 +1,122 @@
+//! 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/src/output/textwrap/word_separators.rs b/vendor/clap/src/output/textwrap/word_separators.rs
new file mode 100644
index 000000000..ac09231d5
--- /dev/null
+++ b/vendor/clap/src/output/textwrap/word_separators.rs
@@ -0,0 +1,91 @@
+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() {
+ if in_whitespace && ch != ' ' {
+ let word = &line[start..idx];
+ start = idx;
+ in_whitespace = ch == ' ';
+ return Some(word);
+ }
+
+ in_whitespace = ch == ' ';
+ }
+
+ 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/src/output/textwrap/wrap_algorithms.rs b/vendor/clap/src/output/textwrap/wrap_algorithms.rs
new file mode 100644
index 000000000..019cc04ff
--- /dev/null
+++ b/vendor/clap/src/output/textwrap/wrap_algorithms.rs
@@ -0,0 +1,44 @@
+use super::core::display_width;
+
+#[derive(Debug)]
+pub(crate) struct LineWrapper {
+ line_width: usize,
+ hard_width: usize,
+}
+
+impl LineWrapper {
+ pub(crate) fn new(hard_width: usize) -> Self {
+ Self {
+ line_width: 0,
+ hard_width,
+ }
+ }
+
+ pub(crate) fn reset(&mut self) {
+ self.line_width = 0;
+ }
+
+ pub(crate) fn wrap<'w>(&mut self, mut words: Vec<&'w str>) -> Vec<&'w str> {
+ 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;
+ }
+ words.insert(i, "\n");
+ i += 1;
+ self.reset();
+ }
+ self.line_width += word_width + trimmed_delta;
+
+ i += 1;
+ }
+ words
+ }
+}
diff --git a/vendor/clap/src/output/usage.rs b/vendor/clap/src/output/usage.rs
new file mode 100644
index 000000000..145fce12d
--- /dev/null
+++ b/vendor/clap/src/output/usage.rs
@@ -0,0 +1,441 @@
+#![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::StyledStr;
+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";
+
+pub(crate) struct Usage<'cmd> {
+ cmd: &'cmd Command,
+ required: Option<&'cmd ChildGraph<Id>>,
+}
+
+impl<'cmd> Usage<'cmd> {
+ pub(crate) fn new(cmd: &'cmd Command) -> 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]) -> Option<StyledStr> {
+ debug!("Usage::create_usage_with_title");
+ let usage = some!(self.create_usage_no_title(used));
+
+ let mut styled = StyledStr::new();
+ styled.header("Usage:");
+ styled.none(" ");
+ styled.extend(usage.into_iter());
+ 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");
+ if let Some(u) = self.cmd.get_override_usage() {
+ Some(u.clone())
+ } else {
+ #[cfg(feature = "usage")]
+ {
+ if used.is_empty() {
+ Some(self.create_help_usage(true))
+ } else {
+ Some(self.create_smart_usage(used))
+ }
+ }
+
+ #[cfg(not(feature = "usage"))]
+ {
+ None
+ }
+ }
+ }
+}
+
+#[cfg(feature = "usage")]
+impl<'cmd> Usage<'cmd> {
+ // Creates a usage string for display in help messages (i.e. not for errors)
+ fn create_help_usage(&self, incl_reqs: bool) -> StyledStr {
+ debug!("Usage::create_help_usage; incl_reqs={:?}", incl_reqs);
+ let mut styled = StyledStr::new();
+ let name = self
+ .cmd
+ .get_usage_name()
+ .or_else(|| self.cmd.get_bin_name())
+ .unwrap_or_else(|| self.cmd.get_name());
+ styled.literal(name);
+
+ if self.needs_options_tag() {
+ styled.placeholder(" [OPTIONS]");
+ }
+
+ self.write_args(&[], !incl_reqs, &mut styled);
+
+ // 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(DEFAULT_SUB_VALUE_NAME);
+ if self.cmd.is_subcommand_negates_reqs_set()
+ || self.cmd.is_args_conflicts_with_subcommands_set()
+ {
+ styled.none("\n");
+ styled.none(" ");
+ if self.cmd.is_args_conflicts_with_subcommands_set() {
+ // Short-circuit full usage creation since no args will be relevant
+ styled.literal(name);
+ } else {
+ styled.extend(self.create_help_usage(false).into_iter());
+ }
+ styled.placeholder(" <");
+ styled.placeholder(placeholder);
+ styled.placeholder(">");
+ } else if self.cmd.is_subcommand_required_set() {
+ styled.placeholder(" <");
+ styled.placeholder(placeholder);
+ styled.placeholder(">");
+ } else {
+ styled.placeholder(" [");
+ styled.placeholder(placeholder);
+ styled.placeholder("]");
+ }
+ }
+ styled.trim();
+ debug!("Usage::create_help_usage: usage={}", styled);
+ styled
+ }
+
+ // Creates a context aware usage string, or "smart usage" from currently used
+ // args, and requirements
+ fn create_smart_usage(&self, used: &[Id]) -> StyledStr {
+ debug!("Usage::create_smart_usage");
+ let mut styled = StyledStr::new();
+
+ styled.literal(
+ self.cmd
+ .get_usage_name()
+ .or_else(|| self.cmd.get_bin_name())
+ .unwrap_or_else(|| self.cmd.get_name()),
+ );
+
+ self.write_args(used, false, &mut styled);
+
+ if self.cmd.is_subcommand_required_set() {
+ styled.placeholder(" <");
+ styled.placeholder(
+ self.cmd
+ .get_subcommand_value_name()
+ .unwrap_or(DEFAULT_SUB_VALUE_NAME),
+ );
+ styled.placeholder(">");
+ }
+ styled
+ }
+
+ // 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;
+ }
+
+ 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, incls: &[Id], force_optional: bool, styled: &mut StyledStr) {
+ for required in self.get_args(incls, force_optional) {
+ styled.none(" ");
+ styled.extend(required.into_iter());
+ }
+ }
+
+ pub(crate) fn get_args(&self, incls: &[Id], force_optional: bool) -> Vec<StyledStr> {
+ debug!("Usage::get_args: incls={:?}", incls,);
+
+ 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(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();
+ new.literal("-- ");
+ new.extend(styled.into_iter());
+ required_positionals[index] = Some(new);
+ }
+ } else {
+ let mut styled;
+ if pos.is_last_set() {
+ styled = StyledStr::new();
+ styled.literal("[-- ");
+ styled.extend(pos.stylized(Some(true)).into_iter());
+ styled.literal("]");
+ } else {
+ styled = pos.stylized(Some(false));
+ }
+ required_positionals[index] = Some(styled);
+ }
+ if pos.is_last_set() && force_optional {
+ required_positionals[index] = None;
+ }
+ }
+
+ let mut ret_val = Vec::new();
+ if !force_optional {
+ 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_args: ret_val={:?}", ret_val);
+ ret_val
+ }
+
+ 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:{:?} group is_present={}",
+ req, 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());
+ }
+ }
+
+ 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:{:?} arg is_present={}",
+ req, is_present
+ );
+ if is_present {
+ continue;
+ }
+
+ let stylized = arg.stylized(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
+ }
+}