Initial vendor packages
Signed-off-by: Valentin Popov <valentin@popov.link>
This commit is contained in:
1
vendor/clap_builder/.cargo-checksum.json
vendored
Normal file
1
vendor/clap_builder/.cargo-checksum.json
vendored
Normal file
File diff suppressed because one or more lines are too long
139
vendor/clap_builder/Cargo.toml
vendored
Normal file
139
vendor/clap_builder/Cargo.toml
vendored
Normal file
@ -0,0 +1,139 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70.0"
|
||||
name = "clap_builder"
|
||||
version = "4.4.12"
|
||||
include = [
|
||||
"build.rs",
|
||||
"src/**/*",
|
||||
"Cargo.toml",
|
||||
"LICENSE*",
|
||||
"README.md",
|
||||
"benches/**/*",
|
||||
"examples/**/*",
|
||||
]
|
||||
description = "A simple to use, efficient, and full-featured Command Line Argument Parser"
|
||||
readme = "README.md"
|
||||
keywords = [
|
||||
"argument",
|
||||
"cli",
|
||||
"arg",
|
||||
"parser",
|
||||
"parse",
|
||||
]
|
||||
categories = ["command-line-interface"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/clap-rs/clap"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
cargo-args = [
|
||||
"-Zunstable-options",
|
||||
"-Zrustdoc-scrape-examples",
|
||||
]
|
||||
features = ["unstable-doc"]
|
||||
rustdoc-args = [
|
||||
"--cfg",
|
||||
"docsrs",
|
||||
]
|
||||
|
||||
[package.metadata.playground]
|
||||
features = ["unstable-doc"]
|
||||
|
||||
[package.metadata.release]
|
||||
dependent-version = "upgrade"
|
||||
shared-version = true
|
||||
tag-name = "v{{version}}"
|
||||
|
||||
[lib]
|
||||
bench = false
|
||||
|
||||
[dependencies.anstream]
|
||||
version = "0.6.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.anstyle]
|
||||
version = "1.0.0"
|
||||
|
||||
[dependencies.backtrace]
|
||||
version = "0.3.67"
|
||||
optional = true
|
||||
|
||||
[dependencies.clap_lex]
|
||||
version = "0.6.0"
|
||||
|
||||
[dependencies.strsim]
|
||||
version = "0.10.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.terminal_size]
|
||||
version = "0.3.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicase]
|
||||
version = "2.6.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.unicode-width]
|
||||
version = "0.1.9"
|
||||
optional = true
|
||||
|
||||
[dev-dependencies.color-print]
|
||||
version = "0.3.5"
|
||||
|
||||
[dev-dependencies.static_assertions]
|
||||
version = "1.1.0"
|
||||
|
||||
[dev-dependencies.unic-emoji-char]
|
||||
version = "0.9.0"
|
||||
|
||||
[features]
|
||||
cargo = []
|
||||
color = ["dep:anstream"]
|
||||
debug = ["dep:backtrace"]
|
||||
default = [
|
||||
"std",
|
||||
"color",
|
||||
"help",
|
||||
"usage",
|
||||
"error-context",
|
||||
"suggestions",
|
||||
]
|
||||
deprecated = []
|
||||
env = []
|
||||
error-context = []
|
||||
help = []
|
||||
std = ["anstyle/std"]
|
||||
string = []
|
||||
suggestions = [
|
||||
"dep:strsim",
|
||||
"error-context",
|
||||
]
|
||||
unicode = [
|
||||
"dep:unicode-width",
|
||||
"dep:unicase",
|
||||
]
|
||||
unstable-doc = [
|
||||
"cargo",
|
||||
"wrap_help",
|
||||
"env",
|
||||
"unicode",
|
||||
"string",
|
||||
]
|
||||
unstable-styles = ["color"]
|
||||
unstable-v5 = ["deprecated"]
|
||||
usage = []
|
||||
wrap_help = [
|
||||
"help",
|
||||
"dep:terminal_size",
|
||||
]
|
201
vendor/clap_builder/LICENSE-APACHE
vendored
Normal file
201
vendor/clap_builder/LICENSE-APACHE
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
21
vendor/clap_builder/LICENSE-MIT
vendored
Normal file
21
vendor/clap_builder/LICENSE-MIT
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2022 Kevin B. Knapp and Clap Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
24
vendor/clap_builder/README.md
vendored
Normal file
24
vendor/clap_builder/README.md
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# clap_builder
|
||||
|
||||
Builder implementation for clap.
|
||||
|
||||
[docs.rs](https://docs.rs/clap)
|
||||
- [Derive Tutorial](https://docs.rs/clap/latest/clap/_derive/_tutorial/index.html)
|
||||
- [Derive Reference](https://docs.rs/clap/latest/clap/_derive/index.html)
|
||||
|
||||
## License
|
||||
|
||||
Licensed under either of
|
||||
|
||||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
|
||||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
|
||||
|
||||
at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
See [CONTRIBUTING](CONTRIBUTING.md) for more details.
|
418
vendor/clap_builder/src/builder/action.rs
vendored
Normal file
418
vendor/clap_builder/src/builder/action.rs
vendored
Normal file
@ -0,0 +1,418 @@
|
||||
#[cfg(debug_assertions)]
|
||||
use crate::util::AnyValueId;
|
||||
|
||||
/// Behavior of arguments when they are encountered while parsing
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
#[non_exhaustive]
|
||||
#[allow(missing_copy_implementations)] // In the future, we may accept `Box<dyn ...>`
|
||||
pub enum ArgAction {
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Set)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value"]
|
||||
/// );
|
||||
/// ```
|
||||
Set,
|
||||
/// When encountered, store the associated value(s) in [`ArgMatches`][crate::ArgMatches]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Append)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd", "--flag", "value1", "--flag", "value2"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_many::<String>("flag").unwrap_or_default().map(|v| v.as_str()).collect::<Vec<_>>(),
|
||||
/// vec!["value1", "value2"]
|
||||
/// );
|
||||
/// ```
|
||||
Append,
|
||||
/// When encountered, act as if `"true"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `false`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
/// You can use [`TypedValueParser::map`][crate::builder::TypedValueParser::map] to have the
|
||||
/// flag control an application-specific type:
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// # use clap::builder::TypedValueParser as _;
|
||||
/// # use clap::builder::BoolishValueParser;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetTrue)
|
||||
/// .value_parser(
|
||||
/// BoolishValueParser::new()
|
||||
/// .map(|b| -> usize {
|
||||
/// if b { 10 } else { 5 }
|
||||
/// })
|
||||
/// )
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(10)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_one::<usize>("flag").copied(),
|
||||
/// Some(5)
|
||||
/// );
|
||||
/// ```
|
||||
SetTrue,
|
||||
/// When encountered, act as if `"false"` was encountered on the command-line
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `true`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// **NOTE:** If the argument has previously been seen, it will result in a
|
||||
/// [`ArgumentConflict`][crate::error::ErrorKind::ArgumentConflict] unless
|
||||
/// [`Command::args_override_self(true)`][crate::Command::args_override_self] is set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::SetFalse)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// false
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_flag("flag"),
|
||||
/// true
|
||||
/// );
|
||||
/// ```
|
||||
SetFalse,
|
||||
/// When encountered, increment a `u8` counter
|
||||
///
|
||||
/// If no [`default_value`][super::Arg::default_value] is set, it will be `0`.
|
||||
///
|
||||
/// No value is allowed. To optionally accept a value, see
|
||||
/// [`Arg::default_missing_value`][super::Arg::default_missing_value]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("flag")
|
||||
/// .long("flag")
|
||||
/// .action(clap::ArgAction::Count)
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.clone().try_get_matches_from(["mycmd", "--flag", "--flag"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 2
|
||||
/// );
|
||||
///
|
||||
/// let matches = cmd.try_get_matches_from(["mycmd"]).unwrap();
|
||||
/// assert!(matches.contains_id("flag"));
|
||||
/// assert_eq!(
|
||||
/// matches.get_count("flag"),
|
||||
/// 0
|
||||
/// );
|
||||
/// ```
|
||||
Count,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// Depending on the flag, [`Command::print_long_help`][super::Command::print_long_help] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::Help)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
Help,
|
||||
/// When encountered, display [`Command::print_help`][super::Command::print_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpShort)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpShort,
|
||||
/// When encountered, display [`Command::print_long_help`][super::Command::print_long_help]
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .arg(
|
||||
/// Arg::new("special-help")
|
||||
/// .short('?')
|
||||
/// .action(clap::ArgAction::HelpLong)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "-h"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "-?"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
HelpLong,
|
||||
/// When encountered, display [`Command::version`][super::Command::version]
|
||||
///
|
||||
/// Depending on the flag, [`Command::long_version`][super::Command::long_version] may be shown
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// let cmd = Command::new("mycmd")
|
||||
/// .version("1.0.0")
|
||||
/// .arg(
|
||||
/// Arg::new("special-version")
|
||||
/// .long("special-version")
|
||||
/// .action(clap::ArgAction::Version)
|
||||
/// );
|
||||
///
|
||||
/// // Existing help still exists
|
||||
/// let err = cmd.clone().try_get_matches_from(["mycmd", "--version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
///
|
||||
/// // New help available
|
||||
/// let err = cmd.try_get_matches_from(["mycmd", "--special-version"]).unwrap_err();
|
||||
/// assert_eq!(err.kind(), clap::error::ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
Version,
|
||||
}
|
||||
|
||||
impl ArgAction {
|
||||
/// Returns whether this action accepts values on the command-line
|
||||
///
|
||||
/// [`default_values`][super::Arg::default_values] and [`env`][super::Arg::env] may still be
|
||||
/// processed.
|
||||
pub fn takes_values(&self) -> bool {
|
||||
match self {
|
||||
Self::Set => true,
|
||||
Self::Append => true,
|
||||
Self::SetTrue => false,
|
||||
Self::SetFalse => false,
|
||||
Self::Count => false,
|
||||
Self::Help => false,
|
||||
Self::HelpShort => false,
|
||||
Self::HelpLong => false,
|
||||
Self::Version => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("false")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("true")),
|
||||
Self::Count => Some(std::ffi::OsStr::new("0")),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_missing_value(&self) -> Option<&'static std::ffi::OsStr> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(std::ffi::OsStr::new("true")),
|
||||
Self::SetFalse => Some(std::ffi::OsStr::new("false")),
|
||||
Self::Count => None,
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn default_value_parser(&self) -> Option<super::ValueParser> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => Some(super::ValueParser::bool()),
|
||||
Self::SetFalse => Some(super::ValueParser::bool()),
|
||||
Self::Count => Some(crate::value_parser!(u8).into()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(crate) fn value_type_id(&self) -> Option<AnyValueId> {
|
||||
match self {
|
||||
Self::Set => None,
|
||||
Self::Append => None,
|
||||
Self::SetTrue => None,
|
||||
Self::SetFalse => None,
|
||||
Self::Count => Some(AnyValueId::of::<CountType>()),
|
||||
Self::Help => None,
|
||||
Self::HelpShort => None,
|
||||
Self::HelpLong => None,
|
||||
Self::Version => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type CountType = u8;
|
84
vendor/clap_builder/src/builder/app_settings.rs
vendored
Normal file
84
vendor/clap_builder/src/builder/app_settings.rs
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
#[allow(unused)]
|
||||
use crate::Command;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct AppFlags(u32);
|
||||
|
||||
impl AppFlags {
|
||||
pub(crate) fn set(&mut self, setting: AppSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: AppSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: AppSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for AppFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Application level settings, which affect how [`Command`] operates
|
||||
///
|
||||
/// **NOTE:** When these settings are used, they apply only to current command, and are *not*
|
||||
/// propagated down or up through child or parent subcommands
|
||||
///
|
||||
/// [`Command`]: crate::Command
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum AppSettings {
|
||||
IgnoreErrors,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
AllArgsOverrideSelf,
|
||||
AllowMissingPositional,
|
||||
TrailingVarArg,
|
||||
DontDelimitTrailingValues,
|
||||
InferLongArgs,
|
||||
InferSubcommands,
|
||||
SubcommandRequired,
|
||||
AllowExternalSubcommands,
|
||||
Multicall,
|
||||
SubcommandsNegateReqs,
|
||||
ArgsNegateSubcommands,
|
||||
SubcommandPrecedenceOverArg,
|
||||
FlattenHelp,
|
||||
ArgRequiredElseHelp,
|
||||
NextLineHelp,
|
||||
DisableColoredHelp,
|
||||
DisableHelpFlag,
|
||||
DisableHelpSubcommand,
|
||||
DisableVersionFlag,
|
||||
PropagateVersion,
|
||||
Hidden,
|
||||
HidePossibleValues,
|
||||
HelpExpected,
|
||||
NoBinaryName,
|
||||
#[allow(dead_code)]
|
||||
ColorAuto,
|
||||
ColorAlways,
|
||||
ColorNever,
|
||||
Built,
|
||||
BinNameBuilt,
|
||||
}
|
||||
|
||||
impl AppSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
4800
vendor/clap_builder/src/builder/arg.rs
vendored
Normal file
4800
vendor/clap_builder/src/builder/arg.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
611
vendor/clap_builder/src/builder/arg_group.rs
vendored
Normal file
611
vendor/clap_builder/src/builder/arg_group.rs
vendored
Normal file
@ -0,0 +1,611 @@
|
||||
// Internal
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::util::Id;
|
||||
|
||||
/// Family of related [arguments].
|
||||
///
|
||||
/// By placing arguments in a logical group, you can create easier requirement and
|
||||
/// exclusion rules instead of having to list each argument individually, or when you want a rule
|
||||
/// to apply "any but not all" arguments.
|
||||
///
|
||||
/// For instance, you can make an entire `ArgGroup` required. If [`ArgGroup::multiple(true)`] is
|
||||
/// set, this means that at least one argument from that group must be present. If
|
||||
/// [`ArgGroup::multiple(false)`] is set (the default), one and *only* one must be present.
|
||||
///
|
||||
/// You can also do things such as name an entire `ArgGroup` as a [conflict] or [requirement] for
|
||||
/// another argument, meaning any of the arguments that belong to that group will cause a failure
|
||||
/// if present, or must be present respectively.
|
||||
///
|
||||
/// Perhaps the most common use of `ArgGroup`s is to require one and *only* one argument to be
|
||||
/// present out of a given set. Imagine that you had multiple arguments, and you want one of them
|
||||
/// to be required, but making all of them required isn't feasible because perhaps they conflict
|
||||
/// with each other. For example, lets say that you were building an application where one could
|
||||
/// set a given version number by supplying a string with an option argument, i.e.
|
||||
/// `--set-ver v1.2.3`, you also wanted to support automatically using a previous version number
|
||||
/// and simply incrementing one of the three numbers. So you create three flags `--major`,
|
||||
/// `--minor`, and `--patch`. All of these arguments shouldn't be used at one time but you want to
|
||||
/// specify that *at least one* of them is used. For this, you can create a group.
|
||||
///
|
||||
/// Finally, you may use `ArgGroup`s to pull a value from a group of arguments when you don't care
|
||||
/// exactly which argument was actually used at runtime.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// The following example demonstrates using an `ArgGroup` to ensure that one, and only one, of
|
||||
/// the arguments from the specified group is present at runtime.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, error::ErrorKind};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .arg(arg!(--major "auto increase major"))
|
||||
/// .arg(arg!(--minor "auto increase minor"))
|
||||
/// .arg(arg!(--patch "auto increase patch"))
|
||||
/// .group(ArgGroup::new("vers")
|
||||
/// .args(["set-ver", "major", "minor", "patch"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major", "--patch"]);
|
||||
/// // Because we used two args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// This next example shows a passing parse of the same scenario
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, ArgGroup, Id};
|
||||
/// let result = Command::new("cmd")
|
||||
/// .arg(arg!(--"set-ver" <ver> "set the version manually"))
|
||||
/// .arg(arg!(--major "auto increase major"))
|
||||
/// .arg(arg!(--minor "auto increase minor"))
|
||||
/// .arg(arg!(--patch "auto increase patch"))
|
||||
/// .group(ArgGroup::new("vers")
|
||||
/// .args(["set-ver", "major", "minor","patch"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["cmd", "--major"]);
|
||||
/// assert!(result.is_ok());
|
||||
/// let matches = result.unwrap();
|
||||
/// // We may not know which of the args was used, so we can test for the group...
|
||||
/// assert!(matches.contains_id("vers"));
|
||||
/// // We can also ask the group which arg was used
|
||||
/// assert_eq!(matches
|
||||
/// .get_one::<Id>("vers")
|
||||
/// .expect("`vers` is required")
|
||||
/// .as_str(),
|
||||
/// "major"
|
||||
/// );
|
||||
/// // we could also alternatively check each arg individually (not shown here)
|
||||
/// ```
|
||||
/// [`ArgGroup::multiple(true)`]: ArgGroup::multiple()
|
||||
///
|
||||
/// [`ArgGroup::multiple(false)`]: ArgGroup::multiple()
|
||||
/// [arguments]: crate::Arg
|
||||
/// [conflict]: crate::Arg::conflicts_with()
|
||||
/// [requirement]: crate::Arg::requires()
|
||||
#[derive(Default, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct ArgGroup {
|
||||
pub(crate) id: Id,
|
||||
pub(crate) args: Vec<Id>,
|
||||
pub(crate) required: bool,
|
||||
pub(crate) requires: Vec<Id>,
|
||||
pub(crate) conflicts: Vec<Id>,
|
||||
pub(crate) multiple: bool,
|
||||
}
|
||||
|
||||
/// # Builder
|
||||
impl ArgGroup {
|
||||
/// Create a `ArgGroup` using a unique name.
|
||||
///
|
||||
/// The name will be used to get values from the group or refer to the group inside of conflict
|
||||
/// and requirement rules.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::new("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
pub fn new(id: impl Into<Id>) -> Self {
|
||||
ArgGroup::default().id(id)
|
||||
}
|
||||
|
||||
/// Sets the group name.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ArgGroup};
|
||||
/// ArgGroup::default().id("config")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn id(mut self, id: impl Into<Id>) -> Self {
|
||||
self.id = id.into();
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds an [argument] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .arg("flag")
|
||||
/// .arg("color"))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [argument]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn arg(mut self, arg_id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(arg_id) = arg_id.into_resettable().into_option() {
|
||||
self.args.push(arg_id);
|
||||
} else {
|
||||
self.args.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds multiple [arguments] to this group by name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .get_matches_from(vec!["myprog", "-f"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// // but we can also check individually if needed
|
||||
/// assert!(m.contains_id("flag"));
|
||||
/// ```
|
||||
/// [arguments]: crate::Arg
|
||||
#[must_use]
|
||||
pub fn args(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.arg(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Getters for all args. It will return a vector of `Id`
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let args: Vec<&str> = vec!["a1".into(), "a4".into()];
|
||||
/// let grp = ArgGroup::new("program").args(&args);
|
||||
///
|
||||
/// for (pos, arg) in grp.get_args().enumerate() {
|
||||
/// assert_eq!(*arg, args[pos]);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn get_args(&self) -> impl Iterator<Item = &Id> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
/// Allows more than one of the [`Arg`]s in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Notice in this example we use *both* the `-f` and `-c` flags which are both part of the
|
||||
/// group
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, ArgAction};
|
||||
/// let m = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .multiple(true))
|
||||
/// .get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // maybe we don't know which of the two flags was used...
|
||||
/// assert!(m.contains_id("req_flags"));
|
||||
/// ```
|
||||
/// In this next example, we show the default behavior (i.e. `multiple(false)) which will throw
|
||||
/// an error if more than one of the args in the group was used.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-f", "-c"]);
|
||||
/// // Because we used both args in the group it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn multiple(mut self, yes: bool) -> Self {
|
||||
self.multiple = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Return true if the group allows more than one of the arguments
|
||||
/// in this group to be used. (Default: `false`)
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{ArgGroup};
|
||||
/// let mut group = ArgGroup::new("myprog")
|
||||
/// .args(["f", "c"])
|
||||
/// .multiple(true);
|
||||
///
|
||||
/// assert!(group.is_multiple());
|
||||
/// ```
|
||||
pub fn is_multiple(&mut self) -> bool {
|
||||
self.multiple
|
||||
}
|
||||
|
||||
/// Require an argument from the group to be present when parsing.
|
||||
///
|
||||
/// This is unless conflicting with another argument. A required group will be displayed in
|
||||
/// the usage string of the application in the format `<arg|arg2|arg3>`.
|
||||
///
|
||||
/// **NOTE:** This setting only applies to the current [`Command`] / [`Subcommand`]s, and not
|
||||
/// globally.
|
||||
///
|
||||
/// **NOTE:** By default, [`ArgGroup::multiple`] is set to `false` which when combined with
|
||||
/// `ArgGroup::required(true)` states, "One and *only one* arg must be used from this group.
|
||||
/// Use of more than one arg is an error." Vice setting `ArgGroup::multiple(true)` which
|
||||
/// states, '*At least* one arg from this group must be used. Using multiple is OK."
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["myprog"]);
|
||||
/// // Because we didn't use any of the args in the group, it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`ArgGroup::multiple`]: ArgGroup::multiple()
|
||||
/// [`Command`]: crate::Command
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn required(mut self, yes: bool) -> Self {
|
||||
self.required = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when any one of the arguments from this group is used.
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" to be used, it's an
|
||||
/// // error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires()
|
||||
#[must_use]
|
||||
pub fn requires(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.requires.push(id);
|
||||
} else {
|
||||
self.requires.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must be present when this group is.
|
||||
///
|
||||
/// This is not to be confused with a [required group]. Requirement rules function just like
|
||||
/// [argument requirement rules], you can name other arguments or groups that must be present
|
||||
/// when one of the arguments from this group is used.
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .requires_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group requires "-d" and "-v" to be used,
|
||||
/// // yet we only used "-d" it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
/// [required group]: ArgGroup::required()
|
||||
/// [argument requirement rules]: crate::Arg::requires_ifs()
|
||||
#[must_use]
|
||||
pub fn requires_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.requires(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify an argument or group that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion (aka conflict) rules function just like [argument exclusion rules], you can name
|
||||
/// other arguments or groups that must *not* be present when one of the arguments from this
|
||||
/// group are used.
|
||||
///
|
||||
/// **NOTE:** The name provided may be an argument, or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with("debug"))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-d"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with "-d", it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with()
|
||||
#[must_use]
|
||||
pub fn conflicts_with(mut self, id: impl IntoResettable<Id>) -> Self {
|
||||
if let Some(id) = id.into_resettable().into_option() {
|
||||
self.conflicts.push(id);
|
||||
} else {
|
||||
self.conflicts.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Specify arguments or groups that must **not** be present when this group is.
|
||||
///
|
||||
/// Exclusion rules function just like [argument exclusion rules], you can name other arguments
|
||||
/// or groups that must *not* be present when one of the arguments from this group are used.
|
||||
///
|
||||
/// **NOTE:** The names provided may be an argument, or group name
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, ArgGroup, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("myprog")
|
||||
/// .arg(Arg::new("flag")
|
||||
/// .short('f')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .short('c')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .short('d')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .arg(Arg::new("verb")
|
||||
/// .short('v')
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .group(ArgGroup::new("req_flags")
|
||||
/// .args(["flag", "color"])
|
||||
/// .conflicts_with_all(["debug", "verb"]))
|
||||
/// .try_get_matches_from(vec!["myprog", "-c", "-v"]);
|
||||
/// // because we used an arg from the group, and the group conflicts with either "-v" or "-d"
|
||||
/// // it's an error
|
||||
/// assert!(result.is_err());
|
||||
/// let err = result.unwrap_err();
|
||||
/// assert_eq!(err.kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
///
|
||||
/// [argument exclusion rules]: crate::Arg::conflicts_with_all()
|
||||
#[must_use]
|
||||
pub fn conflicts_with_all(mut self, ns: impl IntoIterator<Item = impl Into<Id>>) -> Self {
|
||||
for n in ns {
|
||||
self = self.conflicts_with(n);
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// # Reflection
|
||||
impl ArgGroup {
|
||||
/// Get the name of the group
|
||||
#[inline]
|
||||
pub fn get_id(&self) -> &Id {
|
||||
&self.id
|
||||
}
|
||||
|
||||
/// Reports whether [`ArgGroup::required`] is set
|
||||
#[inline]
|
||||
pub fn is_required_set(&self) -> bool {
|
||||
self.required
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ ArgGroup> for ArgGroup {
|
||||
fn from(g: &ArgGroup) -> Self {
|
||||
g.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn groups() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
assert_eq!(g.args, args);
|
||||
assert_eq!(g.requires, reqs);
|
||||
assert_eq!(g.conflicts, confs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from() {
|
||||
let g = ArgGroup::new("test")
|
||||
.arg("a1")
|
||||
.arg("a4")
|
||||
.args(["a2", "a3"])
|
||||
.required(true)
|
||||
.conflicts_with("c1")
|
||||
.conflicts_with_all(["c2", "c3"])
|
||||
.conflicts_with("c4")
|
||||
.requires("r1")
|
||||
.requires_all(["r2", "r3"])
|
||||
.requires("r4");
|
||||
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into(), "a2".into(), "a3".into()];
|
||||
let reqs: Vec<Id> = vec!["r1".into(), "r2".into(), "r3".into(), "r4".into()];
|
||||
let confs: Vec<Id> = vec!["c1".into(), "c2".into(), "c3".into(), "c4".into()];
|
||||
|
||||
let g2 = ArgGroup::from(&g);
|
||||
assert_eq!(g2.args, args);
|
||||
assert_eq!(g2.requires, reqs);
|
||||
assert_eq!(g2.conflicts, confs);
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if ArgGroup is not Send + Sync
|
||||
#[test]
|
||||
fn arg_group_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(ArgGroup::new("test"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_is_multiple_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
|
||||
let mut grp_multiple = ArgGroup::new("test_multiple").args(&args).multiple(true);
|
||||
assert!(grp_multiple.is_multiple());
|
||||
|
||||
let mut grp_not_multiple = ArgGroup::new("test_multiple").args(&args).multiple(false);
|
||||
assert!(!grp_not_multiple.is_multiple());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arg_group_expose_get_args_helper() {
|
||||
let args: Vec<Id> = vec!["a1".into(), "a4".into()];
|
||||
let grp = ArgGroup::new("program").args(&args);
|
||||
|
||||
for (pos, arg) in grp.get_args().enumerate() {
|
||||
assert_eq!(*arg, args[pos]);
|
||||
}
|
||||
}
|
||||
}
|
19
vendor/clap_builder/src/builder/arg_predicate.rs
vendored
Normal file
19
vendor/clap_builder/src/builder/arg_predicate.rs
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
use crate::builder::OsStr;
|
||||
|
||||
/// Operations to perform on argument values
|
||||
///
|
||||
/// These do not apply to [`ValueSource::DefaultValue`][crate::parser::ValueSource::DefaultValue]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "unstable-v5", non_exhaustive)]
|
||||
pub enum ArgPredicate {
|
||||
/// Is the argument present?
|
||||
IsPresent,
|
||||
/// Does the argument match the specified value?
|
||||
Equals(OsStr),
|
||||
}
|
||||
|
||||
impl<S: Into<OsStr>> From<S> for ArgPredicate {
|
||||
fn from(other: S) -> Self {
|
||||
Self::Equals(other.into())
|
||||
}
|
||||
}
|
91
vendor/clap_builder/src/builder/arg_settings.rs
vendored
Normal file
91
vendor/clap_builder/src/builder/arg_settings.rs
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
#[allow(unused)]
|
||||
use crate::Arg;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct ArgFlags(u32);
|
||||
|
||||
impl ArgFlags {
|
||||
pub(crate) fn set(&mut self, setting: ArgSettings) {
|
||||
self.0 |= setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn unset(&mut self, setting: ArgSettings) {
|
||||
self.0 &= !setting.bit();
|
||||
}
|
||||
|
||||
pub(crate) fn is_set(&self, setting: ArgSettings) -> bool {
|
||||
self.0 & setting.bit() != 0
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, other: Self) {
|
||||
self.0 |= other.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::BitOr for ArgFlags {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(mut self, rhs: Self) -> Self::Output {
|
||||
self.insert(rhs);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Various settings that apply to arguments and may be set, unset, and checked via getter/setter
|
||||
/// methods [`Arg::setting`], [`Arg::unset_setting`], and [`Arg::is_set`]. This is what the
|
||||
/// [`Arg`] methods which accept a `bool` use internally.
|
||||
///
|
||||
/// [`Arg`]: crate::Arg
|
||||
/// [`Arg::setting`]: crate::Arg::setting()
|
||||
/// [`Arg::unset_setting`]: crate::Arg::unset_setting()
|
||||
/// [`Arg::is_set`]: crate::Arg::is_set()
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
#[repr(u8)]
|
||||
pub(crate) enum ArgSettings {
|
||||
Required,
|
||||
Global,
|
||||
Hidden,
|
||||
NextLineHelp,
|
||||
HidePossibleValues,
|
||||
AllowHyphenValues,
|
||||
AllowNegativeNumbers,
|
||||
RequireEquals,
|
||||
Last,
|
||||
TrailingVarArg,
|
||||
HideDefaultValue,
|
||||
IgnoreCase,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnv,
|
||||
#[cfg(feature = "env")]
|
||||
HideEnvValues,
|
||||
HiddenShortHelp,
|
||||
HiddenLongHelp,
|
||||
Exclusive,
|
||||
}
|
||||
|
||||
impl ArgSettings {
|
||||
fn bit(self) -> u32 {
|
||||
1 << (self as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::Arg;
|
||||
|
||||
#[test]
|
||||
fn setting() {
|
||||
let m = Arg::new("setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unset_setting() {
|
||||
let m = Arg::new("unset_setting").setting(ArgSettings::Required);
|
||||
assert!(m.is_required_set());
|
||||
|
||||
let m = m.unset_setting(ArgSettings::Required);
|
||||
assert!(!m.is_required_set(), "{m:#?}");
|
||||
}
|
||||
}
|
4916
vendor/clap_builder/src/builder/command.rs
vendored
Normal file
4916
vendor/clap_builder/src/builder/command.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
840
vendor/clap_builder/src/builder/debug_asserts.rs
vendored
Normal file
840
vendor/clap_builder/src/builder/debug_asserts.rs
vendored
Normal file
@ -0,0 +1,840 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::builder::ValueRange;
|
||||
use crate::mkeymap::KeyType;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
use crate::ArgAction;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
use crate::{Arg, Command, ValueHint};
|
||||
|
||||
pub(crate) fn assert_app(cmd: &Command) {
|
||||
debug!("Command::_debug_asserts");
|
||||
|
||||
let mut short_flags = vec![];
|
||||
let mut long_flags = vec![];
|
||||
|
||||
// Invalid version flag settings
|
||||
if cmd.get_version().is_none() && cmd.get_long_version().is_none() {
|
||||
// PropagateVersion is meaningless if there is no version
|
||||
assert!(
|
||||
!cmd.is_propagate_version_set(),
|
||||
"Command {}: No version information via Command::version or Command::long_version to propagate",
|
||||
cmd.get_name(),
|
||||
);
|
||||
|
||||
// Used `Command::mut_arg("version", ..) but did not provide any version information to display
|
||||
let version_needed = cmd
|
||||
.get_arguments()
|
||||
.filter(|x| matches!(x.get_action(), ArgAction::Version))
|
||||
.map(|x| x.get_id())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(version_needed, Vec::<&str>::new(), "Command {}: `ArgAction::Version` used without providing Command::version or Command::long_version"
|
||||
,cmd.get_name()
|
||||
);
|
||||
}
|
||||
|
||||
for sc in cmd.get_subcommands() {
|
||||
if let Some(s) = sc.get_short_flag().as_ref() {
|
||||
short_flags.push(Flag::Command(format!("-{s}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for short_alias in sc.get_all_short_flag_aliases() {
|
||||
short_flags.push(Flag::Command(format!("-{short_alias}"), sc.get_name()));
|
||||
}
|
||||
|
||||
if let Some(l) = sc.get_long_flag().as_ref() {
|
||||
assert!(!l.starts_with('-'), "Command {}: long_flag {:?} must not start with a `-`, that will be handled by the parser", sc.get_name(), l);
|
||||
long_flags.push(Flag::Command(format!("--{l}"), sc.get_name()));
|
||||
}
|
||||
|
||||
for long_alias in sc.get_all_long_flag_aliases() {
|
||||
long_flags.push(Flag::Command(format!("--{long_alias}"), sc.get_name()));
|
||||
}
|
||||
}
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
assert_arg(arg);
|
||||
|
||||
assert!(
|
||||
!cmd.is_multicall_set(),
|
||||
"Command {}: Arguments like {} cannot be set on a multicall command",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if let Some(s) = arg.get_short() {
|
||||
short_flags.push(Flag::Arg(format!("-{s}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (short_alias, _) in &arg.short_aliases {
|
||||
short_flags.push(Flag::Arg(format!("-{short_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
if let Some(l) = arg.get_long() {
|
||||
assert!(!l.starts_with('-'), "Argument {}: long {:?} must not start with a `-`, that will be handled by the parser", arg.get_id(), l);
|
||||
long_flags.push(Flag::Arg(format!("--{l}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
for (long_alias, _) in &arg.aliases {
|
||||
long_flags.push(Flag::Arg(format!("--{long_alias}"), arg.get_id().as_str()));
|
||||
}
|
||||
|
||||
// Name conflicts
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_id() == arg.get_id()) {
|
||||
panic!(
|
||||
"Command {}: Argument names must be unique, but '{}' is in use by more than one argument or group{}",
|
||||
cmd.get_name(),
|
||||
arg.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
);
|
||||
}
|
||||
|
||||
// Long conflicts
|
||||
if let Some(l) = arg.get_long() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_long() == Some(l)) {
|
||||
panic!(
|
||||
"Command {}: Long option names must be unique for each argument, \
|
||||
but '--{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
l,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Short conflicts
|
||||
if let Some(s) = arg.get_short() {
|
||||
if let Some((first, second)) = cmd.two_args_of(|x| x.get_short() == Some(s)) {
|
||||
panic!(
|
||||
"Command {}: Short option names must be unique for each argument, \
|
||||
but '-{}' is in use by both '{}' and '{}'{}",
|
||||
cmd.get_name(),
|
||||
s,
|
||||
first.get_id(),
|
||||
second.get_id(),
|
||||
duplicate_tip(cmd, first, second),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Index conflicts
|
||||
if let Some(idx) = arg.index {
|
||||
if let Some((first, second)) =
|
||||
cmd.two_args_of(|x| x.is_positional() && x.get_index() == Some(idx))
|
||||
{
|
||||
panic!(
|
||||
"Command {}: Argument '{}' has the same index as '{}' \
|
||||
and they are both positional arguments\n\n\t \
|
||||
Use `Arg::num_args(1..)` to allow one \
|
||||
positional argument to take multiple values",
|
||||
cmd.get_name(),
|
||||
first.get_id(),
|
||||
second.get_id()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// requires, r_if, r_unless
|
||||
for req in &arg.requires {
|
||||
assert!(
|
||||
cmd.id_exists(&req.1),
|
||||
"Command {}: Argument or group '{}' specified in 'requires*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.1,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_ifs_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_if_eq_all`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(&req.0),
|
||||
"Command {}: Argument or group '{}' specified in 'required_if_eq_all' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req.0,
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
for req in &arg.r_unless_all {
|
||||
assert!(
|
||||
!arg.is_required_set(),
|
||||
"Argument {}: `required` conflicts with `required_unless*`",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'required_unless*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// blacklist
|
||||
for req in &arg.blacklist {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'conflicts_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
// overrides
|
||||
for req in &arg.overrides {
|
||||
assert!(
|
||||
cmd.id_exists(req),
|
||||
"Command {}: Argument or group '{}' specified in 'overrides_with*' for '{}' does not exist",
|
||||
cmd.get_name(),
|
||||
req,
|
||||
arg.get_id(),
|
||||
);
|
||||
}
|
||||
|
||||
if arg.is_last_set() {
|
||||
assert!(
|
||||
arg.get_long().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a long and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.get_short().is_none(),
|
||||
"Command {}: Flags or Options cannot have last(true) set. '{}' has both a short and last(true) set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert!(
|
||||
!(arg.is_required_set() && arg.is_global_set()),
|
||||
"Command {}: Global arguments cannot be required.\n\n\t'{}' is marked as both global and required",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Command {}: Argument '{}' has hint CommandWithArguments and must be positional.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
assert!(
|
||||
arg.is_trailing_var_arg_set() || arg.is_last_set(),
|
||||
"Command {}: Positional argument '{}' has hint CommandWithArguments, so Command must have `trailing_var_arg(true)` or `last(true)` set.",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for group in cmd.get_groups() {
|
||||
// Name conflicts
|
||||
assert!(
|
||||
cmd.get_groups().filter(|x| x.id == group.id).count() < 2,
|
||||
"Command {}: Argument group name must be unique\n\n\t'{}' is already in use",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
// Groups should not have naming conflicts with Args
|
||||
assert!(
|
||||
!cmd.get_arguments().any(|x| x.get_id() == group.get_id()),
|
||||
"Command {}: Argument group name '{}' must not conflict with argument name",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
);
|
||||
|
||||
for arg in &group.args {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.get_arguments().any(|x| x.get_id() == arg),
|
||||
"Command {}: Argument group '{}' contains non-existent argument '{}'",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.requires {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' requires non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
|
||||
for arg in &group.conflicts {
|
||||
// Args listed inside groups should exist
|
||||
assert!(
|
||||
cmd.id_exists(arg),
|
||||
"Command {}: Argument group '{}' conflicts with non-existent '{}' id",
|
||||
cmd.get_name(),
|
||||
group.get_id(),
|
||||
arg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Conflicts between flags and subcommands
|
||||
|
||||
long_flags.sort_unstable();
|
||||
short_flags.sort_unstable();
|
||||
|
||||
detect_duplicate_flags(&long_flags, "long");
|
||||
detect_duplicate_flags(&short_flags, "short");
|
||||
|
||||
let mut subs = FlatSet::new();
|
||||
for sc in cmd.get_subcommands() {
|
||||
assert!(
|
||||
subs.insert(sc.get_name()),
|
||||
"Command {}: command name `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name()
|
||||
);
|
||||
for alias in sc.get_all_aliases() {
|
||||
assert!(
|
||||
subs.insert(alias),
|
||||
"Command {}: command `{}` alias `{}` is duplicated",
|
||||
cmd.get_name(),
|
||||
sc.get_name(),
|
||||
alias
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
_verify_positionals(cmd);
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
if let Some(help_template) = cmd.get_help_template() {
|
||||
assert!(
|
||||
!help_template.to_string().contains("{flags}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{flags}` template variable was removed in clap3, they are now included in `{options}`",
|
||||
);
|
||||
assert!(
|
||||
!help_template.to_string().contains("{unified}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{unified}` template variable was removed in clap3, use `{options}` instead"
|
||||
);
|
||||
#[cfg(feature = "unstable-v5")]
|
||||
assert!(
|
||||
!help_template.to_string().contains("{bin}"),
|
||||
"Command {}: {}",
|
||||
cmd.get_name(),
|
||||
"`{bin}` template variable was removed in clap5, use `{name}` instead"
|
||||
)
|
||||
}
|
||||
|
||||
cmd._panic_on_missing_help(cmd.is_help_expected_set());
|
||||
assert_app_flags(cmd);
|
||||
}
|
||||
|
||||
fn duplicate_tip(cmd: &Command, first: &Arg, second: &Arg) -> &'static str {
|
||||
if !cmd.is_disable_help_flag_set()
|
||||
&& (first.get_id() == Id::HELP || second.get_id() == Id::HELP)
|
||||
{
|
||||
" (call `cmd.disable_help_flag(true)` to remove the auto-generated `--help`)"
|
||||
} else if !cmd.is_disable_version_flag_set()
|
||||
&& (first.get_id() == Id::VERSION || second.get_id() == Id::VERSION)
|
||||
{
|
||||
" (call `cmd.disable_version_flag(true)` to remove the auto-generated `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq)]
|
||||
enum Flag<'a> {
|
||||
Command(String, &'a str),
|
||||
Arg(String, &'a str),
|
||||
}
|
||||
|
||||
impl PartialEq for Flag<'_> {
|
||||
fn eq(&self, other: &Flag) -> bool {
|
||||
self.cmp(other) == Ordering::Equal
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Flag<'_> {
|
||||
fn partial_cmp(&self, other: &Flag) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Flag<'_> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
use Flag::*;
|
||||
|
||||
match (self, other) {
|
||||
(Command(s1, _), Command(s2, _))
|
||||
| (Arg(s1, _), Arg(s2, _))
|
||||
| (Command(s1, _), Arg(s2, _))
|
||||
| (Arg(s1, _), Command(s2, _)) => {
|
||||
if s1 == s2 {
|
||||
Ordering::Equal
|
||||
} else {
|
||||
s1.cmp(s2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_duplicate_flags(flags: &[Flag], short_or_long: &str) {
|
||||
use Flag::*;
|
||||
|
||||
for (one, two) in find_duplicates(flags) {
|
||||
match (one, two) {
|
||||
(Command(flag, one), Command(_, another)) if one != another => panic!(
|
||||
"the '{flag}' {short_or_long} flag is specified for both '{one}' and '{another}' subcommands"
|
||||
),
|
||||
|
||||
(Arg(flag, one), Arg(_, another)) if one != another => panic!(
|
||||
"{short_or_long} option names must be unique, but '{flag}' is in use by both '{one}' and '{another}'"
|
||||
),
|
||||
|
||||
(Arg(flag, arg), Command(_, sub)) | (Command(flag, sub), Arg(_, arg)) => panic!(
|
||||
"the '{flag}' {short_or_long} flag for the '{arg}' argument conflicts with the short flag \
|
||||
for '{sub}' subcommand"
|
||||
),
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Find duplicates in a sorted array.
|
||||
///
|
||||
/// The algorithm is simple: the array is sorted, duplicates
|
||||
/// must be placed next to each other, we can check only adjacent elements.
|
||||
fn find_duplicates<T: PartialEq>(slice: &[T]) -> impl Iterator<Item = (&T, &T)> {
|
||||
slice.windows(2).filter_map(|w| {
|
||||
if w[0] == w[1] {
|
||||
Some((&w[0], &w[1]))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn assert_app_flags(cmd: &Command) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} is required when AppSettings::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{s}")
|
||||
}
|
||||
}
|
||||
};
|
||||
($a:ident conflicts $($b:ident)|+) => {
|
||||
if cmd.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if cmd.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " AppSettings::{} conflicts with AppSettings::{}.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("{}\n{}", cmd.get_name(), s)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
checker!(is_multicall_set conflicts is_no_binary_name_set);
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
fn _verify_positionals(cmd: &Command) -> bool {
|
||||
debug!("Command::_verify_positionals");
|
||||
// Because you must wait until all arguments have been supplied, this is the first chance
|
||||
// to make assertions on positional argument indexes
|
||||
//
|
||||
// First we verify that the index highest supplied index, is equal to the number of
|
||||
// positional arguments to verify there are no gaps (i.e. supplying an index of 1 and 3
|
||||
// but no 2)
|
||||
|
||||
let highest_idx = cmd
|
||||
.get_keymap()
|
||||
.keys()
|
||||
.filter_map(|x| {
|
||||
if let KeyType::Position(n) = x {
|
||||
Some(*n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
|
||||
let num_p = cmd.get_keymap().keys().filter(|x| x.is_position()).count();
|
||||
|
||||
assert!(
|
||||
highest_idx == num_p,
|
||||
"Found positional argument whose index is {highest_idx} but there \
|
||||
are only {num_p} positional arguments defined",
|
||||
);
|
||||
|
||||
for arg in cmd.get_arguments() {
|
||||
if arg.index.unwrap_or(0) == highest_idx {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set() || !arg.is_last_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` and `Arg::last` cannot be used together",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.is_trailing_var_arg_set() {
|
||||
assert!(
|
||||
arg.is_multiple(),
|
||||
"{}:{}: `Arg::trailing_var_arg` must accept multiple values",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
assert!(
|
||||
!arg.is_trailing_var_arg_set(),
|
||||
"{}:{}: `Arg::trailing_var_arg` can only apply to last positional",
|
||||
cmd.get_name(),
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Next we verify that only the highest index has takes multiple arguments (if any)
|
||||
let only_highest = |a: &Arg| a.is_multiple() && (a.get_index().unwrap_or(0) != highest_idx);
|
||||
if cmd.get_positionals().any(only_highest) {
|
||||
// First we make sure if there is a positional that allows multiple values
|
||||
// the one before it (second to last) has one of these:
|
||||
// * a value terminator
|
||||
// * ArgSettings::Last
|
||||
// * The last arg is Required
|
||||
|
||||
// We can't pass the closure (it.next()) to the macro directly because each call to
|
||||
// find() (iterator, not macro) gets called repeatedly.
|
||||
let last = &cmd.get_keymap()[&KeyType::Position(highest_idx)];
|
||||
let second_to_last = &cmd.get_keymap()[&KeyType::Position(highest_idx - 1)];
|
||||
|
||||
// Either the final positional is required
|
||||
// Or the second to last has a terminator or .last(true) set
|
||||
let ok = last.is_required_set()
|
||||
|| (second_to_last.terminator.is_some() || second_to_last.is_last_set())
|
||||
|| last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Positional argument `{last}` *must* have `required(true)` or `last(true)` set \
|
||||
because a prior positional argument (`{second_to_last}`) has `num_args(1..)`"
|
||||
);
|
||||
|
||||
// We make sure if the second to last is Multiple the last is ArgSettings::Last
|
||||
let ok = second_to_last.is_multiple() || last.is_last_set();
|
||||
assert!(
|
||||
ok,
|
||||
"Only the last positional argument, or second to last positional \
|
||||
argument may be set to `.num_args(1..)`"
|
||||
);
|
||||
|
||||
// Next we check how many have both Multiple and not a specific number of values set
|
||||
let count = cmd
|
||||
.get_positionals()
|
||||
.filter(|p| {
|
||||
p.is_multiple_values_set()
|
||||
&& p.get_value_terminator().is_none()
|
||||
&& !p.get_num_args().expect(INTERNAL_ERROR_MSG).is_fixed()
|
||||
})
|
||||
.count();
|
||||
let ok = count <= 1
|
||||
|| (last.is_last_set()
|
||||
&& last.is_multiple()
|
||||
&& second_to_last.is_multiple()
|
||||
&& count == 2);
|
||||
assert!(
|
||||
ok,
|
||||
"Only one positional argument with `.num_args(1..)` set is allowed per \
|
||||
command, unless the second one also has .last(true) set"
|
||||
);
|
||||
}
|
||||
|
||||
let mut found = false;
|
||||
|
||||
if cmd.is_allow_missing_positional_set() {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required.
|
||||
let mut foundx2 = false;
|
||||
|
||||
for p in cmd.get_positionals() {
|
||||
if foundx2 && !p.is_required_set() {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument by two or more: {:?} \
|
||||
index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
if found {
|
||||
foundx2 = true;
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
continue;
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Check that if a required positional argument is found, all positions with a lower
|
||||
// index are also required
|
||||
for p in (1..=num_p).rev().filter_map(|n| cmd.get_keymap().get(&n)) {
|
||||
if found {
|
||||
assert!(
|
||||
p.is_required_set(),
|
||||
"Found non-required positional argument with a lower \
|
||||
index than a required positional argument: {:?} index {:?}",
|
||||
p.get_id(),
|
||||
p.get_index()
|
||||
);
|
||||
} else if p.is_required_set() && !p.is_last_set() {
|
||||
// Args that .last(true) don't count since they can be required and have
|
||||
// positionals with a lower index that aren't required
|
||||
// Imagine: prog <req1> [opt1] -- <req2>
|
||||
// Both of these are valid invocations:
|
||||
// $ prog r1 -- r2
|
||||
// $ prog r1 o1 -- r2
|
||||
found = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
cmd.get_positionals().filter(|p| p.is_last_set()).count() < 2,
|
||||
"Only one positional argument may have last(true) set. Found two."
|
||||
);
|
||||
if cmd
|
||||
.get_positionals()
|
||||
.any(|p| p.is_last_set() && p.is_required_set())
|
||||
&& cmd.has_subcommands()
|
||||
&& !cmd.is_subcommand_negates_reqs_set()
|
||||
{
|
||||
panic!(
|
||||
"Having a required positional argument with .last(true) set *and* child \
|
||||
subcommands without setting SubcommandsNegateReqs isn't compatible."
|
||||
);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn assert_arg(arg: &Arg) {
|
||||
debug!("Arg::_debug_asserts:{}", arg.get_id());
|
||||
|
||||
// Self conflict
|
||||
// TODO: this check should be recursive
|
||||
assert!(
|
||||
!arg.blacklist.iter().any(|x| x == arg.get_id()),
|
||||
"Argument '{}' cannot conflict with itself",
|
||||
arg.get_id(),
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
arg.get_action().takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `takes_value`",
|
||||
arg.get_id(),
|
||||
arg.get_action()
|
||||
);
|
||||
if let Some(action_type_id) = arg.get_action().value_type_id() {
|
||||
assert_eq!(
|
||||
action_type_id,
|
||||
arg.get_value_parser().type_id(),
|
||||
"Argument `{}`'s selected action {:?} contradicts `value_parser` ({:?})",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
arg.get_value_parser()
|
||||
);
|
||||
}
|
||||
|
||||
if arg.get_value_hint() != ValueHint::Unknown {
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}' has value hint but takes no value",
|
||||
arg.get_id()
|
||||
);
|
||||
|
||||
if arg.get_value_hint() == ValueHint::CommandWithArguments {
|
||||
assert!(
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument '{}' uses hint CommandWithArguments and must accept multiple values",
|
||||
arg.get_id()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if arg.index.is_some() {
|
||||
assert!(
|
||||
arg.is_positional(),
|
||||
"Argument '{}' is a positional argument and can't have short or long name versions",
|
||||
arg.get_id()
|
||||
);
|
||||
assert!(
|
||||
arg.is_takes_value_set(),
|
||||
"Argument '{}` is positional and it must take a value but action is {:?}{}",
|
||||
arg.get_id(),
|
||||
arg.get_action(),
|
||||
if arg.get_id() == Id::HELP {
|
||||
" (`mut_arg` no longer works with implicit `--help`)"
|
||||
} else if arg.get_id() == Id::VERSION {
|
||||
" (`mut_arg` no longer works with implicit `--version`)"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
let num_vals = arg.get_num_args().expect(INTERNAL_ERROR_MSG);
|
||||
// This can be the cause of later asserts, so put this first
|
||||
if num_vals != ValueRange::EMPTY {
|
||||
// HACK: Don't check for flags to make the derive easier
|
||||
let num_val_names = arg.get_value_names().unwrap_or(&[]).len();
|
||||
if num_vals.max_values() < num_val_names {
|
||||
panic!(
|
||||
"Argument {}: Too many value names ({}) compared to `num_args` ({})",
|
||||
arg.get_id(),
|
||||
num_val_names,
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
num_vals.takes_values(),
|
||||
arg.is_takes_value_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `takes_value`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
assert_eq!(
|
||||
num_vals.is_multiple(),
|
||||
arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` ({}) and `multiple_values`",
|
||||
arg.get_id(),
|
||||
num_vals,
|
||||
);
|
||||
|
||||
if 1 < num_vals.min_values() {
|
||||
assert!(
|
||||
!arg.is_require_equals_set(),
|
||||
"Argument {}: cannot accept more than 1 arg (num_args={}) with require_equals",
|
||||
arg.get_id(),
|
||||
num_vals
|
||||
);
|
||||
}
|
||||
|
||||
if num_vals == ValueRange::SINGLE {
|
||||
assert!(
|
||||
!arg.is_multiple_values_set(),
|
||||
"Argument {}: mismatch between `num_args` and `multiple_values`",
|
||||
arg.get_id()
|
||||
);
|
||||
}
|
||||
|
||||
assert_arg_flags(arg);
|
||||
}
|
||||
|
||||
fn assert_arg_flags(arg: &Arg) {
|
||||
macro_rules! checker {
|
||||
($a:ident requires $($b:ident)|+) => {
|
||||
if arg.$a() {
|
||||
let mut s = String::new();
|
||||
|
||||
$(
|
||||
if !arg.$b() {
|
||||
use std::fmt::Write;
|
||||
write!(&mut s, " Arg::{} is required when Arg::{} is set.\n", std::stringify!($b), std::stringify!($a)).unwrap();
|
||||
}
|
||||
)+
|
||||
|
||||
if !s.is_empty() {
|
||||
panic!("Argument {:?}\n{}", arg.get_id(), s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checker!(is_hide_possible_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_hyphen_values_set requires is_takes_value_set);
|
||||
checker!(is_allow_negative_numbers_set requires is_takes_value_set);
|
||||
checker!(is_require_equals_set requires is_takes_value_set);
|
||||
checker!(is_last_set requires is_takes_value_set);
|
||||
checker!(is_hide_default_value_set requires is_takes_value_set);
|
||||
checker!(is_multiple_values_set requires is_takes_value_set);
|
||||
checker!(is_ignore_case_set requires is_takes_value_set);
|
||||
}
|
216
vendor/clap_builder/src/builder/ext.rs
vendored
Normal file
216
vendor/clap_builder/src/builder/ext.rs
vendored
Normal file
@ -0,0 +1,216 @@
|
||||
use crate::util::AnyValueId;
|
||||
use crate::util::FlatMap;
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
pub(crate) struct Extensions {
|
||||
extensions: FlatMap<AnyValueId, BoxedExtension>,
|
||||
}
|
||||
|
||||
impl Extensions {
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get<T: Extension>(&self) -> Option<&T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get(&id).map(|e| e.as_ref::<T>())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_mut<T: Extension>(&mut self) -> Option<&mut T> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.get_mut(&id).map(|e| e.as_mut::<T>())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn get_or_insert_default<T: Extension + Default>(&mut self) -> &mut T {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions
|
||||
.entry(id)
|
||||
.or_insert_with(|| BoxedExtension::new(T::default()))
|
||||
.as_mut::<T>()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn set<T: Extension + Into<BoxedEntry>>(&mut self, tagged: T) -> bool {
|
||||
let BoxedEntry { id, value } = tagged.into();
|
||||
self.extensions.insert(id, value).is_some()
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn remove<T: Extension>(&mut self) -> Option<Box<dyn Extension>> {
|
||||
let id = AnyValueId::of::<T>();
|
||||
self.extensions.remove(&id).map(BoxedExtension::into_inner)
|
||||
}
|
||||
|
||||
pub(crate) fn update(&mut self, other: &Self) {
|
||||
for (key, value) in other.extensions.iter() {
|
||||
self.extensions.insert(*key, value.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Extension`.
|
||||
pub(crate) trait Extension: std::fmt::Debug + Send + Sync + 'static {
|
||||
/// Convert `Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Any>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
/// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;
|
||||
/// Clone `&Box<dyn Trait>` (where `Trait: Extension`) to `Box<dyn Extension>`.
|
||||
///
|
||||
/// `Box<dyn Any>` can /// then be further `downcast` into
|
||||
// `Box<ConcreteType>` where `ConcreteType` implements `Trait`.
|
||||
fn clone_extension(&self) -> Box<dyn Extension>;
|
||||
/// Convert `&Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&Any`'s vtable from
|
||||
/// `&Trait`'s.
|
||||
fn as_any(&self) -> &dyn std::any::Any;
|
||||
/// Convert `&mut Trait` (where `Trait: Extension`) to `&Any`.
|
||||
///
|
||||
/// This is needed since Rust cannot /// generate `&mut Any`'s vtable from
|
||||
/// `&mut Trait`'s.
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
||||
}
|
||||
|
||||
impl<T> Extension for T
|
||||
where
|
||||
T: Clone + std::fmt::Debug + Send + Sync + 'static,
|
||||
{
|
||||
fn into_any(self: Box<Self>) -> Box<dyn std::any::Any> {
|
||||
self
|
||||
}
|
||||
fn clone_extension(&self) -> Box<dyn Extension> {
|
||||
Box::new(self.clone())
|
||||
}
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn Extension> {
|
||||
fn clone(&self) -> Self {
|
||||
self.as_ref().clone_extension()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[repr(transparent)]
|
||||
struct BoxedExtension(Box<dyn Extension>);
|
||||
|
||||
impl BoxedExtension {
|
||||
fn new<T: Extension>(inner: T) -> Self {
|
||||
Self(Box::new(inner))
|
||||
}
|
||||
|
||||
fn into_inner(self) -> Box<dyn Extension> {
|
||||
self.0
|
||||
}
|
||||
|
||||
fn as_ref<T: Extension>(&self) -> &T {
|
||||
self.0.as_ref().as_any().downcast_ref::<T>().unwrap()
|
||||
}
|
||||
|
||||
fn as_mut<T: Extension>(&mut self) -> &mut T {
|
||||
self.0.as_mut().as_any_mut().downcast_mut::<T>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BoxedExtension {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct BoxedEntry {
|
||||
id: AnyValueId,
|
||||
value: BoxedExtension,
|
||||
}
|
||||
|
||||
impl BoxedEntry {
|
||||
pub(crate) fn new(r: impl Extension) -> Self {
|
||||
let id = AnyValueId::from(&r);
|
||||
let value = BoxedExtension::new(r);
|
||||
BoxedEntry { id, value }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Extension> From<R> for BoxedEntry {
|
||||
fn from(inner: R) -> Self {
|
||||
BoxedEntry::new(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
struct Number(usize);
|
||||
|
||||
#[test]
|
||||
fn get() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_mut() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
*ext.get_mut::<Number>().unwrap() = Number(20);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_empty() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_or_insert_default_full() {
|
||||
let mut ext = Extensions::default();
|
||||
ext.set(Number(10));
|
||||
assert_eq!(ext.get_or_insert_default::<Number>(), &Number(10));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set() {
|
||||
let mut ext = Extensions::default();
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
assert!(ext.set(Number(20)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(20)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(ext.remove::<Number>().is_none());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
assert!(!ext.set(Number(10)));
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
|
||||
assert!(ext.remove::<Number>().is_some());
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn update() {
|
||||
let mut ext = Extensions::default();
|
||||
assert_eq!(ext.get::<Number>(), None);
|
||||
|
||||
let mut new = Extensions::default();
|
||||
assert!(!new.set(Number(10)));
|
||||
|
||||
ext.update(&new);
|
||||
assert_eq!(ext.get::<Number>(), Some(&Number(10)));
|
||||
}
|
||||
}
|
67
vendor/clap_builder/src/builder/mod.rs
vendored
Normal file
67
vendor/clap_builder/src/builder/mod.rs
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
//! Define [`Command`] line [arguments][`Arg`]
|
||||
|
||||
mod action;
|
||||
mod app_settings;
|
||||
mod arg;
|
||||
mod arg_group;
|
||||
mod arg_predicate;
|
||||
mod arg_settings;
|
||||
mod command;
|
||||
mod ext;
|
||||
mod os_str;
|
||||
mod possible_value;
|
||||
mod range;
|
||||
mod resettable;
|
||||
mod str;
|
||||
mod styled_str;
|
||||
mod value_hint;
|
||||
mod value_parser;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
mod debug_asserts;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub mod styling;
|
||||
|
||||
pub use self::str::Str;
|
||||
pub use action::ArgAction;
|
||||
pub use arg::Arg;
|
||||
pub use arg_group::ArgGroup;
|
||||
pub use arg_predicate::ArgPredicate;
|
||||
pub use command::Command;
|
||||
pub use os_str::OsStr;
|
||||
pub use possible_value::PossibleValue;
|
||||
pub use range::ValueRange;
|
||||
pub use resettable::IntoResettable;
|
||||
pub use resettable::Resettable;
|
||||
pub use styled_str::StyledStr;
|
||||
pub use styling::Styles;
|
||||
pub use value_hint::ValueHint;
|
||||
pub use value_parser::_AutoValueParser;
|
||||
pub use value_parser::via_prelude;
|
||||
pub use value_parser::BoolValueParser;
|
||||
pub use value_parser::BoolishValueParser;
|
||||
pub use value_parser::EnumValueParser;
|
||||
pub use value_parser::FalseyValueParser;
|
||||
pub use value_parser::MapValueParser;
|
||||
pub use value_parser::NonEmptyStringValueParser;
|
||||
pub use value_parser::OsStringValueParser;
|
||||
pub use value_parser::PathBufValueParser;
|
||||
pub use value_parser::PossibleValuesParser;
|
||||
pub use value_parser::RangedI64ValueParser;
|
||||
pub use value_parser::RangedU64ValueParser;
|
||||
pub use value_parser::StringValueParser;
|
||||
pub use value_parser::TryMapValueParser;
|
||||
pub use value_parser::TypedValueParser;
|
||||
pub use value_parser::UnknownArgumentValueParser;
|
||||
pub use value_parser::ValueParser;
|
||||
pub use value_parser::ValueParserFactory;
|
||||
pub use value_parser::_AnonymousValueParser;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use self::str::Inner as StrInner;
|
||||
pub(crate) use action::CountType;
|
||||
pub(crate) use arg_settings::{ArgFlags, ArgSettings};
|
||||
pub(crate) use command::AppTag;
|
336
vendor/clap_builder/src/builder/os_str.rs
vendored
Normal file
336
vendor/clap_builder/src/builder/os_str.rs
vendored
Normal file
@ -0,0 +1,336 @@
|
||||
use crate::builder::Str;
|
||||
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `OsString`), enable the `string`
|
||||
/// feature
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct OsStr {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl OsStr {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the raw string as an `std::ffi::OsStr`
|
||||
pub fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.name.as_os_str()
|
||||
}
|
||||
|
||||
/// Get the raw string as an `OsString`
|
||||
pub fn to_os_string(&self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ OsStr> for OsStr {
|
||||
fn from(id: &'_ OsStr) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
match id.into_inner() {
|
||||
crate::builder::StrInner::Static(s) => Self::from_static_ref(std::ffi::OsStr::new(s)),
|
||||
crate::builder::StrInner::Owned(s) => Self::from_ref(std::ffi::OsStr::new(s.as_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
impl From<Str> for OsStr {
|
||||
fn from(id: Str) -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(id.into_inner().0))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "perf")]
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
match id.clone().into_inner() {
|
||||
crate::builder::StrInner::Static(s) => Self::from_static_ref(std::ffi::OsStr::new(s)),
|
||||
crate::builder::StrInner::Owned(s) => Self::from_ref(std::ffi::OsStr::new(s.as_ref())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for OsStr {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::ffi::OsString> for OsStr {
|
||||
fn from(name: std::ffi::OsString) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::ffi::OsString> for OsStr {
|
||||
fn from(name: &'_ std::ffi::OsString) -> Self {
|
||||
Self::from_ref(name.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for OsStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
Self::from_string(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for OsStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
Self::from_ref(name.as_str().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static std::ffi::OsStr> for OsStr {
|
||||
fn from(name: &'_ &'static std::ffi::OsStr) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for OsStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for OsStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref((*name).as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::ffi::OsString {
|
||||
fn from(name: OsStr) -> Self {
|
||||
name.name.into_os_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OsStr> for std::path::PathBuf {
|
||||
fn from(name: OsStr) -> Self {
|
||||
std::ffi::OsString::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for OsStr {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_os_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for OsStr {
|
||||
type Target = std::ffi::OsStr;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for OsStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &std::ffi::OsStr {
|
||||
self.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(*self, other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::string::String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsString> for OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<OsStr> for std::ffi::OsString {
|
||||
#[inline]
|
||||
fn eq(&self, other: &OsStr) -> bool {
|
||||
PartialEq::eq(self.as_os_str(), other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static std::ffi::OsStr),
|
||||
Owned(Box<std::ffi::OsStr>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
|
||||
Self::Owned(name.into_boxed_os_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(&'static std::ffi::OsStr);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_os_string(self) -> std::ffi::OsString {
|
||||
self.as_os_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref(std::ffi::OsStr::new(""))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Inner) -> bool {
|
||||
self.as_os_str() == other.as_os_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
|
||||
self.as_os_str().cmp(other.as_os_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_os_str().hash(state);
|
||||
}
|
||||
}
|
229
vendor/clap_builder/src/builder/possible_value.rs
vendored
Normal file
229
vendor/clap_builder/src/builder/possible_value.rs
vendored
Normal file
@ -0,0 +1,229 @@
|
||||
use crate::builder::IntoResettable;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::util::eq_ignore_case;
|
||||
|
||||
/// A possible value of an argument.
|
||||
///
|
||||
/// This is used for specifying [possible values] of [Args].
|
||||
///
|
||||
/// See also [`PossibleValuesParser`][crate::builder::PossibleValuesParser]
|
||||
///
|
||||
/// **NOTE:** Most likely you can use strings, rather than `PossibleValue` as it is only required
|
||||
/// to [hide] single values from help messages and shell completions or to attach [help] to
|
||||
/// possible values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Arg, builder::PossibleValue, ArgAction};
|
||||
/// let cfg = Arg::new("config")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .value_name("FILE")
|
||||
/// .value_parser([
|
||||
/// PossibleValue::new("fast"),
|
||||
/// PossibleValue::new("slow").help("slower than fast"),
|
||||
/// PossibleValue::new("secret speed").hide(true)
|
||||
/// ]);
|
||||
/// ```
|
||||
///
|
||||
/// [Args]: crate::Arg
|
||||
/// [possible values]: crate::builder::ValueParser::possible_values
|
||||
/// [hide]: PossibleValue::hide()
|
||||
/// [help]: PossibleValue::help()
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct PossibleValue {
|
||||
name: Str,
|
||||
help: Option<StyledStr>,
|
||||
aliases: Vec<Str>, // (name, visible)
|
||||
hide: bool,
|
||||
}
|
||||
|
||||
impl PossibleValue {
|
||||
/// Create a [`PossibleValue`] with its name.
|
||||
///
|
||||
/// The name will be used to decide whether this value was provided by the user to an argument.
|
||||
///
|
||||
/// **NOTE:** In case it is not [hidden] it will also be shown in help messages for arguments
|
||||
/// that use it as a [possible value] and have not hidden them through [`Arg::hide_possible_values(true)`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [hidden]: PossibleValue::hide
|
||||
/// [possible value]: crate::builder::PossibleValuesParser
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
pub fn new(name: impl Into<Str>) -> Self {
|
||||
PossibleValue {
|
||||
name: name.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the help description of the value.
|
||||
///
|
||||
/// This is typically displayed in completions (where supported) and should be a short, one-line
|
||||
/// description.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .help("not fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn help(mut self, help: impl IntoResettable<StyledStr>) -> Self {
|
||||
self.help = help.into_resettable().into_option();
|
||||
self
|
||||
}
|
||||
|
||||
/// Hides this value from help and shell completions.
|
||||
///
|
||||
/// This is an alternative to hiding through [`Arg::hide_possible_values(true)`], if you only
|
||||
/// want to hide some values.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("secret")
|
||||
/// .hide(true)
|
||||
/// # ;
|
||||
/// ```
|
||||
/// [`Arg::hide_possible_values(true)`]: crate::Arg::hide_possible_values()
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn hide(mut self, yes: bool) -> Self {
|
||||
self.hide = yes;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets a *hidden* alias for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .alias("not-fast")
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn alias(mut self, name: impl IntoResettable<Str>) -> Self {
|
||||
if let Some(name) = name.into_resettable().into_option() {
|
||||
self.aliases.push(name);
|
||||
} else {
|
||||
self.aliases.clear();
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets multiple *hidden* aliases for this argument value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// PossibleValue::new("slow")
|
||||
/// .aliases(["not-fast", "snake-like"])
|
||||
/// # ;
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub fn aliases(mut self, names: impl IntoIterator<Item = impl Into<Str>>) -> Self {
|
||||
self.aliases.extend(names.into_iter().map(|a| a.into()));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl PossibleValue {
|
||||
/// Get the name of the argument value
|
||||
#[inline]
|
||||
pub fn get_name(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
/// Get the help specified for this argument, if any
|
||||
#[inline]
|
||||
pub fn get_help(&self) -> Option<&StyledStr> {
|
||||
self.help.as_ref()
|
||||
}
|
||||
|
||||
/// Report if [`PossibleValue::hide`] is set
|
||||
#[inline]
|
||||
pub fn is_hide_set(&self) -> bool {
|
||||
self.hide
|
||||
}
|
||||
|
||||
/// Report if PossibleValue is not hidden and has a help message
|
||||
pub(crate) fn should_show_help(&self) -> bool {
|
||||
!self.hide && self.help.is_some()
|
||||
}
|
||||
|
||||
/// Get the name if argument value is not hidden, `None` otherwise,
|
||||
/// but wrapped in quotes if it contains whitespace
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn get_visible_quoted_name(&self) -> Option<std::borrow::Cow<'_, str>> {
|
||||
if !self.hide {
|
||||
Some(if self.name.contains(char::is_whitespace) {
|
||||
format!("{:?}", self.name).into()
|
||||
} else {
|
||||
self.name.as_str().into()
|
||||
})
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns all valid values of the argument value.
|
||||
///
|
||||
/// Namely the name and all aliases.
|
||||
pub fn get_name_and_aliases(&self) -> impl Iterator<Item = &str> + '_ {
|
||||
std::iter::once(self.get_name()).chain(self.aliases.iter().map(|s| s.as_str()))
|
||||
}
|
||||
|
||||
/// Tests if the value is valid for this argument value
|
||||
///
|
||||
/// The value is valid if it is either the name or one of the aliases.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::PossibleValue;
|
||||
/// let arg_value = PossibleValue::new("fast").alias("not-slow");
|
||||
///
|
||||
/// assert!(arg_value.matches("fast", false));
|
||||
/// assert!(arg_value.matches("not-slow", false));
|
||||
///
|
||||
/// assert!(arg_value.matches("FAST", true));
|
||||
/// assert!(!arg_value.matches("FAST", false));
|
||||
/// ```
|
||||
pub fn matches(&self, value: &str, ignore_case: bool) -> bool {
|
||||
if ignore_case {
|
||||
self.get_name_and_aliases()
|
||||
.any(|name| eq_ignore_case(name, value))
|
||||
} else {
|
||||
self.get_name_and_aliases().any(|name| name == value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Into<Str>> From<S> for PossibleValue {
|
||||
fn from(s: S) -> Self {
|
||||
Self::new(s)
|
||||
}
|
||||
}
|
286
vendor/clap_builder/src/builder/range.rs
vendored
Normal file
286
vendor/clap_builder/src/builder/range.rs
vendored
Normal file
@ -0,0 +1,286 @@
|
||||
/// Values per occurrence for an argument
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ValueRange {
|
||||
start_inclusive: usize,
|
||||
end_inclusive: usize,
|
||||
}
|
||||
|
||||
impl ValueRange {
|
||||
/// Nor argument values, or a flag
|
||||
pub const EMPTY: Self = Self {
|
||||
start_inclusive: 0,
|
||||
end_inclusive: 0,
|
||||
};
|
||||
|
||||
/// A single argument value, the most common case for options
|
||||
pub const SINGLE: Self = Self {
|
||||
start_inclusive: 1,
|
||||
end_inclusive: 1,
|
||||
};
|
||||
|
||||
/// Create a range
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If the end is less than the start (debug builds)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// let range = ValueRange::new(5..10);
|
||||
/// let range = ValueRange::new(5..=10);
|
||||
/// let range = ValueRange::new(5..);
|
||||
/// let range = ValueRange::new(..10);
|
||||
/// let range = ValueRange::new(..=10);
|
||||
/// ```
|
||||
///
|
||||
/// While this will panic:
|
||||
/// ```should_panic
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(10..5); // Panics!
|
||||
/// ```
|
||||
pub fn new(range: impl Into<Self>) -> Self {
|
||||
range.into()
|
||||
}
|
||||
|
||||
pub(crate) fn raw(start_inclusive: usize, end_inclusive: usize) -> Self {
|
||||
debug_assert!(start_inclusive <= end_inclusive);
|
||||
Self {
|
||||
start_inclusive,
|
||||
end_inclusive,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fewest number of values the argument accepts
|
||||
pub fn min_values(&self) -> usize {
|
||||
self.start_inclusive
|
||||
}
|
||||
|
||||
/// Most number of values the argument accepts
|
||||
pub fn max_values(&self) -> usize {
|
||||
self.end_inclusive
|
||||
}
|
||||
|
||||
/// Report whether the argument takes any values (ie is a flag)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::ValueRange;
|
||||
/// let range = ValueRange::new(5);
|
||||
/// assert!(range.takes_values());
|
||||
///
|
||||
/// let range = ValueRange::new(0);
|
||||
/// assert!(!range.takes_values());
|
||||
/// ```
|
||||
pub fn takes_values(&self) -> bool {
|
||||
self.end_inclusive != 0
|
||||
}
|
||||
|
||||
pub(crate) fn is_unbounded(&self) -> bool {
|
||||
self.end_inclusive == usize::MAX
|
||||
}
|
||||
|
||||
pub(crate) fn is_fixed(&self) -> bool {
|
||||
self.start_inclusive == self.end_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn is_multiple(&self) -> bool {
|
||||
self.start_inclusive != self.end_inclusive || 1 < self.start_inclusive
|
||||
}
|
||||
|
||||
pub(crate) fn num_values(&self) -> Option<usize> {
|
||||
self.is_fixed().then_some(self.start_inclusive)
|
||||
}
|
||||
|
||||
pub(crate) fn accepts_more(&self, current: usize) -> bool {
|
||||
current < self.end_inclusive
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::RangeBounds<usize> for ValueRange {
|
||||
fn start_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.start_inclusive)
|
||||
}
|
||||
|
||||
fn end_bound(&self) -> std::ops::Bound<&usize> {
|
||||
std::ops::Bound::Included(&self.end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ValueRange {
|
||||
fn default() -> Self {
|
||||
Self::SINGLE
|
||||
}
|
||||
}
|
||||
|
||||
impl From<usize> for ValueRange {
|
||||
fn from(fixed: usize) -> Self {
|
||||
(fixed..=fixed).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::Range<usize>> for ValueRange {
|
||||
fn from(range: std::ops::Range<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFull> for ValueRange {
|
||||
fn from(_: std::ops::RangeFull) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = usize::MAX;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeFrom<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeFrom<usize>) -> Self {
|
||||
let start_inclusive = range.start;
|
||||
let end_inclusive = usize::MAX;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeTo<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeTo<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end.saturating_sub(1);
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeInclusive<usize>) -> Self {
|
||||
let start_inclusive = *range.start();
|
||||
let end_inclusive = *range.end();
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::ops::RangeToInclusive<usize>> for ValueRange {
|
||||
fn from(range: std::ops::RangeToInclusive<usize>) -> Self {
|
||||
let start_inclusive = 0;
|
||||
let end_inclusive = range.end;
|
||||
Self::raw(start_inclusive, end_inclusive)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
ok!(self.start_inclusive.fmt(f));
|
||||
if !self.is_fixed() {
|
||||
ok!("..=".fmt(f));
|
||||
ok!(self.end_inclusive.fmt(f));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ValueRange {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{self}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
use std::ops::RangeBounds;
|
||||
|
||||
#[test]
|
||||
fn from_fixed() {
|
||||
let range: ValueRange = 5.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&5));
|
||||
assert!(range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(5));
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_fixed_empty() {
|
||||
let range: ValueRange = 0.into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&0));
|
||||
assert!(range.is_fixed());
|
||||
assert!(!range.is_multiple());
|
||||
assert_eq!(range.num_values(), Some(0));
|
||||
assert!(!range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range() {
|
||||
let range: ValueRange = (5..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_inclusive() {
|
||||
let range: ValueRange = (5..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_full() {
|
||||
let range: ValueRange = (..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_from() {
|
||||
let range: ValueRange = (5..).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&5));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&usize::MAX));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to() {
|
||||
let range: ValueRange = (..10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&9));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_range_to_inclusive() {
|
||||
let range: ValueRange = (..=10).into();
|
||||
assert_eq!(range.start_bound(), std::ops::Bound::Included(&0));
|
||||
assert_eq!(range.end_bound(), std::ops::Bound::Included(&10));
|
||||
assert!(!range.is_fixed());
|
||||
assert!(range.is_multiple());
|
||||
assert_eq!(range.num_values(), None);
|
||||
assert!(range.takes_values());
|
||||
}
|
||||
}
|
212
vendor/clap_builder/src/builder/resettable.rs
vendored
Normal file
212
vendor/clap_builder/src/builder/resettable.rs
vendored
Normal file
@ -0,0 +1,212 @@
|
||||
// Unlike `impl Into<Option<T>>` or `Option<impl Into<T>>`, this isn't ambiguous for the `None`
|
||||
// case.
|
||||
|
||||
use crate::builder::ArgAction;
|
||||
use crate::builder::OsStr;
|
||||
use crate::builder::Str;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::ValueHint;
|
||||
use crate::builder::ValueParser;
|
||||
use crate::builder::ValueRange;
|
||||
|
||||
/// Clearable builder value
|
||||
///
|
||||
/// This allows a builder function to both accept any value that can [`Into::into`] `T` (like
|
||||
/// `&str` into `OsStr`) as well as `None` to reset it to the default. This is needed to
|
||||
/// workaround a limitation where you can't have a function argument that is `impl Into<Option<T>>`
|
||||
/// where `T` is `impl Into<S>` accept `None` as its type is ambiguous.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// fn common() -> Command {
|
||||
/// Command::new("cli")
|
||||
/// .arg(Arg::new("input").short('i').long("input"))
|
||||
/// }
|
||||
/// let mut command = common();
|
||||
/// command.mut_arg("input", |arg| arg.short(None));
|
||||
/// ```
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Resettable<T> {
|
||||
/// Overwrite builder value
|
||||
Value(T),
|
||||
/// Reset builder value
|
||||
Reset,
|
||||
}
|
||||
|
||||
impl<T> Resettable<T> {
|
||||
pub(crate) fn into_option(self) -> Option<T> {
|
||||
match self {
|
||||
Self::Value(t) => Some(t),
|
||||
Self::Reset => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<T> for Resettable<T> {
|
||||
fn from(other: T) -> Self {
|
||||
Self::Value(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Option<T>> for Resettable<T> {
|
||||
fn from(other: Option<T>) -> Self {
|
||||
match other {
|
||||
Some(inner) => Self::Value(inner),
|
||||
None => Self::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert to the intended resettable type
|
||||
pub trait IntoResettable<T> {
|
||||
/// Convert to the intended resettable type
|
||||
fn into_resettable(self) -> Resettable<T>;
|
||||
}
|
||||
|
||||
impl IntoResettable<char> for Option<char> {
|
||||
fn into_resettable(self) -> Resettable<char> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<usize> for Option<usize> {
|
||||
fn into_resettable(self) -> Resettable<usize> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ArgAction> for Option<ArgAction> {
|
||||
fn into_resettable(self) -> Resettable<ArgAction> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueHint> for Option<ValueHint> {
|
||||
fn into_resettable(self) -> Resettable<ValueHint> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueParser> for Option<ValueParser> {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<StyledStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<OsStr> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<Str> for Option<&'static str> {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
match self {
|
||||
Some(s) => Resettable::Value(s.into()),
|
||||
None => Resettable::Reset,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoResettable<T> for Resettable<T> {
|
||||
fn into_resettable(self) -> Resettable<T> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<char> for char {
|
||||
fn into_resettable(self) -> Resettable<char> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<usize> for usize {
|
||||
fn into_resettable(self) -> Resettable<usize> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ArgAction> for ArgAction {
|
||||
fn into_resettable(self) -> Resettable<ArgAction> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoResettable<ValueHint> for ValueHint {
|
||||
fn into_resettable(self) -> Resettable<ValueHint> {
|
||||
Resettable::Value(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueRange>> IntoResettable<ValueRange> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueRange> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<ValueParser>> IntoResettable<ValueParser> for I {
|
||||
fn into_resettable(self) -> Resettable<ValueParser> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<String>> IntoResettable<String> for I {
|
||||
fn into_resettable(self) -> Resettable<String> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<StyledStr>> IntoResettable<StyledStr> for I {
|
||||
fn into_resettable(self) -> Resettable<StyledStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<OsStr>> IntoResettable<OsStr> for I {
|
||||
fn into_resettable(self) -> Resettable<OsStr> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<Str>> IntoResettable<Str> for I {
|
||||
fn into_resettable(self) -> Resettable<Str> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: Into<crate::Id>> IntoResettable<crate::Id> for I {
|
||||
fn into_resettable(self) -> Resettable<crate::Id> {
|
||||
Resettable::Value(self.into())
|
||||
}
|
||||
}
|
310
vendor/clap_builder/src/builder/str.rs
vendored
Normal file
310
vendor/clap_builder/src/builder/str.rs
vendored
Normal file
@ -0,0 +1,310 @@
|
||||
/// A UTF-8-encoded fixed string
|
||||
///
|
||||
/// **NOTE:** To support dynamic values (i.e. `String`), enable the `string`
|
||||
/// feature
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Str {
|
||||
name: Inner,
|
||||
}
|
||||
|
||||
impl Str {
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
Self {
|
||||
name: Inner::from_string(name),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self {
|
||||
name: Inner::from_static_ref(name),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> Inner {
|
||||
self.name
|
||||
}
|
||||
|
||||
/// Get the raw string of the `Str`
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for Str {
|
||||
fn from(id: &'_ Str) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for Str {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
Self::from_string(name)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for Str {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
Self::from_ref(name.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Str {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for Str {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self::from_static_ref(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for String {
|
||||
fn from(name: Str) -> Self {
|
||||
name.name.into_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for Vec<u8> {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::ffi::OsString {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for std::path::PathBuf {
|
||||
fn from(name: Str) -> Self {
|
||||
String::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Str {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Str {
|
||||
type Target = str;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::ffi::OsStr {
|
||||
(**self).as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<std::path::Path> for Str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &std::path::Path {
|
||||
std::path::Path::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<str> for Str {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ std::ffi::OsStr> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for &'_ std::ffi::OsStr {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Str> for std::string::String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum Inner {
|
||||
Static(&'static str),
|
||||
Owned(Box<str>),
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_string(name: std::string::String) -> Self {
|
||||
Self::Owned(name.into_boxed_str())
|
||||
}
|
||||
|
||||
pub(crate) fn from_ref(name: &str) -> Self {
|
||||
Self::Owned(Box::from(name))
|
||||
}
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self::Static(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Self::Static(s) => s,
|
||||
Self::Owned(s) => s.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
match self {
|
||||
Self::Static(s) => s.to_owned(),
|
||||
Self::Owned(s) => s.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "string"))]
|
||||
pub(crate) mod inner {
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Inner(pub(crate) &'static str);
|
||||
|
||||
impl Inner {
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
|
||||
pub(crate) fn as_str(&self) -> &str {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(crate) fn into_string(self) -> String {
|
||||
self.as_str().to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) use inner::Inner;
|
||||
|
||||
impl Default for Inner {
|
||||
fn default() -> Self {
|
||||
Self::from_static_ref("")
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Inner {
|
||||
fn eq(&self, other: &Inner) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Inner {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Inner {
|
||||
fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
|
||||
self.as_str().cmp(other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Inner {}
|
||||
|
||||
impl std::hash::Hash for Inner {
|
||||
#[inline]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state);
|
||||
}
|
||||
}
|
210
vendor/clap_builder/src/builder/styled_str.rs
vendored
Normal file
210
vendor/clap_builder/src/builder/styled_str.rs
vendored
Normal file
@ -0,0 +1,210 @@
|
||||
#![cfg_attr(not(feature = "usage"), allow(dead_code))]
|
||||
|
||||
/// Terminal-styling container
|
||||
///
|
||||
/// Styling may be encoded as [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// // `cstr!` converts tags to ANSI codes
|
||||
/// let after_help: &'static str = color_print::cstr!(
|
||||
/// r#"<bold><underline>Examples</underline></bold>
|
||||
///
|
||||
/// <dim>$</dim> <bold>mybin --input file.toml</bold>
|
||||
/// "#);
|
||||
///
|
||||
/// let cmd = clap::Command::new("mybin")
|
||||
/// .after_help(after_help) // The `&str` gets converted into a `StyledStr`
|
||||
/// // ...
|
||||
/// # ;
|
||||
/// ```
|
||||
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct StyledStr(String);
|
||||
|
||||
impl StyledStr {
|
||||
/// Create an empty buffer
|
||||
pub const fn new() -> Self {
|
||||
Self(String::new())
|
||||
}
|
||||
|
||||
/// Display using [ANSI Escape Code](https://en.wikipedia.org/wiki/ANSI_escape_code) styling
|
||||
#[cfg(feature = "color")]
|
||||
pub fn ansi(&self) -> impl std::fmt::Display + '_ {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
/// May allow the compiler to consolidate the `Drop`s for `msg`, reducing code size compared to
|
||||
/// `styled.push_str(&msg)`
|
||||
pub(crate) fn push_string(&mut self, msg: String) {
|
||||
self.0.push_str(&msg);
|
||||
}
|
||||
|
||||
pub(crate) fn push_str(&mut self, msg: &str) {
|
||||
self.0.push_str(msg);
|
||||
}
|
||||
|
||||
pub(crate) fn trim_start_lines(&mut self) {
|
||||
if let Some(pos) = self.0.find('\n') {
|
||||
let (leading, help) = self.0.split_at(pos + 1);
|
||||
if leading.trim().is_empty() {
|
||||
self.0 = help.to_owned()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn trim_end(&mut self) {
|
||||
self.0 = self.0.trim_end().to_owned()
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn replace_newline_var(&mut self) {
|
||||
self.0 = self.0.replace("{n}", "\n");
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn indent(&mut self, initial: &str, trailing: &str) {
|
||||
self.0.insert_str(0, initial);
|
||||
|
||||
let mut line_sep = "\n".to_owned();
|
||||
line_sep.push_str(trailing);
|
||||
self.0 = self.0.replace('\n', &line_sep);
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "wrap_help"), feature = "help"))]
|
||||
pub(crate) fn wrap(&mut self, _hard_width: usize) {}
|
||||
|
||||
#[cfg(feature = "wrap_help")]
|
||||
pub(crate) fn wrap(&mut self, hard_width: usize) {
|
||||
let mut new = String::with_capacity(self.0.len());
|
||||
|
||||
let mut last = 0;
|
||||
let mut wrapper = crate::output::textwrap::wrap_algorithms::LineWrapper::new(hard_width);
|
||||
for content in self.iter_text() {
|
||||
// Preserve styling
|
||||
let current = content.as_ptr() as usize - self.0.as_str().as_ptr() as usize;
|
||||
if last != current {
|
||||
new.push_str(&self.0.as_str()[last..current]);
|
||||
}
|
||||
last = current + content.len();
|
||||
|
||||
for (i, line) in content.split_inclusive('\n').enumerate() {
|
||||
if 0 < i {
|
||||
// reset char count on newline, skipping the start as we might have carried
|
||||
// over from a prior block of styled text
|
||||
wrapper.reset();
|
||||
}
|
||||
let line = crate::output::textwrap::word_separators::find_words_ascii_space(line)
|
||||
.collect::<Vec<_>>();
|
||||
new.extend(wrapper.wrap(line));
|
||||
}
|
||||
}
|
||||
if last != self.0.len() {
|
||||
new.push_str(&self.0.as_str()[last..]);
|
||||
}
|
||||
new = new.trim_end().to_owned();
|
||||
|
||||
self.0 = new;
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn display_width(&self) -> usize {
|
||||
let mut width = 0;
|
||||
for c in self.iter_text() {
|
||||
width += crate::output::display_width(c);
|
||||
}
|
||||
width
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
#[cfg(feature = "help")]
|
||||
pub(crate) fn as_styled_str(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
|
||||
#[cfg(feature = "color")]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
anstream::adapter::strip_str(&self.0)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "color"))]
|
||||
pub(crate) fn iter_text(&self) -> impl Iterator<Item = &str> {
|
||||
[self.0.as_str()].into_iter()
|
||||
}
|
||||
|
||||
pub(crate) fn push_styled(&mut self, other: &Self) {
|
||||
self.0.push_str(&other.0);
|
||||
}
|
||||
|
||||
pub(crate) fn write_to(&self, buffer: &mut dyn std::io::Write) -> std::io::Result<()> {
|
||||
ok!(buffer.write_all(self.0.as_bytes()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ StyledStr {
|
||||
fn default() -> Self {
|
||||
static DEFAULT: StyledStr = StyledStr::new();
|
||||
&DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::string::String> for StyledStr {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
StyledStr(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ std::string::String> for StyledStr {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
let mut styled = StyledStr::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for StyledStr {
|
||||
fn from(name: &'static str) -> Self {
|
||||
let mut styled = StyledStr::new();
|
||||
styled.push_str(name);
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for StyledStr {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
StyledStr::from(*name)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Write for StyledStr {
|
||||
#[inline]
|
||||
fn write_str(&mut self, s: &str) -> Result<(), std::fmt::Error> {
|
||||
self.0.push_str(s);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_char(&mut self, c: char) -> Result<(), std::fmt::Error> {
|
||||
self.0.push(c);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Color-unaware printing. Never uses coloring.
|
||||
impl std::fmt::Display for StyledStr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
for part in self.iter_text() {
|
||||
part.fmt(f)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
179
vendor/clap_builder/src/builder/styling.rs
vendored
Normal file
179
vendor/clap_builder/src/builder/styling.rs
vendored
Normal file
@ -0,0 +1,179 @@
|
||||
//! Terminal [`Styles`] for help and error output
|
||||
|
||||
pub use anstyle::*;
|
||||
|
||||
/// Terminal styling definitions
|
||||
///
|
||||
/// See also [`Command::styles`][crate::Command::styles].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// clap v3 styling
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::builder::styling::*;
|
||||
/// let styles = Styles::styled()
|
||||
/// .header(AnsiColor::Yellow.on_default())
|
||||
/// .usage(AnsiColor::Green.on_default())
|
||||
/// .literal(AnsiColor::Green.on_default())
|
||||
/// .placeholder(AnsiColor::Green.on_default());
|
||||
/// ```
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_copy_implementations)] // Large enough type that I want an explicit `clone()` for now
|
||||
pub struct Styles {
|
||||
header: anstyle::Style,
|
||||
error: anstyle::Style,
|
||||
usage: anstyle::Style,
|
||||
literal: anstyle::Style,
|
||||
placeholder: anstyle::Style,
|
||||
valid: anstyle::Style,
|
||||
invalid: anstyle::Style,
|
||||
}
|
||||
|
||||
impl Styles {
|
||||
/// No terminal styling
|
||||
pub const fn plain() -> Self {
|
||||
Self {
|
||||
header: anstyle::Style::new(),
|
||||
error: anstyle::Style::new(),
|
||||
usage: anstyle::Style::new(),
|
||||
literal: anstyle::Style::new(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new(),
|
||||
invalid: anstyle::Style::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Default terminal styling
|
||||
pub const fn styled() -> Self {
|
||||
#[cfg(feature = "color")]
|
||||
{
|
||||
Self {
|
||||
header: anstyle::Style::new().bold().underline(),
|
||||
error: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Red)))
|
||||
.bold(),
|
||||
usage: anstyle::Style::new().bold().underline(),
|
||||
literal: anstyle::Style::new().bold(),
|
||||
placeholder: anstyle::Style::new(),
|
||||
valid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Green))),
|
||||
invalid: anstyle::Style::new()
|
||||
.fg_color(Some(anstyle::Color::Ansi(anstyle::AnsiColor::Yellow))),
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "color"))]
|
||||
{
|
||||
Self::plain()
|
||||
}
|
||||
}
|
||||
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline]
|
||||
pub const fn header(mut self, style: anstyle::Style) -> Self {
|
||||
self.header = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline]
|
||||
pub const fn error(mut self, style: anstyle::Style) -> Self {
|
||||
self.error = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline]
|
||||
pub const fn usage(mut self, style: anstyle::Style) -> Self {
|
||||
self.usage = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline]
|
||||
pub const fn literal(mut self, style: anstyle::Style) -> Self {
|
||||
self.literal = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline]
|
||||
pub const fn placeholder(mut self, style: anstyle::Style) -> Self {
|
||||
self.placeholder = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline]
|
||||
pub const fn valid(mut self, style: anstyle::Style) -> Self {
|
||||
self.valid = style;
|
||||
self
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline]
|
||||
pub const fn invalid(mut self, style: anstyle::Style) -> Self {
|
||||
self.invalid = style;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Reflection
|
||||
impl Styles {
|
||||
/// General Heading style, e.g. [`help_heading`][crate::Arg::help_heading]
|
||||
#[inline(always)]
|
||||
pub const fn get_header(&self) -> &anstyle::Style {
|
||||
&self.header
|
||||
}
|
||||
|
||||
/// Error heading
|
||||
#[inline(always)]
|
||||
pub const fn get_error(&self) -> &anstyle::Style {
|
||||
&self.error
|
||||
}
|
||||
|
||||
/// Usage heading
|
||||
#[inline(always)]
|
||||
pub const fn get_usage(&self) -> &anstyle::Style {
|
||||
&self.usage
|
||||
}
|
||||
|
||||
/// Literal command-line syntax, e.g. `--help`
|
||||
#[inline(always)]
|
||||
pub const fn get_literal(&self) -> &anstyle::Style {
|
||||
&self.literal
|
||||
}
|
||||
|
||||
/// Descriptions within command-line syntax, e.g. [`value_name`][crate::Arg::value_name]
|
||||
#[inline(always)]
|
||||
pub const fn get_placeholder(&self) -> &anstyle::Style {
|
||||
&self.placeholder
|
||||
}
|
||||
|
||||
/// Highlight suggested usage
|
||||
#[inline(always)]
|
||||
pub const fn get_valid(&self) -> &anstyle::Style {
|
||||
&self.valid
|
||||
}
|
||||
|
||||
/// Highlight invalid usage
|
||||
#[inline(always)]
|
||||
pub const fn get_invalid(&self) -> &anstyle::Style {
|
||||
&self.invalid
|
||||
}
|
||||
}
|
||||
|
||||
impl super::AppTag for Styles {}
|
||||
|
||||
impl Default for Styles {
|
||||
fn default() -> Self {
|
||||
Self::styled()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for &'_ Styles {
|
||||
fn default() -> Self {
|
||||
const STYLES: Styles = Styles::styled();
|
||||
&STYLES
|
||||
}
|
||||
}
|
56
vendor/clap_builder/src/builder/tests.rs
vendored
Normal file
56
vendor/clap_builder/src/builder/tests.rs
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
use crate::Arg;
|
||||
use crate::Command;
|
||||
|
||||
#[test]
|
||||
fn propagate_version() {
|
||||
let mut cmd = Command::new("test")
|
||||
.propagate_version(true)
|
||||
.version("1.1")
|
||||
.subcommand(Command::new("sub1"));
|
||||
cmd._propagate();
|
||||
assert_eq!(
|
||||
cmd.get_subcommands().next().unwrap().get_version(),
|
||||
Some("1.1")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn global_setting() {
|
||||
let mut cmd = Command::new("test")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("subcmd"));
|
||||
cmd._propagate();
|
||||
assert!(cmd
|
||||
.get_subcommands()
|
||||
.find(|s| s.get_name() == "subcmd")
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set());
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Command is not Send + Sync
|
||||
#[test]
|
||||
fn app_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Command::new("test"))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_2090() {
|
||||
let mut cmd = Command::new("cmd")
|
||||
.disable_version_flag(true)
|
||||
.subcommand(Command::new("sub"));
|
||||
cmd._build_self(false);
|
||||
|
||||
assert!(cmd
|
||||
.get_subcommands()
|
||||
.next()
|
||||
.unwrap()
|
||||
.is_disable_version_flag_set());
|
||||
}
|
||||
|
||||
// This test will *fail to compile* if Arg is not Send + Sync
|
||||
#[test]
|
||||
fn arg_send_sync() {
|
||||
fn foo<T: Send + Sync>(_: T) {}
|
||||
foo(Arg::new("test"))
|
||||
}
|
90
vendor/clap_builder/src/builder/value_hint.rs
vendored
Normal file
90
vendor/clap_builder/src/builder/value_hint.rs
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Provide shell with hint on how to complete an argument.
|
||||
///
|
||||
/// See [Arg::value_hint][crate::Arg::value_hint] to set this on an argument.
|
||||
///
|
||||
/// See the `clap_complete` crate for completion script generation.
|
||||
///
|
||||
/// Overview of which hints are supported by which shell:
|
||||
///
|
||||
/// | Hint | zsh | fish[^1]|
|
||||
/// | ---------------------- | --- | ------- |
|
||||
/// | `AnyPath` | Yes | Yes |
|
||||
/// | `FilePath` | Yes | Yes |
|
||||
/// | `DirPath` | Yes | Yes |
|
||||
/// | `ExecutablePath` | Yes | Partial |
|
||||
/// | `CommandName` | Yes | Yes |
|
||||
/// | `CommandString` | Yes | Partial |
|
||||
/// | `CommandWithArguments` | Yes | |
|
||||
/// | `Username` | Yes | Yes |
|
||||
/// | `Hostname` | Yes | Yes |
|
||||
/// | `Url` | Yes | |
|
||||
/// | `EmailAddress` | Yes | |
|
||||
///
|
||||
/// [^1]: fish completions currently only support named arguments (e.g. -o or --opt), not
|
||||
/// positional arguments.
|
||||
#[derive(Debug, Default, PartialEq, Eq, Hash, Copy, Clone)]
|
||||
#[non_exhaustive]
|
||||
pub enum ValueHint {
|
||||
/// Default value if hint is not specified. Follows shell default behavior, which is usually
|
||||
/// auto-completing filenames.
|
||||
#[default]
|
||||
Unknown,
|
||||
/// None of the hints below apply. Disables shell completion for this argument.
|
||||
Other,
|
||||
/// Any existing path.
|
||||
AnyPath,
|
||||
/// Path to a file.
|
||||
FilePath,
|
||||
/// Path to a directory.
|
||||
DirPath,
|
||||
/// Path to an executable file.
|
||||
ExecutablePath,
|
||||
/// Name of a command, without arguments. May be relative to PATH, or full path to executable.
|
||||
CommandName,
|
||||
/// A single string containing a command and its arguments.
|
||||
CommandString,
|
||||
/// Capture the remaining arguments as a command name and arguments for that command. This is
|
||||
/// common when writing shell wrappers that execute anther command, for example `sudo` or `env`.
|
||||
///
|
||||
/// This hint is special, the argument must be a positional argument and have
|
||||
/// [`.num_args(1..)`] and Command must use [`Command::trailing_var_arg(true)`]. The result is that the
|
||||
/// command line `my_app ls -la /` will be parsed as `["ls", "-la", "/"]` and clap won't try to
|
||||
/// parse the `-la` argument itself.
|
||||
///
|
||||
/// [`Command::trailing_var_arg(true)`]: crate::Command::trailing_var_arg
|
||||
/// [`.num_args(1..)`]: crate::Arg::num_args()
|
||||
CommandWithArguments,
|
||||
/// Name of a local operating system user.
|
||||
Username,
|
||||
/// Host name of a computer.
|
||||
/// Shells usually parse `/etc/hosts` and `.ssh/known_hosts` to complete hostnames.
|
||||
Hostname,
|
||||
/// Complete web address.
|
||||
Url,
|
||||
/// Email address.
|
||||
EmailAddress,
|
||||
}
|
||||
|
||||
impl FromStr for ValueHint {
|
||||
type Err = String;
|
||||
fn from_str(s: &str) -> Result<Self, <Self as FromStr>::Err> {
|
||||
Ok(match &*s.to_ascii_lowercase() {
|
||||
"unknown" => ValueHint::Unknown,
|
||||
"other" => ValueHint::Other,
|
||||
"anypath" => ValueHint::AnyPath,
|
||||
"filepath" => ValueHint::FilePath,
|
||||
"dirpath" => ValueHint::DirPath,
|
||||
"executablepath" => ValueHint::ExecutablePath,
|
||||
"commandname" => ValueHint::CommandName,
|
||||
"commandstring" => ValueHint::CommandString,
|
||||
"commandwitharguments" => ValueHint::CommandWithArguments,
|
||||
"username" => ValueHint::Username,
|
||||
"hostname" => ValueHint::Hostname,
|
||||
"url" => ValueHint::Url,
|
||||
"emailaddress" => ValueHint::EmailAddress,
|
||||
_ => return Err(format!("unknown ValueHint: `{s}`")),
|
||||
})
|
||||
}
|
||||
}
|
2712
vendor/clap_builder/src/builder/value_parser.rs
vendored
Normal file
2712
vendor/clap_builder/src/builder/value_parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
361
vendor/clap_builder/src/derive.rs
vendored
Normal file
361
vendor/clap_builder/src/derive.rs
vendored
Normal file
@ -0,0 +1,361 @@
|
||||
//! This module contains traits that are usable with the `#[derive(...)]`
|
||||
//! macros in `clap_derive`.
|
||||
|
||||
use crate::builder::PossibleValue;
|
||||
use crate::{ArgMatches, Command, Error};
|
||||
|
||||
use std::ffi::OsString;
|
||||
|
||||
/// Parse command-line arguments into `Self`.
|
||||
///
|
||||
/// The primary one-stop-shop trait used to create an instance of a `clap`
|
||||
/// [`Command`], conduct the parsing, and turn the resulting [`ArgMatches`] back
|
||||
/// into concrete instance of the user struct.
|
||||
///
|
||||
/// This trait is primarily a convenience on top of [`FromArgMatches`] +
|
||||
/// [`CommandFactory`] which uses those two underlying traits to build the two
|
||||
/// fundamental functions `parse` which uses the `std::env::args_os` iterator,
|
||||
/// and `parse_from` which allows the consumer to supply the iterator (along
|
||||
/// with fallible options for each).
|
||||
///
|
||||
/// See also [`Subcommand`] and [`Args`].
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
pub trait Parser: FromArgMatches + CommandFactory + Sized {
|
||||
/// Parse from `std::env::args_os()`, exit on error
|
||||
fn parse() -> Self {
|
||||
let mut matches = <Self as CommandFactory>::command().get_matches();
|
||||
let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
|
||||
.map_err(format_error::<Self>);
|
||||
match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse from `std::env::args_os()`, return Err on error.
|
||||
fn try_parse() -> Result<Self, Error> {
|
||||
let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches());
|
||||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Parse from iterator, exit on error
|
||||
fn parse_from<I, T>(itr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = <Self as CommandFactory>::command().get_matches_from(itr);
|
||||
let res = <Self as FromArgMatches>::from_arg_matches_mut(&mut matches)
|
||||
.map_err(format_error::<Self>);
|
||||
match res {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches_from`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse from iterator, return Err on error.
|
||||
fn try_parse_from<I, T>(itr: I) -> Result<Self, Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = ok!(<Self as CommandFactory>::command().try_get_matches_from(itr));
|
||||
<Self as FromArgMatches>::from_arg_matches_mut(&mut matches).map_err(format_error::<Self>)
|
||||
}
|
||||
|
||||
/// Update from iterator, exit on error
|
||||
fn update_from<I, T>(&mut self, itr: I)
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches = <Self as CommandFactory>::command_for_update().get_matches_from(itr);
|
||||
let res = <Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
|
||||
.map_err(format_error::<Self>);
|
||||
if let Err(e) = res {
|
||||
// Since this is more of a development-time error, we aren't doing as fancy of a quit
|
||||
// as `get_matches_from`
|
||||
e.exit()
|
||||
}
|
||||
}
|
||||
|
||||
/// Update from iterator, return Err on error.
|
||||
fn try_update_from<I, T>(&mut self, itr: I) -> Result<(), Error>
|
||||
where
|
||||
I: IntoIterator<Item = T>,
|
||||
T: Into<OsString> + Clone,
|
||||
{
|
||||
let mut matches =
|
||||
ok!(<Self as CommandFactory>::command_for_update().try_get_matches_from(itr));
|
||||
<Self as FromArgMatches>::update_from_arg_matches_mut(self, &mut matches)
|
||||
.map_err(format_error::<Self>)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a [`Command`] relevant for a user-defined container.
|
||||
///
|
||||
/// Derived as part of [`Parser`].
|
||||
pub trait CommandFactory: Sized {
|
||||
/// Build a [`Command`] that can instantiate `Self`.
|
||||
///
|
||||
/// See [`FromArgMatches::from_arg_matches_mut`] for instantiating `Self`.
|
||||
fn command() -> Command;
|
||||
/// Build a [`Command`] that can update `self`.
|
||||
///
|
||||
/// See [`FromArgMatches::update_from_arg_matches_mut`] for updating `self`.
|
||||
fn command_for_update() -> Command;
|
||||
}
|
||||
|
||||
/// Converts an instance of [`ArgMatches`] to a user-defined container.
|
||||
///
|
||||
/// Derived as part of [`Parser`], [`Args`], and [`Subcommand`].
|
||||
pub trait FromArgMatches: Sized {
|
||||
/// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
|
||||
///
|
||||
/// Motivation: If our application had two CLI options, `--name
|
||||
/// <STRING>` and the flag `--debug`, we may create a struct as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// struct Context {
|
||||
/// name: String,
|
||||
/// debug: bool
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// We then need to convert the `ArgMatches` that `clap` generated into our struct.
|
||||
/// `from_arg_matches` serves as the equivalent of:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// # use clap::ArgMatches;
|
||||
/// # struct Context {
|
||||
/// # name: String,
|
||||
/// # debug: bool
|
||||
/// # }
|
||||
/// impl From<ArgMatches> for Context {
|
||||
/// fn from(m: ArgMatches) -> Self {
|
||||
/// Context {
|
||||
/// name: m.get_one::<String>("name").unwrap().clone(),
|
||||
/// debug: m.get_flag("debug"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error>;
|
||||
|
||||
/// Instantiate `Self` from [`ArgMatches`], parsing the arguments as needed.
|
||||
///
|
||||
/// Motivation: If our application had two CLI options, `--name
|
||||
/// <STRING>` and the flag `--debug`, we may create a struct as follows:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// struct Context {
|
||||
/// name: String,
|
||||
/// debug: bool
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// We then need to convert the `ArgMatches` that `clap` generated into our struct.
|
||||
/// `from_arg_matches_mut` serves as the equivalent of:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "derive")] {
|
||||
/// # use clap::ArgMatches;
|
||||
/// # struct Context {
|
||||
/// # name: String,
|
||||
/// # debug: bool
|
||||
/// # }
|
||||
/// impl From<ArgMatches> for Context {
|
||||
/// fn from(m: ArgMatches) -> Self {
|
||||
/// Context {
|
||||
/// name: m.get_one::<String>("name").unwrap().to_string(),
|
||||
/// debug: m.get_flag("debug"),
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
Self::from_arg_matches(matches)
|
||||
}
|
||||
|
||||
/// Assign values from `ArgMatches` to `self`.
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error>;
|
||||
|
||||
/// Assign values from `ArgMatches` to `self`.
|
||||
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
self.update_from_arg_matches(matches)
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a set of arguments into a user-defined container.
|
||||
///
|
||||
/// Implementing this trait lets a parent container delegate argument parsing behavior to `Self`.
|
||||
/// with:
|
||||
/// - `#[command(flatten)] args: ChildArgs`: Attribute can only be used with struct fields that impl
|
||||
/// `Args`.
|
||||
/// - `Variant(ChildArgs)`: No attribute is used with enum variants that impl `Args`.
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
pub trait Args: FromArgMatches + Sized {
|
||||
/// Report the [`ArgGroup::id`][crate::ArgGroup::id] for this set of arguments
|
||||
fn group_id() -> Option<crate::Id> {
|
||||
None
|
||||
}
|
||||
/// Append to [`Command`] so it can instantiate `Self`.
|
||||
///
|
||||
/// See also [`CommandFactory`].
|
||||
fn augment_args(cmd: Command) -> Command;
|
||||
/// Append to [`Command`] so it can update `self`.
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory`].
|
||||
fn augment_args_for_update(cmd: Command) -> Command;
|
||||
}
|
||||
|
||||
/// Parse a sub-command into a user-defined enum.
|
||||
///
|
||||
/// Implementing this trait lets a parent container delegate subcommand behavior to `Self`.
|
||||
/// with:
|
||||
/// - `#[command(subcommand)] field: SubCmd`: Attribute can be used with either struct fields or enum
|
||||
/// variants that impl `Subcommand`.
|
||||
/// - `#[command(flatten)] Variant(SubCmd)`: Attribute can only be used with enum variants that impl
|
||||
/// `Subcommand`.
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
pub trait Subcommand: FromArgMatches + Sized {
|
||||
/// Append to [`Command`] so it can instantiate `Self`.
|
||||
///
|
||||
/// See also [`CommandFactory`].
|
||||
fn augment_subcommands(cmd: Command) -> Command;
|
||||
/// Append to [`Command`] so it can update `self`.
|
||||
///
|
||||
/// This is used to implement `#[command(flatten)]`
|
||||
///
|
||||
/// See also [`CommandFactory`].
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command;
|
||||
/// Test whether `Self` can parse a specific subcommand
|
||||
fn has_subcommand(name: &str) -> bool;
|
||||
}
|
||||
|
||||
/// Parse arguments into enums.
|
||||
///
|
||||
/// When deriving [`Parser`], a field whose type implements `ValueEnum` can have the attribute
|
||||
/// `#[arg(value_enum)]` which will
|
||||
/// - Call [`EnumValueParser`][crate::builder::EnumValueParser]
|
||||
/// - Allowing using the `#[arg(default_value_t)]` attribute without implementing `Display`.
|
||||
///
|
||||
/// **NOTE:** Deriving requires the `derive` feature flag
|
||||
pub trait ValueEnum: Sized + Clone {
|
||||
/// All possible argument values, in display order.
|
||||
fn value_variants<'a>() -> &'a [Self];
|
||||
|
||||
/// Parse an argument into `Self`.
|
||||
fn from_str(input: &str, ignore_case: bool) -> Result<Self, String> {
|
||||
Self::value_variants()
|
||||
.iter()
|
||||
.find(|v| {
|
||||
v.to_possible_value()
|
||||
.expect("ValueEnum::value_variants contains only values with a corresponding ValueEnum::to_possible_value")
|
||||
.matches(input, ignore_case)
|
||||
})
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("invalid variant: {input}"))
|
||||
}
|
||||
|
||||
/// The canonical argument value.
|
||||
///
|
||||
/// The value is `None` for skipped variants.
|
||||
fn to_possible_value(&self) -> Option<PossibleValue>;
|
||||
}
|
||||
|
||||
impl<T: Parser> Parser for Box<T> {
|
||||
fn parse() -> Self {
|
||||
Box::new(<T as Parser>::parse())
|
||||
}
|
||||
|
||||
fn try_parse() -> Result<Self, Error> {
|
||||
<T as Parser>::try_parse().map(Box::new)
|
||||
}
|
||||
|
||||
fn parse_from<I, It>(itr: I) -> Self
|
||||
where
|
||||
I: IntoIterator<Item = It>,
|
||||
It: Into<OsString> + Clone,
|
||||
{
|
||||
Box::new(<T as Parser>::parse_from(itr))
|
||||
}
|
||||
|
||||
fn try_parse_from<I, It>(itr: I) -> Result<Self, Error>
|
||||
where
|
||||
I: IntoIterator<Item = It>,
|
||||
It: Into<OsString> + Clone,
|
||||
{
|
||||
<T as Parser>::try_parse_from(itr).map(Box::new)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CommandFactory> CommandFactory for Box<T> {
|
||||
fn command<'help>() -> Command {
|
||||
<T as CommandFactory>::command()
|
||||
}
|
||||
fn command_for_update<'help>() -> Command {
|
||||
<T as CommandFactory>::command_for_update()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromArgMatches> FromArgMatches for Box<T> {
|
||||
fn from_arg_matches(matches: &ArgMatches) -> Result<Self, Error> {
|
||||
<T as FromArgMatches>::from_arg_matches(matches).map(Box::new)
|
||||
}
|
||||
fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, Error> {
|
||||
<T as FromArgMatches>::from_arg_matches_mut(matches).map(Box::new)
|
||||
}
|
||||
fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), Error> {
|
||||
<T as FromArgMatches>::update_from_arg_matches(self, matches)
|
||||
}
|
||||
fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), Error> {
|
||||
<T as FromArgMatches>::update_from_arg_matches_mut(self, matches)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Args> Args for Box<T> {
|
||||
fn augment_args(cmd: Command) -> Command {
|
||||
<T as Args>::augment_args(cmd)
|
||||
}
|
||||
fn augment_args_for_update(cmd: Command) -> Command {
|
||||
<T as Args>::augment_args_for_update(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Subcommand> Subcommand for Box<T> {
|
||||
fn augment_subcommands(cmd: Command) -> Command {
|
||||
<T as Subcommand>::augment_subcommands(cmd)
|
||||
}
|
||||
fn augment_subcommands_for_update(cmd: Command) -> Command {
|
||||
<T as Subcommand>::augment_subcommands_for_update(cmd)
|
||||
}
|
||||
fn has_subcommand(name: &str) -> bool {
|
||||
<T as Subcommand>::has_subcommand(name)
|
||||
}
|
||||
}
|
||||
|
||||
fn format_error<I: CommandFactory>(err: crate::Error) -> crate::Error {
|
||||
let mut cmd = I::command();
|
||||
err.format(&mut cmd)
|
||||
}
|
114
vendor/clap_builder/src/error/context.rs
vendored
Normal file
114
vendor/clap_builder/src/error/context.rs
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
/// Semantics for a piece of error information
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub enum ContextKind {
|
||||
/// The cause of the error
|
||||
InvalidSubcommand,
|
||||
/// The cause of the error
|
||||
InvalidArg,
|
||||
/// Existing arguments
|
||||
PriorArg,
|
||||
/// Accepted subcommands
|
||||
ValidSubcommand,
|
||||
/// Accepted values
|
||||
ValidValue,
|
||||
/// Rejected values
|
||||
InvalidValue,
|
||||
/// Number of values present
|
||||
ActualNumValues,
|
||||
/// Number of allowed values
|
||||
ExpectedNumValues,
|
||||
/// Minimum number of allowed values
|
||||
MinValues,
|
||||
/// Potential fix for the user
|
||||
SuggestedCommand,
|
||||
/// Potential fix for the user
|
||||
SuggestedSubcommand,
|
||||
/// Potential fix for the user
|
||||
SuggestedArg,
|
||||
/// Potential fix for the user
|
||||
SuggestedValue,
|
||||
/// Trailing argument
|
||||
TrailingArg,
|
||||
/// Potential fix for the user
|
||||
Suggested,
|
||||
/// A usage string
|
||||
Usage,
|
||||
/// An opaque message to the user
|
||||
Custom,
|
||||
}
|
||||
|
||||
impl ContextKind {
|
||||
/// End-user description of the error case, where relevant
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::InvalidSubcommand => Some("Invalid Subcommand"),
|
||||
Self::InvalidArg => Some("Invalid Argument"),
|
||||
Self::PriorArg => Some("Prior Argument"),
|
||||
Self::ValidSubcommand => Some("Valid Subcommand"),
|
||||
Self::ValidValue => Some("Valid Value"),
|
||||
Self::InvalidValue => Some("Invalid Value"),
|
||||
Self::ActualNumValues => Some("Actual Number of Values"),
|
||||
Self::ExpectedNumValues => Some("Expected Number of Values"),
|
||||
Self::MinValues => Some("Minimum Number of Values"),
|
||||
Self::SuggestedCommand => Some("Suggested Command"),
|
||||
Self::SuggestedSubcommand => Some("Suggested Subcommand"),
|
||||
Self::SuggestedArg => Some("Suggested Argument"),
|
||||
Self::SuggestedValue => Some("Suggested Value"),
|
||||
Self::TrailingArg => Some("Trailing Argument"),
|
||||
Self::Suggested => Some("Suggested"),
|
||||
Self::Usage => None,
|
||||
Self::Custom => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ContextKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().unwrap_or_default().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
/// A piece of error information
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub enum ContextValue {
|
||||
/// [`ContextKind`] is self-sufficient, no additional information needed
|
||||
None,
|
||||
/// A single value
|
||||
Bool(bool),
|
||||
/// A single value
|
||||
String(String),
|
||||
/// Many values
|
||||
Strings(Vec<String>),
|
||||
/// A single value
|
||||
StyledStr(crate::builder::StyledStr),
|
||||
/// many value
|
||||
StyledStrs(Vec<crate::builder::StyledStr>),
|
||||
/// A single value
|
||||
Number(isize),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ContextValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::None => "".fmt(f),
|
||||
Self::Bool(v) => v.fmt(f),
|
||||
Self::String(v) => v.fmt(f),
|
||||
Self::Strings(v) => v.join(", ").fmt(f),
|
||||
Self::StyledStr(v) => v.fmt(f),
|
||||
Self::StyledStrs(v) => {
|
||||
for (i, v) in v.iter().enumerate() {
|
||||
if i != 0 {
|
||||
", ".fmt(f)?;
|
||||
}
|
||||
v.fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Self::Number(v) => v.fmt(f),
|
||||
}
|
||||
}
|
||||
}
|
545
vendor/clap_builder/src/error/format.rs
vendored
Normal file
545
vendor/clap_builder/src/error/format.rs
vendored
Normal file
@ -0,0 +1,545 @@
|
||||
#![allow(missing_copy_implementations)]
|
||||
#![allow(missing_debug_implementations)]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
|
||||
|
||||
use crate::builder::Command;
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
#[cfg(feature = "error-context")]
|
||||
use crate::error::ContextKind;
|
||||
#[cfg(feature = "error-context")]
|
||||
use crate::error::ContextValue;
|
||||
use crate::error::ErrorKind;
|
||||
use crate::output::TAB;
|
||||
|
||||
/// Defines how to format an error for displaying to the user
|
||||
pub trait ErrorFormatter: Sized {
|
||||
/// Stylize the error for the terminal
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr;
|
||||
}
|
||||
|
||||
/// Report [`ErrorKind`]
|
||||
///
|
||||
/// No context is included.
|
||||
///
|
||||
/// **NOTE:** Consider removing the `error-context` default feature if using this to remove all
|
||||
/// overhead for [`RichFormatter`].
|
||||
#[non_exhaustive]
|
||||
pub struct KindFormatter;
|
||||
|
||||
impl ErrorFormatter for KindFormatter {
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr {
|
||||
use std::fmt::Write as _;
|
||||
let styles = &error.inner.styles;
|
||||
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
if let Some(msg) = error.kind().as_str() {
|
||||
styled.push_str(msg);
|
||||
} else if let Some(source) = error.inner.source.as_ref() {
|
||||
let _ = write!(styled, "{source}");
|
||||
} else {
|
||||
styled.push_str("unknown cause");
|
||||
}
|
||||
styled.push_str("\n");
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
/// Richly formatted error context
|
||||
///
|
||||
/// This follows the [rustc diagnostic style guide](https://rustc-dev-guide.rust-lang.org/diagnostics.html#suggestion-style-guide).
|
||||
#[non_exhaustive]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub struct RichFormatter;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
impl ErrorFormatter for RichFormatter {
|
||||
fn format_error(error: &crate::error::Error<Self>) -> StyledStr {
|
||||
use std::fmt::Write as _;
|
||||
let styles = &error.inner.styles;
|
||||
let valid = &styles.get_valid();
|
||||
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
|
||||
if !write_dynamic_context(error, &mut styled, styles) {
|
||||
if let Some(msg) = error.kind().as_str() {
|
||||
styled.push_str(msg);
|
||||
} else if let Some(source) = error.inner.source.as_ref() {
|
||||
let _ = write!(styled, "{source}");
|
||||
} else {
|
||||
styled.push_str("unknown cause");
|
||||
}
|
||||
}
|
||||
|
||||
let mut suggested = false;
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedSubcommand) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "subcommand", valid);
|
||||
}
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedArg) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "argument", valid);
|
||||
}
|
||||
if let Some(valid) = error.get(ContextKind::SuggestedValue) {
|
||||
styled.push_str("\n");
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
suggested = true;
|
||||
}
|
||||
did_you_mean(&mut styled, styles, "value", valid);
|
||||
}
|
||||
let suggestions = error.get(ContextKind::Suggested);
|
||||
if let Some(ContextValue::StyledStrs(suggestions)) = suggestions {
|
||||
if !suggested {
|
||||
styled.push_str("\n");
|
||||
}
|
||||
for suggestion in suggestions {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n{TAB}{}tip:{} ",
|
||||
valid.render(),
|
||||
valid.render_reset()
|
||||
);
|
||||
styled.push_styled(suggestion);
|
||||
}
|
||||
}
|
||||
|
||||
let usage = error.get(ContextKind::Usage);
|
||||
if let Some(ContextValue::StyledStr(usage)) = usage {
|
||||
put_usage(&mut styled, usage);
|
||||
}
|
||||
|
||||
try_help(&mut styled, styles, error.inner.help_flag);
|
||||
|
||||
styled
|
||||
}
|
||||
}
|
||||
|
||||
fn start_error(styled: &mut StyledStr, styles: &Styles) {
|
||||
use std::fmt::Write as _;
|
||||
let error = &styles.get_error();
|
||||
let _ = write!(styled, "{}error:{} ", error.render(), error.render_reset());
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
#[cfg(feature = "error-context")]
|
||||
fn write_dynamic_context(
|
||||
error: &crate::error::Error,
|
||||
styled: &mut StyledStr,
|
||||
styles: &Styles,
|
||||
) -> bool {
|
||||
use std::fmt::Write as _;
|
||||
let valid = styles.get_valid();
|
||||
let invalid = styles.get_invalid();
|
||||
let literal = styles.get_literal();
|
||||
|
||||
match error.kind() {
|
||||
ErrorKind::ArgumentConflict => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let prior_arg = error.get(ContextKind::PriorArg);
|
||||
if let (Some(ContextValue::String(invalid_arg)), Some(prior_arg)) =
|
||||
(invalid_arg, prior_arg)
|
||||
{
|
||||
if ContextValue::String(invalid_arg.clone()) == *prior_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the argument '{}{invalid_arg}{}' cannot be used multiple times",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
} else {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"the argument '{}{invalid_arg}{}' cannot be used with",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
|
||||
match prior_arg {
|
||||
ContextValue::Strings(values) => {
|
||||
styled.push_str(":");
|
||||
for v in values {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n{TAB}{}{v}{}",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
}
|
||||
ContextValue::String(value) => {
|
||||
let _ = write!(
|
||||
styled,
|
||||
" '{}{value}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
styled.push_str(" one or more of the other specified arguments");
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::NoEquals => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"equal sign is needed when assigning values to '{}{invalid_arg}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidValue => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
if invalid_value.is_empty() {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"a value is required for '{}{invalid_arg}{}' but none was supplied",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
} else {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"invalid value '{}{invalid_value}{}' for '{}{invalid_arg}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
literal.render(),
|
||||
literal.render_reset()
|
||||
);
|
||||
}
|
||||
|
||||
let values = error.get(ContextKind::ValidValue);
|
||||
write_values_list("possible values", styled, valid, values);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidSubcommand => {
|
||||
let invalid_sub = error.get(ContextKind::InvalidSubcommand);
|
||||
if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unrecognized subcommand '{}{invalid_sub}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::MissingRequiredArgument => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::Strings(invalid_arg)) = invalid_arg {
|
||||
styled.push_str("the following required arguments were not provided:");
|
||||
for v in invalid_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n{TAB}{}{v}{}",
|
||||
valid.render(),
|
||||
valid.render_reset()
|
||||
);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::MissingSubcommand => {
|
||||
let invalid_sub = error.get(ContextKind::InvalidSubcommand);
|
||||
if let Some(ContextValue::String(invalid_sub)) = invalid_sub {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"'{}{invalid_sub}{}' requires a subcommand but one was not provided",
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
let values = error.get(ContextKind::ValidSubcommand);
|
||||
write_values_list("subcommands", styled, valid, values);
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::InvalidUtf8 => false,
|
||||
ErrorKind::TooManyValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unexpected value '{}{invalid_value}{}' for '{}{invalid_arg}{}' found; no more were expected",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
literal.render(),
|
||||
literal.render_reset(),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::TooFewValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let actual_num_values = error.get(ContextKind::ActualNumValues);
|
||||
let min_values = error.get(ContextKind::MinValues);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::Number(actual_num_values)),
|
||||
Some(ContextValue::Number(min_values)),
|
||||
) = (invalid_arg, actual_num_values, min_values)
|
||||
{
|
||||
let were_provided = singular_or_plural(*actual_num_values as usize);
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{}{min_values}{} more values required by '{}{invalid_arg}{}'; only {}{actual_num_values}{}{were_provided}",
|
||||
valid.render(),
|
||||
valid.render_reset(),
|
||||
literal.render(),
|
||||
literal.render_reset(),
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::ValueValidation => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let invalid_value = error.get(ContextKind::InvalidValue);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::String(invalid_value)),
|
||||
) = (invalid_arg, invalid_value)
|
||||
{
|
||||
let _ = write!(
|
||||
styled,
|
||||
"invalid value '{}{invalid_value}{}' for '{}{invalid_arg}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
literal.render(),
|
||||
literal.render_reset(),
|
||||
);
|
||||
if let Some(source) = error.inner.source.as_deref() {
|
||||
let _ = write!(styled, ": {source}");
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::WrongNumberOfValues => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
let actual_num_values = error.get(ContextKind::ActualNumValues);
|
||||
let num_values = error.get(ContextKind::ExpectedNumValues);
|
||||
if let (
|
||||
Some(ContextValue::String(invalid_arg)),
|
||||
Some(ContextValue::Number(actual_num_values)),
|
||||
Some(ContextValue::Number(num_values)),
|
||||
) = (invalid_arg, actual_num_values, num_values)
|
||||
{
|
||||
let were_provided = singular_or_plural(*actual_num_values as usize);
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{}{num_values}{} values required for '{}{invalid_arg}{}' but {}{actual_num_values}{}{were_provided}",
|
||||
valid.render(),
|
||||
valid.render_reset(),
|
||||
literal.render(),
|
||||
literal.render_reset(),
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::UnknownArgument => {
|
||||
let invalid_arg = error.get(ContextKind::InvalidArg);
|
||||
if let Some(ContextValue::String(invalid_arg)) = invalid_arg {
|
||||
let _ = write!(
|
||||
styled,
|
||||
"unexpected argument '{}{invalid_arg}{}' found",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
ErrorKind::DisplayHelp
|
||||
| ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand
|
||||
| ErrorKind::DisplayVersion
|
||||
| ErrorKind::Io
|
||||
| ErrorKind::Format => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
fn write_values_list(
|
||||
list_name: &'static str,
|
||||
styled: &mut StyledStr,
|
||||
valid: &anstyle::Style,
|
||||
possible_values: Option<&ContextValue>,
|
||||
) {
|
||||
use std::fmt::Write as _;
|
||||
if let Some(ContextValue::Strings(possible_values)) = possible_values {
|
||||
if !possible_values.is_empty() {
|
||||
let _ = write!(styled, "\n{TAB}[{list_name}: ");
|
||||
|
||||
let style = valid.render();
|
||||
let reset = valid.render_reset();
|
||||
for (idx, val) in possible_values.iter().enumerate() {
|
||||
if idx > 0 {
|
||||
styled.push_str(", ");
|
||||
}
|
||||
let _ = write!(styled, "{style}{}{reset}", Escape(val));
|
||||
}
|
||||
|
||||
styled.push_str("]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn format_error_message(
|
||||
message: &str,
|
||||
styles: &Styles,
|
||||
cmd: Option<&Command>,
|
||||
usage: Option<&StyledStr>,
|
||||
) -> StyledStr {
|
||||
let mut styled = StyledStr::new();
|
||||
start_error(&mut styled, styles);
|
||||
styled.push_str(message);
|
||||
if let Some(usage) = usage {
|
||||
put_usage(&mut styled, usage);
|
||||
}
|
||||
if let Some(cmd) = cmd {
|
||||
try_help(&mut styled, styles, get_help_flag(cmd));
|
||||
}
|
||||
styled
|
||||
}
|
||||
|
||||
/// Returns the singular or plural form on the verb to be based on the argument's value.
|
||||
fn singular_or_plural(n: usize) -> &'static str {
|
||||
if n > 1 {
|
||||
" were provided"
|
||||
} else {
|
||||
" was provided"
|
||||
}
|
||||
}
|
||||
|
||||
fn put_usage(styled: &mut StyledStr, usage: &StyledStr) {
|
||||
styled.push_str("\n\n");
|
||||
styled.push_styled(usage);
|
||||
}
|
||||
|
||||
pub(crate) fn get_help_flag(cmd: &Command) -> Option<&'static str> {
|
||||
if !cmd.is_disable_help_flag_set() {
|
||||
Some("--help")
|
||||
} else if cmd.has_subcommands() && !cmd.is_disable_help_subcommand_set() {
|
||||
Some("help")
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn try_help(styled: &mut StyledStr, styles: &Styles, help: Option<&str>) {
|
||||
if let Some(help) = help {
|
||||
use std::fmt::Write as _;
|
||||
let literal = &styles.get_literal();
|
||||
let _ = write!(
|
||||
styled,
|
||||
"\n\nFor more information, try '{}{help}{}'.\n",
|
||||
literal.render(),
|
||||
literal.render_reset()
|
||||
);
|
||||
} else {
|
||||
styled.push_str("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
fn did_you_mean(styled: &mut StyledStr, styles: &Styles, context: &str, valid: &ContextValue) {
|
||||
use std::fmt::Write as _;
|
||||
|
||||
let _ = write!(
|
||||
styled,
|
||||
"{TAB}{}tip:{}",
|
||||
styles.get_valid().render(),
|
||||
styles.get_valid().render_reset()
|
||||
);
|
||||
if let ContextValue::String(valid) = valid {
|
||||
let _ = write!(
|
||||
styled,
|
||||
" a similar {context} exists: '{}{valid}{}'",
|
||||
styles.get_valid().render(),
|
||||
styles.get_valid().render_reset()
|
||||
);
|
||||
} else if let ContextValue::Strings(valid) = valid {
|
||||
if valid.len() == 1 {
|
||||
let _ = write!(styled, " a similar {context} exists: ",);
|
||||
} else {
|
||||
let _ = write!(styled, " some similar {context}s exist: ",);
|
||||
}
|
||||
for (i, valid) in valid.iter().enumerate() {
|
||||
if i != 0 {
|
||||
styled.push_str(", ");
|
||||
}
|
||||
let _ = write!(
|
||||
styled,
|
||||
"'{}{valid}{}'",
|
||||
styles.get_valid().render(),
|
||||
styles.get_valid().render_reset()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Escape<'s>(&'s str);
|
||||
|
||||
impl<'s> std::fmt::Display for Escape<'s> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
if self.0.contains(char::is_whitespace) {
|
||||
std::fmt::Debug::fmt(self.0, f)
|
||||
} else {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
}
|
366
vendor/clap_builder/src/error/kind.rs
vendored
Normal file
366
vendor/clap_builder/src/error/kind.rs
vendored
Normal file
@ -0,0 +1,366 @@
|
||||
/// Command line argument parser kind of error
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum ErrorKind {
|
||||
/// Occurs when an [`Arg`][crate::Arg] has a set of possible values,
|
||||
/// and the user provides a value which isn't in that set.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("speed")
|
||||
/// .value_parser(["fast", "slow"]))
|
||||
/// .try_get_matches_from(vec!["prog", "other"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidValue);
|
||||
/// ```
|
||||
InvalidValue,
|
||||
|
||||
/// Occurs when a user provides a flag, option, argument or subcommand which isn't defined.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(arg!(--flag "some flag"))
|
||||
/// .try_get_matches_from(vec!["prog", "--other"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::UnknownArgument);
|
||||
/// ```
|
||||
UnknownArgument,
|
||||
|
||||
/// Occurs when the user provides an unrecognized [`Subcommand`] which meets the threshold for
|
||||
/// being similar enough to an existing subcommand.
|
||||
/// If it doesn't meet the threshold, or the 'suggestions' feature is disabled,
|
||||
/// the more general [`UnknownArgument`] error is returned.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "suggestions")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, };
|
||||
/// let result = Command::new("prog")
|
||||
/// .subcommand(Command::new("config")
|
||||
/// .about("Used for configuration")
|
||||
/// .arg(Arg::new("config_file")
|
||||
/// .help("The configuration file to use")))
|
||||
/// .try_get_matches_from(vec!["prog", "confi"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidSubcommand);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`UnknownArgument`]: ErrorKind::UnknownArgument
|
||||
InvalidSubcommand,
|
||||
|
||||
/// Occurs when the user doesn't use equals for an option that requires equal
|
||||
/// sign to provide values.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let res = Command::new("prog")
|
||||
/// .arg(Arg::new("color")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .require_equals(true)
|
||||
/// .long("color"))
|
||||
/// .try_get_matches_from(vec!["prog", "--color", "red"]);
|
||||
/// assert!(res.is_err());
|
||||
/// assert_eq!(res.unwrap_err().kind(), ErrorKind::NoEquals);
|
||||
/// ```
|
||||
NoEquals,
|
||||
|
||||
/// Occurs when the user provides a value for an argument with a custom validation and the
|
||||
/// value fails that validation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, value_parser};
|
||||
/// fn is_numeric(val: &str) -> Result<(), String> {
|
||||
/// match val.parse::<i64>() {
|
||||
/// Ok(..) => Ok(()),
|
||||
/// Err(..) => Err(String::from("value wasn't a number!")),
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("num")
|
||||
/// .value_parser(value_parser!(u8)))
|
||||
/// .try_get_matches_from(vec!["prog", "NotANumber"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::ValueValidation);
|
||||
/// ```
|
||||
ValueValidation,
|
||||
|
||||
/// Occurs when a user provides more values for an argument than were defined by setting
|
||||
/// [`Arg::num_args`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("arg")
|
||||
/// .num_args(1..=2))
|
||||
/// .try_get_matches_from(vec!["prog", "too", "many", "values"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooManyValues);
|
||||
/// ```
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
TooManyValues,
|
||||
|
||||
/// Occurs when the user provides fewer values for an argument than were defined by setting
|
||||
/// [`Arg::num_args`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("some_opt")
|
||||
/// .long("opt")
|
||||
/// .num_args(3..))
|
||||
/// .try_get_matches_from(vec!["prog", "--opt", "too", "few"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::TooFewValues);
|
||||
/// ```
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
TooFewValues,
|
||||
|
||||
/// Occurs when the user provides a different number of values for an argument than what's
|
||||
/// been defined by setting [`Arg::num_args`] or than was implicitly set by
|
||||
/// [`Arg::value_names`].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("some_opt")
|
||||
/// .long("opt")
|
||||
/// .action(ArgAction::Set)
|
||||
/// .num_args(2))
|
||||
/// .try_get_matches_from(vec!["prog", "--opt", "wrong"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::WrongNumberOfValues);
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg::num_args`]: crate::Arg::num_args()
|
||||
/// [`Arg::value_names`]: crate::Arg::value_names()
|
||||
WrongNumberOfValues,
|
||||
|
||||
/// Occurs when the user provides two values which conflict with each other and can't be used
|
||||
/// together.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .long("debug")
|
||||
/// .action(ArgAction::SetTrue)
|
||||
/// .conflicts_with("color"))
|
||||
/// .arg(Arg::new("color")
|
||||
/// .long("color")
|
||||
/// .action(ArgAction::SetTrue))
|
||||
/// .try_get_matches_from(vec!["prog", "--debug", "--color"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::ArgumentConflict);
|
||||
/// ```
|
||||
ArgumentConflict,
|
||||
|
||||
/// Occurs when the user does not provide one or more required arguments.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("debug")
|
||||
/// .required(true))
|
||||
/// .try_get_matches_from(vec!["prog"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::MissingRequiredArgument);
|
||||
/// ```
|
||||
MissingRequiredArgument,
|
||||
|
||||
/// Occurs when a subcommand is required (as defined by [`Command::subcommand_required`]),
|
||||
/// but the user does not provide one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, error::ErrorKind};
|
||||
/// let err = Command::new("prog")
|
||||
/// .subcommand_required(true)
|
||||
/// .subcommand(Command::new("test"))
|
||||
/// .try_get_matches_from(vec![
|
||||
/// "myprog",
|
||||
/// ]);
|
||||
/// assert!(err.is_err());
|
||||
/// assert_eq!(err.unwrap_err().kind(), ErrorKind::MissingSubcommand);
|
||||
/// # ;
|
||||
/// ```
|
||||
///
|
||||
/// [`Command::subcommand_required`]: crate::Command::subcommand_required
|
||||
MissingSubcommand,
|
||||
|
||||
/// Occurs when the user provides a value containing invalid UTF-8.
|
||||
///
|
||||
/// To allow arbitrary data
|
||||
/// - Set [`Arg::value_parser(value_parser!(OsString))`] for argument values
|
||||
/// - Set [`Command::external_subcommand_value_parser`] for external-subcommand
|
||||
/// values
|
||||
///
|
||||
/// # Platform Specific
|
||||
///
|
||||
/// Non-Windows platforms only (such as Linux, Unix, OSX, etc.)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(unix)] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, ArgAction};
|
||||
/// # use std::os::unix::ffi::OsStringExt;
|
||||
/// # use std::ffi::OsString;
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg(Arg::new("utf8")
|
||||
/// .short('u')
|
||||
/// .action(ArgAction::Set))
|
||||
/// .try_get_matches_from(vec![OsString::from("myprog"),
|
||||
/// OsString::from("-u"),
|
||||
/// OsString::from_vec(vec![0xE9])]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::InvalidUtf8);
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// [`Arg::allow_invalid_utf8`]: crate::Arg::allow_invalid_utf8
|
||||
/// [`Command::external_subcommand_value_parser`]: crate::Command::external_subcommand_value_parser
|
||||
InvalidUtf8,
|
||||
|
||||
/// Not a true "error" as it means `--help` or similar was used.
|
||||
/// The help message will be sent to `stdout`.
|
||||
///
|
||||
/// **Note**: If the help is displayed due to an error (such as missing subcommands) it will
|
||||
/// be sent to `stderr` instead of `stdout`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "help")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .try_get_matches_from(vec!["prog", "--help"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelp);
|
||||
/// # }
|
||||
/// ```
|
||||
DisplayHelp,
|
||||
|
||||
/// Occurs when either an argument or a [`Subcommand`] is required, as defined by
|
||||
/// [`Command::arg_required_else_help`] , but the user did not provide
|
||||
/// one.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind, };
|
||||
/// let result = Command::new("prog")
|
||||
/// .arg_required_else_help(true)
|
||||
/// .subcommand(Command::new("config")
|
||||
/// .about("Used for configuration")
|
||||
/// .arg(Arg::new("config_file")
|
||||
/// .help("The configuration file to use")))
|
||||
/// .try_get_matches_from(vec!["prog"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand);
|
||||
/// ```
|
||||
///
|
||||
/// [`Subcommand`]: crate::Subcommand
|
||||
/// [`Command::arg_required_else_help`]: crate::Command::arg_required_else_help
|
||||
DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
|
||||
/// Not a true "error" as it means `--version` or similar was used.
|
||||
/// The message will be sent to `stdout`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, error::ErrorKind};
|
||||
/// let result = Command::new("prog")
|
||||
/// .version("3.0")
|
||||
/// .try_get_matches_from(vec!["prog", "--version"]);
|
||||
/// assert!(result.is_err());
|
||||
/// assert_eq!(result.unwrap_err().kind(), ErrorKind::DisplayVersion);
|
||||
/// ```
|
||||
DisplayVersion,
|
||||
|
||||
/// Represents an [I/O error].
|
||||
/// Can occur when writing to `stderr` or `stdout` or reading a configuration file.
|
||||
///
|
||||
/// [I/O error]: std::io::Error
|
||||
Io,
|
||||
|
||||
/// Represents a [Format error] (which is a part of [`Display`]).
|
||||
/// Typically caused by writing to `stderr` or `stdout`.
|
||||
///
|
||||
/// [`Display`]: std::fmt::Display
|
||||
/// [Format error]: std::fmt::Error
|
||||
Format,
|
||||
}
|
||||
|
||||
impl ErrorKind {
|
||||
/// End-user description of the error case, where relevant
|
||||
pub fn as_str(self) -> Option<&'static str> {
|
||||
match self {
|
||||
Self::InvalidValue => Some("one of the values isn't valid for an argument"),
|
||||
Self::UnknownArgument => Some("unexpected argument found"),
|
||||
Self::InvalidSubcommand => Some("unrecognized subcommand"),
|
||||
Self::NoEquals => Some("equal is needed when assigning values to one of the arguments"),
|
||||
Self::ValueValidation => Some("invalid value for one of the arguments"),
|
||||
Self::TooManyValues => Some("unexpected value for an argument found"),
|
||||
Self::TooFewValues => Some("more values required for an argument"),
|
||||
Self::WrongNumberOfValues => Some("too many or too few values for an argument"),
|
||||
Self::ArgumentConflict => {
|
||||
Some("an argument cannot be used with one or more of the other specified arguments")
|
||||
}
|
||||
Self::MissingRequiredArgument => {
|
||||
Some("one or more required arguments were not provided")
|
||||
}
|
||||
Self::MissingSubcommand => Some("a subcommand is required but one was not provided"),
|
||||
Self::InvalidUtf8 => Some("invalid UTF-8 was detected in one or more arguments"),
|
||||
Self::DisplayHelp => None,
|
||||
Self::DisplayHelpOnMissingArgumentOrSubcommand => None,
|
||||
Self::DisplayVersion => None,
|
||||
Self::Io => None,
|
||||
Self::Format => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ErrorKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_str().unwrap_or_default().fmt(f)
|
||||
}
|
||||
}
|
923
vendor/clap_builder/src/error/mod.rs
vendored
Normal file
923
vendor/clap_builder/src/error/mod.rs
vendored
Normal file
@ -0,0 +1,923 @@
|
||||
//! Error reporting
|
||||
|
||||
#![cfg_attr(not(feature = "error-context"), allow(dead_code))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_imports))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_variables))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(unused_mut))]
|
||||
#![cfg_attr(not(feature = "error-context"), allow(clippy::let_and_return))]
|
||||
|
||||
// Std
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
convert::From,
|
||||
error,
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
io::{self},
|
||||
result::Result as StdResult,
|
||||
};
|
||||
|
||||
// Internal
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::Styles;
|
||||
use crate::output::fmt::Colorizer;
|
||||
use crate::output::fmt::Stream;
|
||||
use crate::parser::features::suggestions;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::{color::ColorChoice, safe_exit, SUCCESS_CODE, USAGE_CODE};
|
||||
use crate::Command;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
mod context;
|
||||
mod format;
|
||||
mod kind;
|
||||
|
||||
pub use format::ErrorFormatter;
|
||||
pub use format::KindFormatter;
|
||||
pub use kind::ErrorKind;
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use context::ContextKind;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use context::ContextValue;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use format::RichFormatter;
|
||||
|
||||
#[cfg(not(feature = "error-context"))]
|
||||
pub use KindFormatter as DefaultFormatter;
|
||||
#[cfg(feature = "error-context")]
|
||||
pub use RichFormatter as DefaultFormatter;
|
||||
|
||||
/// Short hand for [`Result`] type
|
||||
///
|
||||
/// [`Result`]: std::result::Result
|
||||
pub type Result<T, E = Error> = StdResult<T, E>;
|
||||
|
||||
/// Command Line Argument Parser Error
|
||||
///
|
||||
/// See [`Command::error`] to create an error.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub struct Error<F: ErrorFormatter = DefaultFormatter> {
|
||||
inner: Box<ErrorInner>,
|
||||
phantom: std::marker::PhantomData<F>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct ErrorInner {
|
||||
kind: ErrorKind,
|
||||
#[cfg(feature = "error-context")]
|
||||
context: FlatMap<ContextKind, ContextValue>,
|
||||
message: Option<Message>,
|
||||
source: Option<Box<dyn error::Error + Send + Sync>>,
|
||||
help_flag: Option<&'static str>,
|
||||
styles: Styles,
|
||||
color_when: ColorChoice,
|
||||
color_help_when: ColorChoice,
|
||||
backtrace: Option<Backtrace>,
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> Error<F> {
|
||||
/// Create an unformatted error
|
||||
///
|
||||
/// This is for you need to pass the error up to
|
||||
/// a place that has access to the `Command` at which point you can call [`Error::format`].
|
||||
///
|
||||
/// Prefer [`Command::error`] for generating errors.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub fn raw(kind: ErrorKind, message: impl std::fmt::Display) -> Self {
|
||||
Self::new(kind).set_message(message.to_string())
|
||||
}
|
||||
|
||||
/// Format the existing message with the Command's context
|
||||
#[must_use]
|
||||
pub fn format(mut self, cmd: &mut Command) -> Self {
|
||||
cmd._build_self(false);
|
||||
let usage = cmd.render_usage_();
|
||||
if let Some(message) = self.inner.message.as_mut() {
|
||||
message.format(cmd, usage);
|
||||
}
|
||||
self.with_cmd(cmd)
|
||||
}
|
||||
|
||||
/// Create an error with a pre-defined message
|
||||
///
|
||||
/// See also
|
||||
/// - [`Error::insert`]
|
||||
/// - [`Error::with_cmd`]
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "error-context")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::error::ErrorKind;
|
||||
/// # use clap::error::ContextKind;
|
||||
/// # use clap::error::ContextValue;
|
||||
///
|
||||
/// let cmd = clap::Command::new("prog");
|
||||
///
|
||||
/// let mut err = clap::Error::new(ErrorKind::ValueValidation)
|
||||
/// .with_cmd(&cmd);
|
||||
/// err.insert(ContextKind::InvalidArg, ContextValue::String("--foo".to_owned()));
|
||||
/// err.insert(ContextKind::InvalidValue, ContextValue::String("bar".to_owned()));
|
||||
///
|
||||
/// err.print();
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn new(kind: ErrorKind) -> Self {
|
||||
Self {
|
||||
inner: Box::new(ErrorInner {
|
||||
kind,
|
||||
#[cfg(feature = "error-context")]
|
||||
context: FlatMap::new(),
|
||||
message: None,
|
||||
source: None,
|
||||
help_flag: None,
|
||||
styles: Styles::plain(),
|
||||
color_when: ColorChoice::Never,
|
||||
color_help_when: ColorChoice::Never,
|
||||
backtrace: Backtrace::new(),
|
||||
}),
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply [`Command`]'s formatting to the error
|
||||
///
|
||||
/// Generally, this is used with [`Error::new`]
|
||||
pub fn with_cmd(self, cmd: &Command) -> Self {
|
||||
self.set_styles(cmd.get_styles().clone())
|
||||
.set_color(cmd.get_color())
|
||||
.set_colored_help(cmd.color_help())
|
||||
.set_help_flag(format::get_help_flag(cmd))
|
||||
}
|
||||
|
||||
/// Apply an alternative formatter to the error
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::Command;
|
||||
/// # use clap::Arg;
|
||||
/// # use clap::error::KindFormatter;
|
||||
/// let cmd = Command::new("foo")
|
||||
/// .arg(Arg::new("input").required(true));
|
||||
/// let matches = cmd
|
||||
/// .try_get_matches_from(["foo", "input.txt"])
|
||||
/// .map_err(|e| e.apply::<KindFormatter>())
|
||||
/// .unwrap_or_else(|e| e.exit());
|
||||
/// ```
|
||||
pub fn apply<EF: ErrorFormatter>(self) -> Error<EF> {
|
||||
Error {
|
||||
inner: self.inner,
|
||||
phantom: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of error for programmatic processing
|
||||
pub fn kind(&self) -> ErrorKind {
|
||||
self.inner.kind
|
||||
}
|
||||
|
||||
/// Additional information to further qualify the error
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn context(&self) -> impl Iterator<Item = (ContextKind, &ContextValue)> {
|
||||
self.inner.context.iter().map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
/// Lookup a piece of context
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn get(&self, kind: ContextKind) -> Option<&ContextValue> {
|
||||
self.inner.context.get(&kind)
|
||||
}
|
||||
|
||||
/// Insert a piece of context
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub fn insert(&mut self, kind: ContextKind, value: ContextValue) -> Option<ContextValue> {
|
||||
self.inner.context.insert(kind, value)
|
||||
}
|
||||
|
||||
/// Should the message be written to `stdout` or not?
|
||||
#[inline]
|
||||
pub fn use_stderr(&self) -> bool {
|
||||
self.stream() == Stream::Stderr
|
||||
}
|
||||
|
||||
pub(crate) fn stream(&self) -> Stream {
|
||||
match self.kind() {
|
||||
ErrorKind::DisplayHelp | ErrorKind::DisplayVersion => Stream::Stdout,
|
||||
_ => Stream::Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the exit code that `.exit` will exit the process with.
|
||||
///
|
||||
/// When the error's kind would print to `stderr` this returns `2`,
|
||||
/// else it returns `0`.
|
||||
pub fn exit_code(&self) -> i32 {
|
||||
if self.use_stderr() {
|
||||
USAGE_CODE
|
||||
} else {
|
||||
SUCCESS_CODE
|
||||
}
|
||||
}
|
||||
|
||||
/// Prints the error and exits.
|
||||
///
|
||||
/// Depending on the error kind, this either prints to `stderr` and exits with a status of `2`
|
||||
/// or prints to `stdout` and exits with a status of `0`.
|
||||
pub fn exit(&self) -> ! {
|
||||
// Swallow broken pipe errors
|
||||
let _ = self.print();
|
||||
safe_exit(self.exit_code())
|
||||
}
|
||||
|
||||
/// Prints formatted and colored error to `stdout` or `stderr` according to its error kind
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// use clap::Command;
|
||||
///
|
||||
/// match Command::new("Command").try_get_matches() {
|
||||
/// Ok(matches) => {
|
||||
/// // do_something
|
||||
/// },
|
||||
/// Err(err) => {
|
||||
/// err.print().expect("Error writing Error");
|
||||
/// // do_something
|
||||
/// },
|
||||
/// };
|
||||
/// ```
|
||||
pub fn print(&self) -> io::Result<()> {
|
||||
let style = self.formatted();
|
||||
let color_when = if matches!(
|
||||
self.kind(),
|
||||
ErrorKind::DisplayHelp | ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
) {
|
||||
self.inner.color_help_when
|
||||
} else {
|
||||
self.inner.color_when
|
||||
};
|
||||
let c = Colorizer::new(self.stream(), color_when).with_content(style.into_owned());
|
||||
c.print()
|
||||
}
|
||||
|
||||
/// Render the error message to a [`StyledStr`].
|
||||
///
|
||||
/// # Example
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// use clap::Command;
|
||||
///
|
||||
/// match Command::new("Command").try_get_matches() {
|
||||
/// Ok(matches) => {
|
||||
/// // do_something
|
||||
/// },
|
||||
/// Err(err) => {
|
||||
/// let err = err.render();
|
||||
/// println!("{err}");
|
||||
/// // do_something
|
||||
/// },
|
||||
/// };
|
||||
/// ```
|
||||
pub fn render(&self) -> StyledStr {
|
||||
self.formatted().into_owned()
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn for_app(kind: ErrorKind, cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::new(kind).set_message(styled).with_cmd(cmd)
|
||||
}
|
||||
|
||||
pub(crate) fn set_message(mut self, message: impl Into<Message>) -> Self {
|
||||
self.inner.message = Some(message.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_source(mut self, source: Box<dyn error::Error + Send + Sync>) -> Self {
|
||||
self.inner.source = Some(source);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_styles(mut self, styles: Styles) -> Self {
|
||||
self.inner.styles = styles;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_color(mut self, color_when: ColorChoice) -> Self {
|
||||
self.inner.color_when = color_when;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_colored_help(mut self, color_help_when: ColorChoice) -> Self {
|
||||
self.inner.color_help_when = color_help_when;
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_help_flag(mut self, help_flag: Option<&'static str>) -> Self {
|
||||
self.inner.help_flag = help_flag;
|
||||
self
|
||||
}
|
||||
|
||||
/// Does not verify if `ContextKind` is already present
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub(crate) fn insert_context_unchecked(
|
||||
mut self,
|
||||
kind: ContextKind,
|
||||
value: ContextValue,
|
||||
) -> Self {
|
||||
self.inner.context.insert_unchecked(kind, value);
|
||||
self
|
||||
}
|
||||
|
||||
/// Does not verify if `ContextKind` is already present
|
||||
#[inline(never)]
|
||||
#[cfg(feature = "error-context")]
|
||||
pub(crate) fn extend_context_unchecked<const N: usize>(
|
||||
mut self,
|
||||
context: [(ContextKind, ContextValue); N],
|
||||
) -> Self {
|
||||
self.inner.context.extend_unchecked(context);
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn display_help(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(ErrorKind::DisplayHelp, cmd, styled)
|
||||
}
|
||||
|
||||
pub(crate) fn display_help_error(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(
|
||||
ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand,
|
||||
cmd,
|
||||
styled,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn display_version(cmd: &Command, styled: StyledStr) -> Self {
|
||||
Self::for_app(ErrorKind::DisplayVersion, cmd, styled)
|
||||
}
|
||||
|
||||
pub(crate) fn argument_conflict(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
mut others: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::ArgumentConflict).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let others = match others.len() {
|
||||
0 => ContextValue::None,
|
||||
1 => ContextValue::String(others.pop().unwrap()),
|
||||
_ => ContextValue::Strings(others),
|
||||
};
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::PriorArg, others),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn empty_value(cmd: &Command, good_vals: &[String], arg: String) -> Self {
|
||||
Self::invalid_value(cmd, "".to_owned(), good_vals, arg)
|
||||
}
|
||||
|
||||
pub(crate) fn no_equals(cmd: &Command, arg: String, usage: Option<StyledStr>) -> Self {
|
||||
let mut err = Self::new(ErrorKind::NoEquals).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err
|
||||
.extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_value(
|
||||
cmd: &Command,
|
||||
bad_val: String,
|
||||
good_vals: &[String],
|
||||
arg: String,
|
||||
) -> Self {
|
||||
let suggestion = suggestions::did_you_mean(&bad_val, good_vals.iter()).pop();
|
||||
let mut err = Self::new(ErrorKind::InvalidValue).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(bad_val)),
|
||||
(
|
||||
ContextKind::ValidValue,
|
||||
ContextValue::Strings(good_vals.iter().map(|s| (*s).to_owned()).collect()),
|
||||
),
|
||||
]);
|
||||
if let Some(suggestion) = suggestion {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::SuggestedValue,
|
||||
ContextValue::String(suggestion),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_subcommand(
|
||||
cmd: &Command,
|
||||
subcmd: String,
|
||||
did_you_mean: Vec<String>,
|
||||
name: String,
|
||||
suggested_trailing_arg: bool,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut suggestions = vec![];
|
||||
if suggested_trailing_arg {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"to pass '{}{subcmd}{}' as a value, use '{}{name} -- {subcmd}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
valid.render(),
|
||||
valid.render_reset()
|
||||
);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidSubcommand, ContextValue::String(subcmd)),
|
||||
(
|
||||
ContextKind::SuggestedSubcommand,
|
||||
ContextValue::Strings(did_you_mean),
|
||||
),
|
||||
(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(suggestions),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unrecognized_subcommand(
|
||||
cmd: &Command,
|
||||
subcmd: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::InvalidSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([(
|
||||
ContextKind::InvalidSubcommand,
|
||||
ContextValue::String(subcmd),
|
||||
)]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn missing_required_argument(
|
||||
cmd: &Command,
|
||||
required: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::MissingRequiredArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([(
|
||||
ContextKind::InvalidArg,
|
||||
ContextValue::Strings(required),
|
||||
)]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn missing_subcommand(
|
||||
cmd: &Command,
|
||||
parent: String,
|
||||
available: Vec<String>,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::MissingSubcommand).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidSubcommand, ContextValue::String(parent)),
|
||||
(
|
||||
ContextKind::ValidSubcommand,
|
||||
ContextValue::Strings(available),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_utf8(cmd: &Command, usage: Option<StyledStr>) -> Self {
|
||||
let mut err = Self::new(ErrorKind::InvalidUtf8).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn too_many_values(
|
||||
cmd: &Command,
|
||||
val: String,
|
||||
arg: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::TooManyValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(val)),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn too_few_values(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
min_vals: usize,
|
||||
curr_vals: usize,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::TooFewValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::MinValues,
|
||||
ContextValue::Number(min_vals as isize),
|
||||
),
|
||||
(
|
||||
ContextKind::ActualNumValues,
|
||||
ContextValue::Number(curr_vals as isize),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn value_validation(
|
||||
arg: String,
|
||||
val: String,
|
||||
err: Box<dyn error::Error + Send + Sync>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::ValueValidation).set_source(err);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(ContextKind::InvalidValue, ContextValue::String(val)),
|
||||
]);
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn wrong_number_of_values(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
num_vals: usize,
|
||||
curr_vals: usize,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
let mut err = Self::new(ErrorKind::WrongNumberOfValues).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::ExpectedNumValues,
|
||||
ContextValue::Number(num_vals as isize),
|
||||
),
|
||||
(
|
||||
ContextKind::ActualNumValues,
|
||||
ContextValue::Number(curr_vals as isize),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unknown_argument(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
did_you_mean: Option<(String, Option<String>)>,
|
||||
suggested_trailing_arg: bool,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut suggestions = vec![];
|
||||
if suggested_trailing_arg {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"to pass '{}{arg}{}' as a value, use '{}-- {arg}{}'",
|
||||
invalid.render(),
|
||||
invalid.render_reset(),
|
||||
valid.render(),
|
||||
valid.render_reset()
|
||||
);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
|
||||
err = err
|
||||
.extend_context_unchecked([(ContextKind::InvalidArg, ContextValue::String(arg))]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
match did_you_mean {
|
||||
Some((flag, Some(sub))) => {
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"'{}{sub} {flag}{}' exists",
|
||||
valid.render(),
|
||||
valid.render_reset()
|
||||
);
|
||||
suggestions.push(styled_suggestion);
|
||||
}
|
||||
Some((flag, None)) => {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::SuggestedArg,
|
||||
ContextValue::String(flag),
|
||||
);
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
if !suggestions.is_empty() {
|
||||
err = err.insert_context_unchecked(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(suggestions),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
pub(crate) fn unnecessary_double_dash(
|
||||
cmd: &Command,
|
||||
arg: String,
|
||||
usage: Option<StyledStr>,
|
||||
) -> Self {
|
||||
use std::fmt::Write as _;
|
||||
let styles = cmd.get_styles();
|
||||
let invalid = &styles.get_invalid();
|
||||
let valid = &styles.get_valid();
|
||||
let mut err = Self::new(ErrorKind::UnknownArgument).with_cmd(cmd);
|
||||
|
||||
#[cfg(feature = "error-context")]
|
||||
{
|
||||
let mut styled_suggestion = StyledStr::new();
|
||||
let _ = write!(
|
||||
styled_suggestion,
|
||||
"subcommand '{}{arg}{}' exists; to use it, remove the '{}--{}' before it",
|
||||
valid.render(),
|
||||
valid.render_reset(),
|
||||
invalid.render(),
|
||||
invalid.render_reset()
|
||||
);
|
||||
|
||||
err = err.extend_context_unchecked([
|
||||
(ContextKind::InvalidArg, ContextValue::String(arg)),
|
||||
(
|
||||
ContextKind::Suggested,
|
||||
ContextValue::StyledStrs(vec![styled_suggestion]),
|
||||
),
|
||||
]);
|
||||
if let Some(usage) = usage {
|
||||
err = err
|
||||
.insert_context_unchecked(ContextKind::Usage, ContextValue::StyledStr(usage));
|
||||
}
|
||||
}
|
||||
|
||||
err
|
||||
}
|
||||
|
||||
fn formatted(&self) -> Cow<'_, StyledStr> {
|
||||
if let Some(message) = self.inner.message.as_ref() {
|
||||
message.formatted(&self.inner.styles)
|
||||
} else {
|
||||
let styled = F::format_error(self);
|
||||
Cow::Owned(styled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> From<io::Error> for Error<F> {
|
||||
fn from(e: io::Error) -> Self {
|
||||
Error::raw(ErrorKind::Io, e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> From<fmt::Error> for Error<F> {
|
||||
fn from(e: fmt::Error) -> Self {
|
||||
Error::raw(ErrorKind::Format, e)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> std::fmt::Debug for Error<F> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
self.inner.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> error::Error for Error<F> {
|
||||
#[allow(trivial_casts)]
|
||||
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
||||
self.inner.source.as_ref().map(|e| e.as_ref() as _)
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: ErrorFormatter> Display for Error<F> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
// Assuming `self.message` already has a trailing newline, from `try_help` or similar
|
||||
ok!(write!(f, "{}", self.formatted()));
|
||||
if let Some(backtrace) = self.inner.backtrace.as_ref() {
|
||||
ok!(writeln!(f));
|
||||
ok!(writeln!(f, "Backtrace:"));
|
||||
ok!(writeln!(f, "{backtrace}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) enum Message {
|
||||
Raw(String),
|
||||
Formatted(StyledStr),
|
||||
}
|
||||
|
||||
impl Message {
|
||||
fn format(&mut self, cmd: &Command, usage: Option<StyledStr>) {
|
||||
match self {
|
||||
Message::Raw(s) => {
|
||||
let mut message = String::new();
|
||||
std::mem::swap(s, &mut message);
|
||||
|
||||
let styled = format::format_error_message(
|
||||
&message,
|
||||
cmd.get_styles(),
|
||||
Some(cmd),
|
||||
usage.as_ref(),
|
||||
);
|
||||
|
||||
*self = Self::Formatted(styled);
|
||||
}
|
||||
Message::Formatted(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn formatted(&self, styles: &Styles) -> Cow<StyledStr> {
|
||||
match self {
|
||||
Message::Raw(s) => {
|
||||
let styled = format::format_error_message(s, styles, None, None);
|
||||
|
||||
Cow::Owned(styled)
|
||||
}
|
||||
Message::Formatted(s) => Cow::Borrowed(s),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Message {
|
||||
fn from(inner: String) -> Self {
|
||||
Self::Raw(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StyledStr> for Message {
|
||||
fn from(inner: StyledStr) -> Self {
|
||||
Self::Formatted(inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
#[derive(Debug)]
|
||||
struct Backtrace(backtrace::Backtrace);
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Backtrace {
|
||||
fn new() -> Option<Self> {
|
||||
Some(Self(backtrace::Backtrace::new()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
// `backtrace::Backtrace` uses `Debug` instead of `Display`
|
||||
write!(f, "{:?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
#[derive(Debug)]
|
||||
struct Backtrace;
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
impl Backtrace {
|
||||
fn new() -> Option<Self> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
impl Display for Backtrace {
|
||||
fn fmt(&self, _: &mut Formatter) -> fmt::Result {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_auto_traits() {
|
||||
static_assertions::assert_impl_all!(Error: Send, Sync, Unpin);
|
||||
}
|
66
vendor/clap_builder/src/lib.rs
vendored
Normal file
66
vendor/clap_builder/src/lib.rs
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright ⓒ 2015-2016 Kevin B. Knapp and [`clap-rs` contributors](https://github.com/clap-rs/clap/graphs/contributors).
|
||||
// Licensed under the MIT license
|
||||
// (see LICENSE or <http://opensource.org/licenses/MIT>) All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
|
||||
#![warn(
|
||||
missing_docs,
|
||||
missing_debug_implementations,
|
||||
missing_copy_implementations,
|
||||
trivial_casts,
|
||||
unused_allocation,
|
||||
trivial_numeric_casts,
|
||||
clippy::single_char_pattern
|
||||
)]
|
||||
#![forbid(unsafe_code)]
|
||||
// Wanting consistency in our calls
|
||||
#![allow(clippy::write_with_newline)]
|
||||
// Gets in the way of logging
|
||||
#![allow(clippy::let_and_return)]
|
||||
// HACK https://github.com/rust-lang/rust-clippy/issues/7290
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
#![allow(clippy::branches_sharing_code)]
|
||||
// Doesn't allow for debug statements, etc to be unique
|
||||
#![allow(clippy::if_same_then_else)]
|
||||
// Breaks up parallelism that clarifies intent
|
||||
#![allow(clippy::collapsible_else_if)]
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
compile_error!("`std` feature is currently required to build `clap`");
|
||||
|
||||
pub use crate::builder::ArgAction;
|
||||
pub use crate::builder::Command;
|
||||
pub use crate::builder::ValueHint;
|
||||
pub use crate::builder::{Arg, ArgGroup};
|
||||
pub use crate::parser::ArgMatches;
|
||||
pub use crate::util::color::ColorChoice;
|
||||
pub use crate::util::Id;
|
||||
|
||||
/// Command Line Argument Parser Error
|
||||
///
|
||||
/// See [`Command::error`] to create an error.
|
||||
///
|
||||
/// [`Command::error`]: crate::Command::error
|
||||
pub type Error = crate::error::Error<crate::error::DefaultFormatter>;
|
||||
|
||||
pub use crate::derive::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
|
||||
|
||||
#[macro_use]
|
||||
#[allow(missing_docs)]
|
||||
mod macros;
|
||||
|
||||
mod derive;
|
||||
|
||||
pub mod builder;
|
||||
pub mod error;
|
||||
pub mod parser;
|
||||
|
||||
mod mkeymap;
|
||||
mod output;
|
||||
mod util;
|
||||
|
||||
const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
|
||||
report at https://github.com/clap-rs/clap/issues";
|
574
vendor/clap_builder/src/macros.rs
vendored
Normal file
574
vendor/clap_builder/src/macros.rs
vendored
Normal file
@ -0,0 +1,574 @@
|
||||
/// Allows you to pull the version from your Cargo.toml at compile time as
|
||||
/// `MAJOR.MINOR.PATCH_PKGVERSION_PRE`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_version;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .version(crate_version!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_version {
|
||||
() => {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the authors for the command from your Cargo.toml at
|
||||
/// compile time in the form:
|
||||
/// `"author1 lastname <author1@example.com>:author2 lastname <author2@example.com>"`
|
||||
///
|
||||
/// You can replace the colons with a custom separator by supplying a
|
||||
/// replacement string, so, for example,
|
||||
/// `crate_authors!(",\n")` would become
|
||||
/// `"author1 lastname <author1@example.com>,\nauthor2 lastname <author2@example.com>,\nauthor3 lastname <author3@example.com>"`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_authors;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .author(crate_authors!("\n"))
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_authors {
|
||||
($sep:expr) => {{
|
||||
static authors: &str = env!("CARGO_PKG_AUTHORS");
|
||||
if authors.contains(':') {
|
||||
static CACHED: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
||||
let s = CACHED.get_or_init(|| authors.replace(':', $sep));
|
||||
let s: &'static str = &*s;
|
||||
s
|
||||
} else {
|
||||
authors
|
||||
}
|
||||
}};
|
||||
() => {
|
||||
env!("CARGO_PKG_AUTHORS")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the description from your Cargo.toml at compile time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_description;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new("cmd")
|
||||
/// .about(crate_description!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_description {
|
||||
() => {
|
||||
env!("CARGO_PKG_DESCRIPTION")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to pull the name from your Cargo.toml at compile time.
|
||||
///
|
||||
/// **NOTE:** This macro extracts the name from an environment variable `CARGO_PKG_NAME`.
|
||||
/// When the crate name is set to something different from the package name,
|
||||
/// use environment variables `CARGO_CRATE_NAME` or `CARGO_BIN_NAME`.
|
||||
/// See [the Cargo Book](https://doc.rust-lang.org/cargo/reference/environment-variables.html)
|
||||
/// for more information.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::crate_name;
|
||||
/// # use clap::Command;
|
||||
/// let m = Command::new(crate_name!())
|
||||
/// .get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! crate_name {
|
||||
() => {
|
||||
env!("CARGO_PKG_NAME")
|
||||
};
|
||||
}
|
||||
|
||||
/// Allows you to build the `Command` instance from your Cargo.toml at compile time.
|
||||
///
|
||||
/// **NOTE:** Changing the values in your `Cargo.toml` does not trigger a re-build automatically,
|
||||
/// and therefore won't change the generated output until you recompile.
|
||||
///
|
||||
/// In some cases you can "trick" the compiler into triggering a rebuild when your
|
||||
/// `Cargo.toml` is changed by including this in your `src/main.rs` file
|
||||
/// `include_str!("../Cargo.toml");`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::command;
|
||||
/// let m = command!().get_matches();
|
||||
/// ```
|
||||
#[cfg(feature = "cargo")]
|
||||
#[macro_export]
|
||||
macro_rules! command {
|
||||
() => {{
|
||||
$crate::command!($crate::crate_name!())
|
||||
}};
|
||||
($name:expr) => {{
|
||||
let mut cmd = $crate::Command::new($name).version($crate::crate_version!());
|
||||
|
||||
let author = $crate::crate_authors!();
|
||||
if !author.is_empty() {
|
||||
cmd = cmd.author(author)
|
||||
}
|
||||
|
||||
let about = $crate::crate_description!();
|
||||
if !about.is_empty() {
|
||||
cmd = cmd.about(about)
|
||||
}
|
||||
|
||||
cmd
|
||||
}};
|
||||
}
|
||||
|
||||
/// Requires `cargo` feature flag to be enabled.
|
||||
#[cfg(not(feature = "cargo"))]
|
||||
#[macro_export]
|
||||
macro_rules! command {
|
||||
() => {{
|
||||
compile_error!("`cargo` feature flag is required");
|
||||
}};
|
||||
($name:expr) => {{
|
||||
compile_error!("`cargo` feature flag is required");
|
||||
}};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! arg_impl {
|
||||
( @string $val:ident ) => {
|
||||
stringify!($val)
|
||||
};
|
||||
( @string $val:literal ) => {{
|
||||
let ident_or_string_literal: &str = $val;
|
||||
ident_or_string_literal
|
||||
}};
|
||||
( @string $val:tt ) => {
|
||||
::std::compile_error!("Only identifiers or string literals supported");
|
||||
};
|
||||
( @string ) => {
|
||||
None
|
||||
};
|
||||
|
||||
( @char $val:ident ) => {{
|
||||
let ident_or_char_literal = stringify!($val);
|
||||
debug_assert_eq!(
|
||||
ident_or_char_literal.len(),
|
||||
1,
|
||||
"Single-letter identifier expected, got {ident_or_char_literal}",
|
||||
);
|
||||
ident_or_char_literal.chars().next().unwrap()
|
||||
}};
|
||||
( @char $val:literal ) => {{
|
||||
let ident_or_char_literal: char = $val;
|
||||
ident_or_char_literal
|
||||
}};
|
||||
( @char ) => {{
|
||||
None
|
||||
}};
|
||||
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
--$long:ident
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let mut arg = $arg;
|
||||
let long = $crate::arg_impl! { @string $long };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(long);
|
||||
}
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = arg
|
||||
.long(long)
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
--$long:literal
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let mut arg = $arg;
|
||||
let long = $crate::arg_impl! { @string $long };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(long);
|
||||
}
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = arg
|
||||
.long(long)
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
-$short:ident
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = $arg
|
||||
.short($crate::arg_impl! { @char $short })
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
-$short:literal
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert_eq!($arg.get_long(), None, "Short flags should precede long flags");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Flags should precede values");
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
|
||||
let action = $crate::ArgAction::SetTrue;
|
||||
let arg = $arg
|
||||
.short($crate::arg_impl! { @char $short })
|
||||
.action(action);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
<$value_name:ident>
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(true);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
<$value_name:literal>
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(true);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
[$value_name:ident]
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(false);
|
||||
} else {
|
||||
arg = arg.num_args(0..=1);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
[$value_name:literal]
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
debug_assert!(!matches!($arg.get_action(), $crate::ArgAction::Append), "Flags should precede `...`");
|
||||
debug_assert_eq!($arg.get_value_names(), None, "Multiple values not yet supported");
|
||||
|
||||
let mut arg = $arg;
|
||||
|
||||
if arg.get_long().is_none() && arg.get_short().is_none() {
|
||||
arg = arg.required(false);
|
||||
} else {
|
||||
arg = arg.num_args(0..=1);
|
||||
}
|
||||
|
||||
let value_name = $crate::arg_impl! { @string $value_name };
|
||||
if arg.get_id() == "" {
|
||||
arg = arg.id(value_name);
|
||||
}
|
||||
let arg = arg
|
||||
.value_name(value_name)
|
||||
.action($crate::ArgAction::Set);
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
...
|
||||
$($tail:tt)*
|
||||
) => {{
|
||||
let arg = match $arg.get_action() {
|
||||
$crate::ArgAction::Set => {
|
||||
if $arg.get_long().is_none() && $arg.get_short().is_none() {
|
||||
$arg.num_args(1..)
|
||||
// Allow collecting arguments interleaved with flags
|
||||
.action($crate::ArgAction::Append)
|
||||
} else {
|
||||
$arg.action($crate::ArgAction::Append)
|
||||
}
|
||||
},
|
||||
$crate::ArgAction::SetTrue | $crate::ArgAction::Help | $crate::ArgAction::Version => {
|
||||
$arg.action($crate::ArgAction::Count)
|
||||
}
|
||||
action => {
|
||||
panic!("Unexpected action {action:?}")
|
||||
}
|
||||
};
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)*
|
||||
};
|
||||
arg
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
$help:literal
|
||||
) => {{
|
||||
$arg.help($help)
|
||||
}};
|
||||
(
|
||||
@arg
|
||||
($arg:expr)
|
||||
) => {{
|
||||
$arg
|
||||
}};
|
||||
}
|
||||
|
||||
/// Create an [`Arg`] from a usage string.
|
||||
///
|
||||
/// Allows creation of basic settings for the [`Arg`].
|
||||
///
|
||||
/// **NOTE**: Not all settings may be set using the usage string method. Some properties are
|
||||
/// only available via the builder pattern.
|
||||
///
|
||||
/// # Syntax
|
||||
///
|
||||
/// Usage strings typically following the form:
|
||||
///
|
||||
/// ```notrust
|
||||
/// [explicit name] [short] [long] [value names] [...] [help string]
|
||||
/// ```
|
||||
///
|
||||
/// ### Explicit Name
|
||||
///
|
||||
/// The name may be either a bare-word or a string, followed by a `:`, like `name:` or
|
||||
/// `"name":`.
|
||||
///
|
||||
/// *Note:* This is an optional field, if it's omitted the argument will use one of the additional
|
||||
/// fields as the name using the following priority order:
|
||||
///
|
||||
/// 1. Explicit Name
|
||||
/// 2. Long
|
||||
/// 3. Value Name
|
||||
///
|
||||
/// See [`Arg::id`][crate::Arg::id].
|
||||
///
|
||||
/// ### Short
|
||||
///
|
||||
/// A short flag is a `-` followed by either a bare-character or quoted character, like `-f` or
|
||||
/// `-'f'`.
|
||||
///
|
||||
/// See [`Arg::short`][crate::Arg::short].
|
||||
///
|
||||
/// ### Long
|
||||
///
|
||||
/// A long flag is a `--` followed by either a bare-word or a string, like `--foo` or
|
||||
/// `--"foo"`.
|
||||
///
|
||||
/// **NOTE:** Dashes in the long name (e.g. `--foo-bar`) is not supported and quoting is required
|
||||
/// (e.g. `--"foo-bar"`).
|
||||
///
|
||||
/// See [`Arg::long`][crate::Arg::long].
|
||||
///
|
||||
/// ### Values (Value Notation)
|
||||
///
|
||||
/// This is set by placing bare-word between:
|
||||
/// - `[]` like `[FOO]`
|
||||
/// - Positional argument: optional
|
||||
/// - Named argument: optional value
|
||||
/// - `<>` like `<FOO>`: required
|
||||
///
|
||||
/// See [`Arg::value_name`][crate::Arg::value_name].
|
||||
///
|
||||
/// ### `...`
|
||||
///
|
||||
/// `...` (three consecutive dots/periods) specifies that this argument may occur multiple
|
||||
/// times (not to be confused with multiple values per occurrence).
|
||||
///
|
||||
/// See [`ArgAction::Count`][crate::ArgAction::Count] and [`ArgAction::Append`][crate::ArgAction::Append].
|
||||
///
|
||||
/// ### Help String
|
||||
///
|
||||
/// The help string is denoted between a pair of double quotes `""` and may contain any
|
||||
/// characters.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, Arg, arg};
|
||||
/// let cmd = Command::new("prog")
|
||||
/// .args(&[
|
||||
/// arg!(--config <FILE> "a required file for the configuration and no short"),
|
||||
/// arg!(-d --debug ... "turns on debugging information and allows multiples"),
|
||||
/// arg!([input] "an optional input file to use")
|
||||
/// ]);
|
||||
///
|
||||
/// let m = cmd.try_get_matches_from(["prog", "--config", "file.toml"]).unwrap();
|
||||
/// assert_eq!(m.get_one::<String>("config").unwrap(), "file.toml");
|
||||
/// assert_eq!(*m.get_one::<u8>("debug").unwrap(), 0);
|
||||
/// assert_eq!(m.get_one::<String>("input"), None);
|
||||
/// ```
|
||||
/// [`Arg`]: crate::Arg
|
||||
#[macro_export]
|
||||
macro_rules! arg {
|
||||
( $name:ident: $($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::new($crate::arg_impl! { @string $name });
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)+
|
||||
};
|
||||
arg
|
||||
}};
|
||||
( $($tail:tt)+ ) => {{
|
||||
let arg = $crate::Arg::default();
|
||||
let arg = $crate::arg_impl! {
|
||||
@arg (arg) $($tail)+
|
||||
};
|
||||
debug_assert_ne!(arg.get_id(), "", "Without a value or long flag, the `name:` prefix is required");
|
||||
arg
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => ({
|
||||
use std::fmt::Write as _;
|
||||
let hint = anstyle::Style::new().dimmed();
|
||||
|
||||
let module_path = module_path!();
|
||||
let body = format!($($arg)*);
|
||||
let mut styled = $crate::builder::StyledStr::new();
|
||||
let _ = write!(styled, "{}[{module_path:>28}]{body}{}\n", hint.render(), hint.render_reset());
|
||||
let color = $crate::output::fmt::Colorizer::new($crate::output::fmt::Stream::Stderr, $crate::ColorChoice::Auto).with_content(styled);
|
||||
let _ = color.print();
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "debug"))]
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => {};
|
||||
}
|
||||
|
||||
macro_rules! ok {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! some {
|
||||
($expr:expr) => {
|
||||
match $expr {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
188
vendor/clap_builder/src/mkeymap.rs
vendored
Normal file
188
vendor/clap_builder/src/mkeymap.rs
vendored
Normal file
@ -0,0 +1,188 @@
|
||||
use std::iter::Iterator;
|
||||
use std::ops::Index;
|
||||
|
||||
use crate::builder::OsStr;
|
||||
use crate::Arg;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub(crate) struct Key {
|
||||
key: KeyType,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
#[derive(Default, PartialEq, Eq, Debug, Clone)]
|
||||
pub(crate) struct MKeyMap {
|
||||
/// All of the arguments.
|
||||
args: Vec<Arg>,
|
||||
|
||||
// Cache part:
|
||||
/// Will be set after `_build()`.
|
||||
keys: Vec<Key>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub(crate) enum KeyType {
|
||||
Short(char),
|
||||
Long(OsStr),
|
||||
Position(usize),
|
||||
}
|
||||
|
||||
impl KeyType {
|
||||
pub(crate) fn is_position(&self) -> bool {
|
||||
matches!(self, KeyType::Position(_))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<usize> for KeyType {
|
||||
fn eq(&self, rhs: &usize) -> bool {
|
||||
match self {
|
||||
KeyType::Position(x) => x == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for KeyType {
|
||||
fn eq(&self, rhs: &&str) -> bool {
|
||||
match self {
|
||||
KeyType::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for KeyType {
|
||||
fn eq(&self, rhs: &str) -> bool {
|
||||
match self {
|
||||
KeyType::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<OsStr> for KeyType {
|
||||
fn eq(&self, rhs: &OsStr) -> bool {
|
||||
match self {
|
||||
KeyType::Long(l) => l == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<char> for KeyType {
|
||||
fn eq(&self, rhs: &char) -> bool {
|
||||
match self {
|
||||
KeyType::Short(c) => c == rhs,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MKeyMap {
|
||||
/// If any arg has corresponding key in this map, we can search the key with
|
||||
/// u64(for positional argument), char(for short flag), &str and OsString
|
||||
/// (for long flag)
|
||||
pub(crate) fn contains<K>(&self, key: K) -> bool
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
{
|
||||
self.keys.iter().any(|x| x.key == key)
|
||||
}
|
||||
|
||||
/// Push an argument in the map.
|
||||
pub(crate) fn push(&mut self, new_arg: Arg) {
|
||||
self.args.push(new_arg);
|
||||
}
|
||||
|
||||
/// Find the arg have corresponding key in this map, we can search the key
|
||||
/// with u64(for positional argument), char(for short flag), &str and
|
||||
/// OsString (for long flag)
|
||||
pub(crate) fn get<K: ?Sized>(&self, key: &K) -> Option<&Arg>
|
||||
where
|
||||
KeyType: PartialEq<K>,
|
||||
{
|
||||
self.keys
|
||||
.iter()
|
||||
.find(|k| &k.key == key)
|
||||
.map(|k| &self.args[k.index])
|
||||
}
|
||||
|
||||
/// Return iterators of all keys.
|
||||
pub(crate) fn keys(&self) -> impl Iterator<Item = &KeyType> {
|
||||
self.keys.iter().map(|x| &x.key)
|
||||
}
|
||||
|
||||
/// Return iterators of all args.
|
||||
pub(crate) fn args(&self) -> impl Iterator<Item = &Arg> {
|
||||
self.args.iter()
|
||||
}
|
||||
|
||||
/// Return mutable iterators of all args.
|
||||
pub(crate) fn args_mut(&mut self) -> impl Iterator<Item = &mut Arg> {
|
||||
self.args.iter_mut()
|
||||
}
|
||||
|
||||
/// Mutate every argument.
|
||||
pub(crate) fn mut_args<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(Arg) -> Arg,
|
||||
{
|
||||
let mut args = std::mem::take(&mut self.args);
|
||||
self.args.extend(args.drain(..).map(f));
|
||||
}
|
||||
|
||||
/// We need a lazy build here since some we may change args after creating
|
||||
/// the map, you can checkout who uses `args_mut`.
|
||||
pub(crate) fn _build(&mut self) {
|
||||
// There will be at least as many keys as args, so that is a good starting point
|
||||
self.keys.reserve(self.args.len());
|
||||
for (i, arg) in self.args.iter().enumerate() {
|
||||
append_keys(&mut self.keys, arg, i);
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove an arg in the graph by Id, usually used by `mut_arg`. Return
|
||||
/// `Some(arg)` if removed.
|
||||
pub(crate) fn remove_by_name(&mut self, name: &str) -> Option<Arg> {
|
||||
self.args
|
||||
.iter()
|
||||
.position(|arg| arg.id == name)
|
||||
// since it's a cold function, using this wouldn't hurt much
|
||||
.map(|i| self.args.remove(i))
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<&'_ KeyType> for MKeyMap {
|
||||
type Output = Arg;
|
||||
|
||||
fn index(&self, key: &KeyType) -> &Self::Output {
|
||||
self.get(key).expect(INTERNAL_ERROR_MSG)
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate key types for an specific Arg.
|
||||
fn append_keys(keys: &mut Vec<Key>, arg: &Arg, index: usize) {
|
||||
if let Some(pos_index) = arg.index {
|
||||
let key = KeyType::Position(pos_index);
|
||||
keys.push(Key { key, index });
|
||||
} else {
|
||||
if let Some(short) = arg.short {
|
||||
let key = KeyType::Short(short);
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
if let Some(long) = arg.long.clone() {
|
||||
let key = KeyType::Long(long.into());
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
|
||||
for (short, _) in arg.short_aliases.iter() {
|
||||
let key = KeyType::Short(*short);
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
for (long, _) in arg.aliases.iter() {
|
||||
let key = KeyType::Long(long.into());
|
||||
keys.push(Key { key, index });
|
||||
}
|
||||
}
|
||||
}
|
83
vendor/clap_builder/src/output/fmt.rs
vendored
Normal file
83
vendor/clap_builder/src/output/fmt.rs
vendored
Normal file
@ -0,0 +1,83 @@
|
||||
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)
|
||||
}
|
||||
}
|
39
vendor/clap_builder/src/output/help.rs
vendored
Normal file
39
vendor/clap_builder/src/output/help.rs
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
#![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");
|
||||
}
|
1198
vendor/clap_builder/src/output/help_template.rs
vendored
Normal file
1198
vendor/clap_builder/src/output/help_template.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
23
vendor/clap_builder/src/output/mod.rs
vendored
Normal file
23
vendor/clap_builder/src/output/mod.rs
vendored
Normal file
@ -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();
|
158
vendor/clap_builder/src/output/textwrap/core.rs
vendored
Normal file
158
vendor/clap_builder/src/output/textwrap/core.rs
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
122
vendor/clap_builder/src/output/textwrap/mod.rs
vendored
Normal file
122
vendor/clap_builder/src/output/textwrap/mod.rs
vendored
Normal file
@ -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"]);
|
||||
}
|
||||
}
|
92
vendor/clap_builder/src/output/textwrap/word_separators.rs
vendored
Normal file
92
vendor/clap_builder/src/output/textwrap/word_separators.rs
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
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"]]
|
||||
);
|
||||
}
|
63
vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs
vendored
Normal file
63
vendor/clap_builder/src/output/textwrap/wrap_algorithms.rs
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
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
|
||||
}
|
||||
}
|
529
vendor/clap_builder/src/output/usage.rs
vendored
Normal file
529
vendor/clap_builder/src/output/usage.rs
vendored
Normal file
@ -0,0 +1,529 @@
|
||||
#![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
|
||||
}
|
||||
}
|
238
vendor/clap_builder/src/parser/arg_matcher.rs
vendored
Normal file
238
vendor/clap_builder/src/parser/arg_matcher.rs
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
// Std
|
||||
use std::ffi::OsString;
|
||||
use std::mem;
|
||||
use std::ops::Deref;
|
||||
|
||||
// Internal
|
||||
use crate::builder::{Arg, ArgPredicate, Command};
|
||||
use crate::parser::Identifier;
|
||||
use crate::parser::PendingArg;
|
||||
use crate::parser::{ArgMatches, MatchedArg, SubCommand, ValueSource};
|
||||
use crate::util::AnyValue;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::Id;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub(crate) struct ArgMatcher {
|
||||
matches: ArgMatches,
|
||||
pending: Option<PendingArg>,
|
||||
}
|
||||
|
||||
impl ArgMatcher {
|
||||
pub(crate) fn new(_cmd: &Command) -> Self {
|
||||
ArgMatcher {
|
||||
matches: ArgMatches {
|
||||
#[cfg(debug_assertions)]
|
||||
valid_args: {
|
||||
let args = _cmd.get_arguments().map(|a| a.get_id().clone());
|
||||
let groups = _cmd.get_groups().map(|g| g.get_id().clone());
|
||||
args.chain(groups).collect()
|
||||
},
|
||||
#[cfg(debug_assertions)]
|
||||
valid_subcommands: _cmd
|
||||
.get_subcommands()
|
||||
.map(|sc| sc.get_name_str().clone())
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
pending: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_inner(self) -> ArgMatches {
|
||||
self.matches
|
||||
}
|
||||
|
||||
pub(crate) fn propagate_globals(&mut self, global_arg_vec: &[Id]) {
|
||||
debug!("ArgMatcher::get_global_values: global_arg_vec={global_arg_vec:?}");
|
||||
let mut vals_map = FlatMap::new();
|
||||
self.fill_in_global_values(global_arg_vec, &mut vals_map);
|
||||
}
|
||||
|
||||
fn fill_in_global_values(
|
||||
&mut self,
|
||||
global_arg_vec: &[Id],
|
||||
vals_map: &mut FlatMap<Id, MatchedArg>,
|
||||
) {
|
||||
for global_arg in global_arg_vec {
|
||||
if let Some(ma) = self.get(global_arg) {
|
||||
// We have to check if the parent's global arg wasn't used but still exists
|
||||
// such as from a default value.
|
||||
//
|
||||
// For example, `myprog subcommand --global-arg=value` where `--global-arg` defines
|
||||
// a default value of `other` myprog would have an existing MatchedArg for
|
||||
// `--global-arg` where the value is `other`
|
||||
let to_update = if let Some(parent_ma) = vals_map.get(global_arg) {
|
||||
if parent_ma.source() > ma.source() {
|
||||
parent_ma
|
||||
} else {
|
||||
ma
|
||||
}
|
||||
} else {
|
||||
ma
|
||||
}
|
||||
.clone();
|
||||
vals_map.insert(global_arg.clone(), to_update);
|
||||
}
|
||||
}
|
||||
if let Some(ref mut sc) = self.matches.subcommand {
|
||||
let mut am = ArgMatcher {
|
||||
matches: mem::take(&mut sc.matches),
|
||||
pending: None,
|
||||
};
|
||||
am.fill_in_global_values(global_arg_vec, vals_map);
|
||||
mem::swap(&mut am.matches, &mut sc.matches);
|
||||
}
|
||||
|
||||
for (name, matched_arg) in vals_map.iter_mut() {
|
||||
self.matches.args.insert(name.clone(), matched_arg.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, arg: &Id) -> Option<&MatchedArg> {
|
||||
self.matches.args.get(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(&mut self, arg: &Id) -> Option<&mut MatchedArg> {
|
||||
self.matches.args.get_mut(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&mut self, arg: &Id) -> bool {
|
||||
self.matches.args.remove(arg).is_some()
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, arg: &Id) -> bool {
|
||||
self.matches.args.contains_key(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn arg_ids(&self) -> std::slice::Iter<'_, Id> {
|
||||
self.matches.args.keys()
|
||||
}
|
||||
|
||||
pub(crate) fn args(&self) -> crate::util::flat_map::Iter<'_, Id, MatchedArg> {
|
||||
self.matches.args.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn entry(&mut self, arg: Id) -> crate::util::Entry<Id, MatchedArg> {
|
||||
self.matches.args.entry(arg)
|
||||
}
|
||||
|
||||
pub(crate) fn subcommand(&mut self, sc: SubCommand) {
|
||||
self.matches.subcommand = Some(Box::new(sc));
|
||||
}
|
||||
|
||||
pub(crate) fn subcommand_name(&self) -> Option<&str> {
|
||||
self.matches.subcommand_name()
|
||||
}
|
||||
|
||||
pub(crate) fn check_explicit(&self, arg: &Id, predicate: &ArgPredicate) -> bool {
|
||||
self.get(arg)
|
||||
.map(|a| a.check_explicit(predicate))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn start_custom_arg(&mut self, arg: &Arg, source: ValueSource) {
|
||||
let id = arg.get_id().clone();
|
||||
debug!("ArgMatcher::start_custom_arg: id={id:?}, source={source:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_arg(arg));
|
||||
debug_assert_eq!(ma.type_id(), Some(arg.get_value_parser().type_id()));
|
||||
ma.set_source(source);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn start_custom_group(&mut self, id: Id, source: ValueSource) {
|
||||
debug!("ArgMatcher::start_custom_arg: id={id:?}, source={source:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_group());
|
||||
debug_assert_eq!(ma.type_id(), None);
|
||||
ma.set_source(source);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn start_occurrence_of_external(&mut self, cmd: &crate::Command) {
|
||||
let id = Id::from_static_ref(Id::EXTERNAL);
|
||||
debug!("ArgMatcher::start_occurrence_of_external: id={id:?}");
|
||||
let ma = self.entry(id).or_insert(MatchedArg::new_external(cmd));
|
||||
debug_assert_eq!(
|
||||
ma.type_id(),
|
||||
Some(
|
||||
cmd.get_external_subcommand_value_parser()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.type_id()
|
||||
)
|
||||
);
|
||||
ma.set_source(ValueSource::CommandLine);
|
||||
ma.new_val_group();
|
||||
}
|
||||
|
||||
pub(crate) fn add_val_to(&mut self, arg: &Id, val: AnyValue, raw_val: OsString) {
|
||||
let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
|
||||
ma.append_val(val, raw_val);
|
||||
}
|
||||
|
||||
pub(crate) fn add_index_to(&mut self, arg: &Id, idx: usize) {
|
||||
let ma = self.get_mut(arg).expect(INTERNAL_ERROR_MSG);
|
||||
ma.push_index(idx);
|
||||
}
|
||||
|
||||
pub(crate) fn needs_more_vals(&self, o: &Arg) -> bool {
|
||||
let num_pending = self
|
||||
.pending
|
||||
.as_ref()
|
||||
.and_then(|p| (p.id == *o.get_id()).then_some(p.raw_vals.len()))
|
||||
.unwrap_or(0);
|
||||
debug!(
|
||||
"ArgMatcher::needs_more_vals: o={}, pending={}",
|
||||
o.get_id(),
|
||||
num_pending
|
||||
);
|
||||
let expected = o.get_num_args().expect(INTERNAL_ERROR_MSG);
|
||||
debug!("ArgMatcher::needs_more_vals: expected={expected}, actual={num_pending}");
|
||||
expected.accepts_more(num_pending)
|
||||
}
|
||||
|
||||
pub(crate) fn pending_arg_id(&self) -> Option<&Id> {
|
||||
self.pending.as_ref().map(|p| &p.id)
|
||||
}
|
||||
|
||||
pub(crate) fn pending_values_mut(
|
||||
&mut self,
|
||||
id: &Id,
|
||||
ident: Option<Identifier>,
|
||||
trailing_values: bool,
|
||||
) -> &mut Vec<OsString> {
|
||||
let pending = self.pending.get_or_insert_with(|| PendingArg {
|
||||
id: id.clone(),
|
||||
ident,
|
||||
raw_vals: Default::default(),
|
||||
trailing_idx: None,
|
||||
});
|
||||
debug_assert_eq!(pending.id, *id, "{INTERNAL_ERROR_MSG}");
|
||||
if ident.is_some() {
|
||||
debug_assert_eq!(pending.ident, ident, "{INTERNAL_ERROR_MSG}");
|
||||
}
|
||||
if trailing_values {
|
||||
pending.trailing_idx.get_or_insert(pending.raw_vals.len());
|
||||
}
|
||||
&mut pending.raw_vals
|
||||
}
|
||||
|
||||
pub(crate) fn start_trailing(&mut self) {
|
||||
if let Some(pending) = &mut self.pending {
|
||||
// Allow asserting its started on subsequent calls
|
||||
pending.trailing_idx.get_or_insert(pending.raw_vals.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn take_pending(&mut self) -> Option<PendingArg> {
|
||||
self.pending.take()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ArgMatcher {
|
||||
type Target = ArgMatches;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.matches
|
||||
}
|
||||
}
|
63
vendor/clap_builder/src/parser/error.rs
vendored
Normal file
63
vendor/clap_builder/src/parser/error.rs
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
use crate::util::AnyValueId;
|
||||
|
||||
/// Violation of [`ArgMatches`][crate::ArgMatches] assumptions
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(missing_copy_implementations)] // We might add non-Copy types in the future
|
||||
#[non_exhaustive]
|
||||
pub enum MatchesError {
|
||||
/// Failed to downcast `AnyValue` to the specified type
|
||||
#[non_exhaustive]
|
||||
Downcast {
|
||||
/// Type for value stored in [`ArgMatches`][crate::ArgMatches]
|
||||
actual: AnyValueId,
|
||||
/// The target type to downcast to
|
||||
expected: AnyValueId,
|
||||
},
|
||||
/// Argument not defined in [`Command`][crate::Command]
|
||||
#[non_exhaustive]
|
||||
UnknownArgument {
|
||||
// Missing `id` but blocked on a public id type which will hopefully come with `unstable-v4`
|
||||
},
|
||||
}
|
||||
|
||||
impl MatchesError {
|
||||
#[cfg_attr(debug_assertions, track_caller)]
|
||||
pub(crate) fn unwrap<T>(id: &str, r: Result<T, MatchesError>) -> T {
|
||||
let err = match r {
|
||||
Ok(t) => {
|
||||
return t;
|
||||
}
|
||||
Err(err) => err,
|
||||
};
|
||||
panic!("Mismatch between definition and access of `{id}`. {err}",)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for MatchesError {}
|
||||
|
||||
impl std::fmt::Display for MatchesError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Downcast { actual, expected } => {
|
||||
writeln!(
|
||||
f,
|
||||
"Could not downcast to {expected:?}, need to downcast to {actual:?}"
|
||||
)
|
||||
}
|
||||
Self::UnknownArgument {} => {
|
||||
writeln!(f, "Unknown argument or group id. Make sure you are using the argument id and not the short or long flags")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_auto_traits() {
|
||||
static_assertions::assert_impl_all!(
|
||||
MatchesError: Send,
|
||||
Sync,
|
||||
std::panic::RefUnwindSafe,
|
||||
std::panic::UnwindSafe,
|
||||
Unpin
|
||||
);
|
||||
}
|
1
vendor/clap_builder/src/parser/features/mod.rs
vendored
Normal file
1
vendor/clap_builder/src/parser/features/mod.rs
vendored
Normal file
@ -0,0 +1 @@
|
||||
pub(crate) mod suggestions;
|
167
vendor/clap_builder/src/parser/features/suggestions.rs
vendored
Normal file
167
vendor/clap_builder/src/parser/features/suggestions.rs
vendored
Normal file
@ -0,0 +1,167 @@
|
||||
#[cfg(feature = "suggestions")]
|
||||
use std::cmp::Ordering;
|
||||
|
||||
// Internal
|
||||
use crate::builder::Command;
|
||||
|
||||
/// Find strings from an iterable of `possible_values` similar to a given value `v`
|
||||
/// Returns a Vec of all possible values that exceed a similarity threshold
|
||||
/// sorted by ascending similarity, most similar comes last
|
||||
#[cfg(feature = "suggestions")]
|
||||
pub(crate) fn did_you_mean<T, I>(v: &str, possible_values: I) -> Vec<String>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
let mut candidates: Vec<(f64, String)> = possible_values
|
||||
.into_iter()
|
||||
// GH #4660: using `jaro` because `jaro_winkler` implementation in `strsim-rs` is wrong
|
||||
// causing strings with common prefix >=10 to be considered perfectly similar
|
||||
.map(|pv| (strsim::jaro(v, pv.as_ref()), pv.as_ref().to_owned()))
|
||||
// Confidence of 0.7 so that bar -> baz is suggested
|
||||
.filter(|(confidence, _)| *confidence > 0.7)
|
||||
.collect();
|
||||
candidates.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap_or(Ordering::Equal));
|
||||
candidates.into_iter().map(|(_, pv)| pv).collect()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "suggestions"))]
|
||||
pub(crate) fn did_you_mean<T, I>(_: &str, _: I) -> Vec<String>
|
||||
where
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
|
||||
pub(crate) fn did_you_mean_flag<'a, 'help, I, T>(
|
||||
arg: &str,
|
||||
remaining_args: &[&std::ffi::OsStr],
|
||||
longs: I,
|
||||
subcommands: impl IntoIterator<Item = &'a mut Command>,
|
||||
) -> Option<(String, Option<String>)>
|
||||
where
|
||||
'help: 'a,
|
||||
T: AsRef<str>,
|
||||
I: IntoIterator<Item = T>,
|
||||
{
|
||||
use crate::mkeymap::KeyType;
|
||||
|
||||
match did_you_mean(arg, longs).pop() {
|
||||
Some(candidate) => Some((candidate, None)),
|
||||
None => subcommands
|
||||
.into_iter()
|
||||
.filter_map(|subcommand| {
|
||||
subcommand._build_self(false);
|
||||
|
||||
let longs = subcommand.get_keymap().keys().filter_map(|a| {
|
||||
if let KeyType::Long(v) = a {
|
||||
Some(v.to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let subcommand_name = subcommand.get_name();
|
||||
|
||||
let candidate = some!(did_you_mean(arg, longs).pop());
|
||||
let score = some!(remaining_args.iter().position(|x| subcommand_name == *x));
|
||||
Some((score, (candidate, Some(subcommand_name.to_string()))))
|
||||
})
|
||||
.min_by_key(|(x, _)| *x)
|
||||
.map(|(_, suggestion)| suggestion),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, feature = "suggestions"))]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn missing_letter() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(did_you_mean("tst", p_vals.iter()), vec!["test"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ambiguous() {
|
||||
let p_vals = ["test", "temp", "possible", "values"];
|
||||
assert_eq!(did_you_mean("te", p_vals.iter()), vec!["test", "temp"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unrelated() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean("hahaahahah", p_vals.iter()),
|
||||
Vec::<String>::new()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn best_fit() {
|
||||
let p_vals = [
|
||||
"test",
|
||||
"possible",
|
||||
"values",
|
||||
"alignmentStart",
|
||||
"alignmentScore",
|
||||
];
|
||||
assert_eq!(
|
||||
did_you_mean("alignmentScorr", p_vals.iter()),
|
||||
vec!["alignmentStart", "alignmentScore"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn best_fit_long_common_prefix_issue_4660() {
|
||||
let p_vals = ["alignmentScore", "alignmentStart"];
|
||||
assert_eq!(
|
||||
did_you_mean("alignmentScorr", p_vals.iter()),
|
||||
vec!["alignmentStart", "alignmentScore"]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_missing_letter() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("tst", &[], p_vals.iter(), []),
|
||||
Some(("test".to_owned(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_ambiguous() {
|
||||
let p_vals = ["test", "temp", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("te", &[], p_vals.iter(), []),
|
||||
Some(("temp".to_owned(), None))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_unrelated() {
|
||||
let p_vals = ["test", "possible", "values"];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("hahaahahah", &[], p_vals.iter(), []),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flag_best_fit() {
|
||||
let p_vals = [
|
||||
"test",
|
||||
"possible",
|
||||
"values",
|
||||
"alignmentStart",
|
||||
"alignmentScore",
|
||||
];
|
||||
assert_eq!(
|
||||
did_you_mean_flag("alignmentScorr", &[], p_vals.iter(), []),
|
||||
Some(("alignmentScore".to_owned(), None))
|
||||
);
|
||||
}
|
||||
}
|
2030
vendor/clap_builder/src/parser/matches/arg_matches.rs
vendored
Normal file
2030
vendor/clap_builder/src/parser/matches/arg_matches.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
225
vendor/clap_builder/src/parser/matches/matched_arg.rs
vendored
Normal file
225
vendor/clap_builder/src/parser/matches/matched_arg.rs
vendored
Normal file
@ -0,0 +1,225 @@
|
||||
// Std
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
iter::{Cloned, Flatten},
|
||||
slice::Iter,
|
||||
};
|
||||
|
||||
use crate::builder::ArgPredicate;
|
||||
use crate::parser::ValueSource;
|
||||
use crate::util::eq_ignore_case;
|
||||
use crate::util::AnyValue;
|
||||
use crate::util::AnyValueId;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct MatchedArg {
|
||||
source: Option<ValueSource>,
|
||||
indices: Vec<usize>,
|
||||
type_id: Option<AnyValueId>,
|
||||
vals: Vec<Vec<AnyValue>>,
|
||||
raw_vals: Vec<Vec<OsString>>,
|
||||
ignore_case: bool,
|
||||
}
|
||||
|
||||
impl MatchedArg {
|
||||
pub(crate) fn new_arg(arg: &crate::Arg) -> Self {
|
||||
let ignore_case = arg.is_ignore_case_set();
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: Some(arg.get_value_parser().type_id()),
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_group() -> Self {
|
||||
let ignore_case = false;
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: None,
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn new_external(cmd: &crate::Command) -> Self {
|
||||
let ignore_case = false;
|
||||
Self {
|
||||
source: None,
|
||||
indices: Vec::new(),
|
||||
type_id: Some(
|
||||
cmd.get_external_subcommand_value_parser()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.type_id(),
|
||||
),
|
||||
vals: Vec::new(),
|
||||
raw_vals: Vec::new(),
|
||||
ignore_case,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn indices(&self) -> Cloned<Iter<'_, usize>> {
|
||||
self.indices.iter().cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn get_index(&self, index: usize) -> Option<usize> {
|
||||
self.indices.get(index).cloned()
|
||||
}
|
||||
|
||||
pub(crate) fn push_index(&mut self, index: usize) {
|
||||
self.indices.push(index)
|
||||
}
|
||||
|
||||
pub(crate) fn vals(&self) -> Iter<Vec<AnyValue>> {
|
||||
self.vals.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn into_vals(self) -> Vec<Vec<AnyValue>> {
|
||||
self.vals
|
||||
}
|
||||
|
||||
pub(crate) fn vals_flatten(&self) -> Flatten<Iter<Vec<AnyValue>>> {
|
||||
self.vals.iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn into_vals_flatten(self) -> Flatten<std::vec::IntoIter<Vec<AnyValue>>> {
|
||||
self.vals.into_iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn raw_vals(&self) -> Iter<Vec<OsString>> {
|
||||
self.raw_vals.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn raw_vals_flatten(&self) -> Flatten<Iter<Vec<OsString>>> {
|
||||
self.raw_vals.iter().flatten()
|
||||
}
|
||||
|
||||
pub(crate) fn first(&self) -> Option<&AnyValue> {
|
||||
self.vals_flatten().next()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn first_raw(&self) -> Option<&OsString> {
|
||||
self.raw_vals_flatten().next()
|
||||
}
|
||||
|
||||
pub(crate) fn new_val_group(&mut self) {
|
||||
self.vals.push(vec![]);
|
||||
self.raw_vals.push(vec![]);
|
||||
}
|
||||
|
||||
pub(crate) fn append_val(&mut self, val: AnyValue, raw_val: OsString) {
|
||||
// We assume there is always a group created before.
|
||||
self.vals.last_mut().expect(INTERNAL_ERROR_MSG).push(val);
|
||||
self.raw_vals
|
||||
.last_mut()
|
||||
.expect(INTERNAL_ERROR_MSG)
|
||||
.push(raw_val);
|
||||
}
|
||||
|
||||
pub(crate) fn num_vals(&self) -> usize {
|
||||
self.vals.iter().map(|v| v.len()).sum()
|
||||
}
|
||||
|
||||
// Will be used later
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn num_vals_last_group(&self) -> usize {
|
||||
self.vals.last().map(|x| x.len()).unwrap_or(0)
|
||||
}
|
||||
|
||||
pub(crate) fn all_val_groups_empty(&self) -> bool {
|
||||
self.vals.iter().flatten().count() == 0
|
||||
}
|
||||
|
||||
pub(crate) fn check_explicit(&self, predicate: &ArgPredicate) -> bool {
|
||||
if self.source.map(|s| !s.is_explicit()).unwrap_or(false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
match predicate {
|
||||
ArgPredicate::Equals(val) => self.raw_vals_flatten().any(|v| {
|
||||
if self.ignore_case {
|
||||
// If `v` isn't utf8, it can't match `val`, so `OsStr::to_str` should be fine
|
||||
eq_ignore_case(&v.to_string_lossy(), &val.to_string_lossy())
|
||||
} else {
|
||||
OsString::as_os_str(v) == OsStr::new(val)
|
||||
}
|
||||
}),
|
||||
ArgPredicate::IsPresent => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn source(&self) -> Option<ValueSource> {
|
||||
self.source
|
||||
}
|
||||
|
||||
pub(crate) fn set_source(&mut self, source: ValueSource) {
|
||||
if let Some(existing) = self.source {
|
||||
self.source = Some(existing.max(source));
|
||||
} else {
|
||||
self.source = Some(source)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn type_id(&self) -> Option<AnyValueId> {
|
||||
self.type_id
|
||||
}
|
||||
|
||||
pub(crate) fn infer_type_id(&self, expected: AnyValueId) -> AnyValueId {
|
||||
self.type_id()
|
||||
.or_else(|| {
|
||||
self.vals_flatten()
|
||||
.map(|v| v.type_id())
|
||||
.find(|actual| *actual != expected)
|
||||
})
|
||||
.unwrap_or(expected)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for MatchedArg {
|
||||
fn eq(&self, other: &MatchedArg) -> bool {
|
||||
let MatchedArg {
|
||||
source: self_source,
|
||||
indices: self_indices,
|
||||
type_id: self_type_id,
|
||||
vals: _,
|
||||
raw_vals: self_raw_vals,
|
||||
ignore_case: self_ignore_case,
|
||||
} = self;
|
||||
let MatchedArg {
|
||||
source: other_source,
|
||||
indices: other_indices,
|
||||
type_id: other_type_id,
|
||||
vals: _,
|
||||
raw_vals: other_raw_vals,
|
||||
ignore_case: other_ignore_case,
|
||||
} = other;
|
||||
self_source == other_source
|
||||
&& self_indices == other_indices
|
||||
&& self_type_id == other_type_id
|
||||
&& self_raw_vals == other_raw_vals
|
||||
&& self_ignore_case == other_ignore_case
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for MatchedArg {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_grouped_vals_first() {
|
||||
let mut m = MatchedArg::new_group();
|
||||
m.new_val_group();
|
||||
m.new_val_group();
|
||||
m.append_val(AnyValue::new(String::from("bbb")), "bbb".into());
|
||||
m.append_val(AnyValue::new(String::from("ccc")), "ccc".into());
|
||||
assert_eq!(m.first_raw(), Some(&OsString::from("bbb")));
|
||||
}
|
||||
}
|
13
vendor/clap_builder/src/parser/matches/mod.rs
vendored
Normal file
13
vendor/clap_builder/src/parser/matches/mod.rs
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
mod arg_matches;
|
||||
mod matched_arg;
|
||||
mod value_source;
|
||||
|
||||
pub use arg_matches::IdsRef;
|
||||
pub use arg_matches::RawValues;
|
||||
pub use arg_matches::Values;
|
||||
pub use arg_matches::ValuesRef;
|
||||
pub use arg_matches::{ArgMatches, Indices};
|
||||
pub use value_source::ValueSource;
|
||||
|
||||
pub(crate) use arg_matches::SubCommand;
|
||||
pub(crate) use matched_arg::MatchedArg;
|
17
vendor/clap_builder/src/parser/matches/value_source.rs
vendored
Normal file
17
vendor/clap_builder/src/parser/matches/value_source.rs
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/// Origin of the argument's value
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
#[non_exhaustive]
|
||||
pub enum ValueSource {
|
||||
/// Value came [`Arg::default_value`][crate::Arg::default_value]
|
||||
DefaultValue,
|
||||
/// Value came [`Arg::env`][crate::Arg::env]
|
||||
EnvVariable,
|
||||
/// Value was passed in on the command-line
|
||||
CommandLine,
|
||||
}
|
||||
|
||||
impl ValueSource {
|
||||
pub(crate) fn is_explicit(self) -> bool {
|
||||
self != Self::DefaultValue
|
||||
}
|
||||
}
|
25
vendor/clap_builder/src/parser/mod.rs
vendored
Normal file
25
vendor/clap_builder/src/parser/mod.rs
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
//! [`Command`][crate::Command] line argument parser
|
||||
|
||||
mod arg_matcher;
|
||||
mod error;
|
||||
mod matches;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod parser;
|
||||
mod validator;
|
||||
|
||||
pub(crate) mod features;
|
||||
|
||||
pub(crate) use self::arg_matcher::ArgMatcher;
|
||||
pub(crate) use self::matches::{MatchedArg, SubCommand};
|
||||
pub(crate) use self::parser::Identifier;
|
||||
pub(crate) use self::parser::PendingArg;
|
||||
pub(crate) use self::parser::{ParseState, Parser};
|
||||
pub(crate) use self::validator::get_possible_values_cli;
|
||||
pub(crate) use self::validator::Validator;
|
||||
|
||||
pub use self::matches::IdsRef;
|
||||
pub use self::matches::RawValues;
|
||||
pub use self::matches::Values;
|
||||
pub use self::matches::ValuesRef;
|
||||
pub use self::matches::{ArgMatches, Indices, ValueSource};
|
||||
pub use error::MatchesError;
|
1622
vendor/clap_builder/src/parser/parser.rs
vendored
Normal file
1622
vendor/clap_builder/src/parser/parser.rs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
561
vendor/clap_builder/src/parser/validator.rs
vendored
Normal file
561
vendor/clap_builder/src/parser/validator.rs
vendored
Normal file
@ -0,0 +1,561 @@
|
||||
// Internal
|
||||
use crate::builder::StyledStr;
|
||||
use crate::builder::{Arg, ArgGroup, ArgPredicate, Command, PossibleValue};
|
||||
use crate::error::{Error, Result as ClapResult};
|
||||
use crate::output::Usage;
|
||||
use crate::parser::{ArgMatcher, ParseState};
|
||||
use crate::util::ChildGraph;
|
||||
use crate::util::FlatMap;
|
||||
use crate::util::FlatSet;
|
||||
use crate::util::Id;
|
||||
use crate::INTERNAL_ERROR_MSG;
|
||||
|
||||
pub(crate) struct Validator<'cmd> {
|
||||
cmd: &'cmd Command,
|
||||
required: ChildGraph<Id>,
|
||||
}
|
||||
|
||||
impl<'cmd> Validator<'cmd> {
|
||||
pub(crate) fn new(cmd: &'cmd Command) -> Self {
|
||||
let required = cmd.required_graph();
|
||||
Validator { cmd, required }
|
||||
}
|
||||
|
||||
pub(crate) fn validate(
|
||||
&mut self,
|
||||
parse_state: ParseState,
|
||||
matcher: &mut ArgMatcher,
|
||||
) -> ClapResult<()> {
|
||||
debug!("Validator::validate");
|
||||
let conflicts = Conflicts::with_args(self.cmd, matcher);
|
||||
let has_subcmd = matcher.subcommand_name().is_some();
|
||||
|
||||
if let ParseState::Opt(a) = parse_state {
|
||||
debug!("Validator::validate: needs_val_of={a:?}");
|
||||
|
||||
let o = &self.cmd[&a];
|
||||
let should_err = if let Some(v) = matcher.args.get(o.get_id()) {
|
||||
v.all_val_groups_empty() && o.get_min_vals() != 0
|
||||
} else {
|
||||
true
|
||||
};
|
||||
if should_err {
|
||||
return Err(Error::empty_value(
|
||||
self.cmd,
|
||||
&get_possible_values_cli(o)
|
||||
.iter()
|
||||
.filter(|pv| !pv.is_hide_set())
|
||||
.map(|n| n.get_name().to_owned())
|
||||
.collect::<Vec<_>>(),
|
||||
o.to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if !has_subcmd && self.cmd.is_arg_required_else_help_set() {
|
||||
let num_user_values = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.count();
|
||||
if num_user_values == 0 {
|
||||
let message = self.cmd.write_help_err(false);
|
||||
return Err(Error::display_help_error(self.cmd, message));
|
||||
}
|
||||
}
|
||||
if !has_subcmd && self.cmd.is_subcommand_required_set() {
|
||||
let bn = self.cmd.get_bin_name_fallback();
|
||||
return Err(Error::missing_subcommand(
|
||||
self.cmd,
|
||||
bn.to_string(),
|
||||
self.cmd
|
||||
.all_subcommand_names()
|
||||
.map(|s| s.to_owned())
|
||||
.collect::<Vec<_>>(),
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&[]),
|
||||
));
|
||||
}
|
||||
|
||||
ok!(self.validate_conflicts(matcher, &conflicts));
|
||||
if !(self.cmd.is_subcommand_negates_reqs_set() && has_subcmd) {
|
||||
ok!(self.validate_required(matcher, &conflicts));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_conflicts(
|
||||
&mut self,
|
||||
matcher: &ArgMatcher,
|
||||
conflicts: &Conflicts,
|
||||
) -> ClapResult<()> {
|
||||
debug!("Validator::validate_conflicts");
|
||||
|
||||
ok!(self.validate_exclusive(matcher));
|
||||
|
||||
for (arg_id, _) in matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.filter(|(arg_id, _)| self.cmd.find(arg_id).is_some())
|
||||
{
|
||||
debug!("Validator::validate_conflicts::iter: id={arg_id:?}");
|
||||
let conflicts = conflicts.gather_conflicts(self.cmd, arg_id);
|
||||
ok!(self.build_conflict_err(arg_id, &conflicts, matcher));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_exclusive(&self, matcher: &ArgMatcher) -> ClapResult<()> {
|
||||
debug!("Validator::validate_exclusive");
|
||||
let args_count = matcher
|
||||
.args()
|
||||
.filter(|(arg_id, matched)| {
|
||||
matched.check_explicit(&crate::builder::ArgPredicate::IsPresent)
|
||||
// Avoid including our own groups by checking none of them. If a group is present, the
|
||||
// args for the group will be.
|
||||
&& self.cmd.find(arg_id).is_some()
|
||||
})
|
||||
.count();
|
||||
if args_count <= 1 {
|
||||
// Nothing present to conflict with
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&crate::builder::ArgPredicate::IsPresent))
|
||||
.filter_map(|(id, _)| {
|
||||
debug!("Validator::validate_exclusive:iter:{id:?}");
|
||||
self.cmd
|
||||
.find(id)
|
||||
// Find `arg`s which are exclusive but also appear with other args.
|
||||
.filter(|&arg| arg.is_exclusive_set() && args_count > 1)
|
||||
})
|
||||
.next()
|
||||
.map(|arg| {
|
||||
// Throw an error for the first conflict found.
|
||||
Err(Error::argument_conflict(
|
||||
self.cmd,
|
||||
arg.to_string(),
|
||||
Vec::new(),
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&[]),
|
||||
))
|
||||
})
|
||||
.unwrap_or(Ok(()))
|
||||
}
|
||||
|
||||
fn build_conflict_err(
|
||||
&self,
|
||||
name: &Id,
|
||||
conflict_ids: &[Id],
|
||||
matcher: &ArgMatcher,
|
||||
) -> ClapResult<()> {
|
||||
if conflict_ids.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
debug!("Validator::build_conflict_err: name={name:?}");
|
||||
let mut seen = FlatSet::new();
|
||||
let conflicts = conflict_ids
|
||||
.iter()
|
||||
.flat_map(|c_id| {
|
||||
if self.cmd.find_group(c_id).is_some() {
|
||||
self.cmd.unroll_args_in_group(c_id)
|
||||
} else {
|
||||
vec![c_id.clone()]
|
||||
}
|
||||
})
|
||||
.filter_map(|c_id| {
|
||||
seen.insert(c_id.clone()).then(|| {
|
||||
let c_arg = self.cmd.find(&c_id).expect(INTERNAL_ERROR_MSG);
|
||||
c_arg.to_string()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
let former_arg = self.cmd.find(name).expect(INTERNAL_ERROR_MSG);
|
||||
let usg = self.build_conflict_err_usage(matcher, conflict_ids);
|
||||
Err(Error::argument_conflict(
|
||||
self.cmd,
|
||||
former_arg.to_string(),
|
||||
conflicts,
|
||||
usg,
|
||||
))
|
||||
}
|
||||
|
||||
fn build_conflict_err_usage(
|
||||
&self,
|
||||
matcher: &ArgMatcher,
|
||||
conflicting_keys: &[Id],
|
||||
) -> Option<StyledStr> {
|
||||
let used_filtered: Vec<Id> = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(n, _)| n)
|
||||
.filter(|n| {
|
||||
// Filter out the args we don't want to specify.
|
||||
self.cmd
|
||||
.find(n)
|
||||
.map(|a| !a.is_hide_set())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.filter(|key| !conflicting_keys.contains(key))
|
||||
.cloned()
|
||||
.collect();
|
||||
let required: Vec<Id> = used_filtered
|
||||
.iter()
|
||||
.filter_map(|key| self.cmd.find(key))
|
||||
.flat_map(|arg| arg.requires.iter().map(|item| &item.1))
|
||||
.filter(|key| !used_filtered.contains(key) && !conflicting_keys.contains(key))
|
||||
.chain(used_filtered.iter())
|
||||
.cloned()
|
||||
.collect();
|
||||
Usage::new(self.cmd)
|
||||
.required(&self.required)
|
||||
.create_usage_with_title(&required)
|
||||
}
|
||||
|
||||
fn gather_requires(&mut self, matcher: &ArgMatcher) {
|
||||
debug!("Validator::gather_requires");
|
||||
for (name, matched) in matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!("Validator::gather_requires:iter:{name:?}");
|
||||
if let Some(arg) = self.cmd.find(name) {
|
||||
let is_relevant = |(val, req_arg): &(ArgPredicate, Id)| -> Option<Id> {
|
||||
let required = matched.check_explicit(val);
|
||||
required.then(|| req_arg.clone())
|
||||
};
|
||||
|
||||
for req in self.cmd.unroll_arg_requires(is_relevant, arg.get_id()) {
|
||||
self.required.insert(req);
|
||||
}
|
||||
} else if let Some(g) = self.cmd.find_group(name) {
|
||||
debug!("Validator::gather_requires:iter:{name:?}:group");
|
||||
for r in &g.requires {
|
||||
self.required.insert(r.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_required(&mut self, matcher: &ArgMatcher, conflicts: &Conflicts) -> ClapResult<()> {
|
||||
debug!("Validator::validate_required: required={:?}", self.required);
|
||||
self.gather_requires(matcher);
|
||||
|
||||
let mut missing_required = Vec::new();
|
||||
let mut highest_index = 0;
|
||||
|
||||
let is_exclusive_present = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.any(|(id, _)| {
|
||||
self.cmd
|
||||
.find(id)
|
||||
.map(|arg| arg.is_exclusive_set())
|
||||
.unwrap_or_default()
|
||||
});
|
||||
debug!("Validator::validate_required: is_exclusive_present={is_exclusive_present}");
|
||||
|
||||
for arg_or_group in self
|
||||
.required
|
||||
.iter()
|
||||
.filter(|r| !matcher.check_explicit(r, &ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!("Validator::validate_required:iter:aog={arg_or_group:?}");
|
||||
if let Some(arg) = self.cmd.find(arg_or_group) {
|
||||
debug!("Validator::validate_required:iter: This is an arg");
|
||||
if !is_exclusive_present && !self.is_missing_required_ok(arg, conflicts) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
arg.get_id()
|
||||
);
|
||||
missing_required.push(arg.get_id().clone());
|
||||
if !arg.is_last_set() {
|
||||
highest_index = highest_index.max(arg.get_index().unwrap_or(0));
|
||||
}
|
||||
}
|
||||
} else if let Some(group) = self.cmd.find_group(arg_or_group) {
|
||||
debug!("Validator::validate_required:iter: This is a group");
|
||||
if !self
|
||||
.cmd
|
||||
.unroll_args_in_group(&group.id)
|
||||
.iter()
|
||||
.any(|a| matcher.check_explicit(a, &ArgPredicate::IsPresent))
|
||||
{
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
group.get_id()
|
||||
);
|
||||
missing_required.push(group.get_id().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the conditionally required args
|
||||
for a in self
|
||||
.cmd
|
||||
.get_arguments()
|
||||
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
|
||||
{
|
||||
let mut required = false;
|
||||
|
||||
for (other, val) in &a.r_ifs {
|
||||
if matcher.check_explicit(other, &ArgPredicate::Equals(val.into())) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
}
|
||||
|
||||
let match_all = a.r_ifs_all.iter().all(|(other, val)| {
|
||||
matcher.check_explicit(other, &ArgPredicate::Equals(val.into()))
|
||||
});
|
||||
if match_all && !a.r_ifs_all.is_empty() {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
|
||||
if (!a.r_unless.is_empty() || !a.r_unless_all.is_empty())
|
||||
&& self.fails_arg_required_unless(a, matcher)
|
||||
{
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
a.get_id()
|
||||
);
|
||||
required = true;
|
||||
}
|
||||
|
||||
if required {
|
||||
missing_required.push(a.get_id().clone());
|
||||
if !a.is_last_set() {
|
||||
highest_index = highest_index.max(a.get_index().unwrap_or(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// For display purposes, include all of the preceding positional arguments
|
||||
if !self.cmd.is_allow_missing_positional_set() {
|
||||
for pos in self
|
||||
.cmd
|
||||
.get_positionals()
|
||||
.filter(|a| !matcher.check_explicit(a.get_id(), &ArgPredicate::IsPresent))
|
||||
{
|
||||
if pos.get_index() < Some(highest_index) {
|
||||
debug!(
|
||||
"Validator::validate_required:iter: Missing {:?}",
|
||||
pos.get_id()
|
||||
);
|
||||
missing_required.push(pos.get_id().clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !missing_required.is_empty() {
|
||||
ok!(self.missing_required_error(matcher, missing_required));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_missing_required_ok(&self, a: &Arg, conflicts: &Conflicts) -> bool {
|
||||
debug!("Validator::is_missing_required_ok: {}", a.get_id());
|
||||
if !conflicts.gather_conflicts(self.cmd, a.get_id()).is_empty() {
|
||||
debug!("Validator::is_missing_required_ok: true (self)");
|
||||
return true;
|
||||
}
|
||||
for group_id in self.cmd.groups_for_arg(a.get_id()) {
|
||||
if !conflicts.gather_conflicts(self.cmd, &group_id).is_empty() {
|
||||
debug!("Validator::is_missing_required_ok: true ({group_id})");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// Failing a required unless means, the arg's "unless" wasn't present, and neither were they
|
||||
fn fails_arg_required_unless(&self, a: &Arg, matcher: &ArgMatcher) -> bool {
|
||||
debug!("Validator::fails_arg_required_unless: a={:?}", a.get_id());
|
||||
let exists = |id| matcher.check_explicit(id, &ArgPredicate::IsPresent);
|
||||
|
||||
(a.r_unless_all.is_empty() || !a.r_unless_all.iter().all(exists))
|
||||
&& !a.r_unless.iter().any(exists)
|
||||
}
|
||||
|
||||
// `req_args`: an arg to include in the error even if not used
|
||||
fn missing_required_error(
|
||||
&self,
|
||||
matcher: &ArgMatcher,
|
||||
raw_req_args: Vec<Id>,
|
||||
) -> ClapResult<()> {
|
||||
debug!("Validator::missing_required_error; incl={raw_req_args:?}");
|
||||
debug!(
|
||||
"Validator::missing_required_error: reqs={:?}",
|
||||
self.required
|
||||
);
|
||||
|
||||
let usg = Usage::new(self.cmd).required(&self.required);
|
||||
|
||||
let req_args = {
|
||||
#[cfg(feature = "usage")]
|
||||
{
|
||||
usg.get_required_usage_from(&raw_req_args, Some(matcher), true)
|
||||
.into_iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "usage"))]
|
||||
{
|
||||
raw_req_args
|
||||
.iter()
|
||||
.map(|id| {
|
||||
if let Some(arg) = self.cmd.find(id) {
|
||||
arg.to_string()
|
||||
} else if let Some(_group) = self.cmd.find_group(id) {
|
||||
self.cmd.format_group(id).to_string()
|
||||
} else {
|
||||
debug_assert!(false, "id={id:?} is unknown");
|
||||
"".to_owned()
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Validator::missing_required_error: req_args={req_args:#?}");
|
||||
|
||||
let used: Vec<Id> = matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(n, _)| n)
|
||||
.filter(|n| {
|
||||
// Filter out the args we don't want to specify.
|
||||
self.cmd
|
||||
.find(n)
|
||||
.map(|a| !a.is_hide_set())
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.cloned()
|
||||
.chain(raw_req_args)
|
||||
.collect();
|
||||
|
||||
Err(Error::missing_required_argument(
|
||||
self.cmd,
|
||||
req_args,
|
||||
usg.create_usage_with_title(&used),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Debug)]
|
||||
struct Conflicts {
|
||||
potential: FlatMap<Id, Vec<Id>>,
|
||||
}
|
||||
|
||||
impl Conflicts {
|
||||
fn with_args(cmd: &Command, matcher: &ArgMatcher) -> Self {
|
||||
let mut potential = FlatMap::new();
|
||||
potential.extend_unchecked(
|
||||
matcher
|
||||
.args()
|
||||
.filter(|(_, matched)| matched.check_explicit(&ArgPredicate::IsPresent))
|
||||
.map(|(id, _)| {
|
||||
let conf = gather_direct_conflicts(cmd, id);
|
||||
(id.clone(), conf)
|
||||
}),
|
||||
);
|
||||
Self { potential }
|
||||
}
|
||||
|
||||
fn gather_conflicts(&self, cmd: &Command, arg_id: &Id) -> Vec<Id> {
|
||||
debug!("Conflicts::gather_conflicts: arg={arg_id:?}");
|
||||
let mut conflicts = Vec::new();
|
||||
|
||||
let arg_id_conflicts_storage;
|
||||
let arg_id_conflicts = if let Some(arg_id_conflicts) = self.get_direct_conflicts(arg_id) {
|
||||
arg_id_conflicts
|
||||
} else {
|
||||
// `is_missing_required_ok` is a case where we check not-present args for conflicts
|
||||
arg_id_conflicts_storage = gather_direct_conflicts(cmd, arg_id);
|
||||
&arg_id_conflicts_storage
|
||||
};
|
||||
for (other_arg_id, other_arg_id_conflicts) in self.potential.iter() {
|
||||
if arg_id == other_arg_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
if arg_id_conflicts.contains(other_arg_id) {
|
||||
conflicts.push(other_arg_id.clone());
|
||||
}
|
||||
if other_arg_id_conflicts.contains(arg_id) {
|
||||
conflicts.push(other_arg_id.clone());
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Conflicts::gather_conflicts: conflicts={conflicts:?}");
|
||||
conflicts
|
||||
}
|
||||
|
||||
fn get_direct_conflicts(&self, arg_id: &Id) -> Option<&[Id]> {
|
||||
self.potential.get(arg_id).map(Vec::as_slice)
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_direct_conflicts(cmd: &Command, id: &Id) -> Vec<Id> {
|
||||
let conf = if let Some(arg) = cmd.find(id) {
|
||||
gather_arg_direct_conflicts(cmd, arg)
|
||||
} else if let Some(group) = cmd.find_group(id) {
|
||||
gather_group_direct_conflicts(group)
|
||||
} else {
|
||||
debug_assert!(false, "id={id:?} is unknown");
|
||||
Vec::new()
|
||||
};
|
||||
debug!("Conflicts::gather_direct_conflicts id={id:?}, conflicts={conf:?}",);
|
||||
conf
|
||||
}
|
||||
|
||||
fn gather_arg_direct_conflicts(cmd: &Command, arg: &Arg) -> Vec<Id> {
|
||||
let mut conf = arg.blacklist.clone();
|
||||
for group_id in cmd.groups_for_arg(arg.get_id()) {
|
||||
let group = cmd.find_group(&group_id).expect(INTERNAL_ERROR_MSG);
|
||||
conf.extend(group.conflicts.iter().cloned());
|
||||
if !group.multiple {
|
||||
for member_id in &group.args {
|
||||
if member_id != arg.get_id() {
|
||||
conf.push(member_id.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overrides are implicitly conflicts
|
||||
conf.extend(arg.overrides.iter().cloned());
|
||||
|
||||
conf
|
||||
}
|
||||
|
||||
fn gather_group_direct_conflicts(group: &ArgGroup) -> Vec<Id> {
|
||||
group.conflicts.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn get_possible_values_cli(a: &Arg) -> Vec<PossibleValue> {
|
||||
if !a.is_takes_value_set() {
|
||||
vec![]
|
||||
} else {
|
||||
a.get_value_parser()
|
||||
.possible_values()
|
||||
.map(|pvs| pvs.collect())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
}
|
127
vendor/clap_builder/src/util/any_value.rs
vendored
Normal file
127
vendor/clap_builder/src/util/any_value.rs
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct AnyValue {
|
||||
inner: std::sync::Arc<dyn std::any::Any + Send + Sync + 'static>,
|
||||
// While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track
|
||||
// the type_name in debug builds.
|
||||
id: AnyValueId,
|
||||
}
|
||||
|
||||
impl AnyValue {
|
||||
pub(crate) fn new<V: std::any::Any + Clone + Send + Sync + 'static>(inner: V) -> Self {
|
||||
let id = AnyValueId::of::<V>();
|
||||
let inner = std::sync::Arc::new(inner);
|
||||
Self { inner, id }
|
||||
}
|
||||
|
||||
pub(crate) fn downcast_ref<T: std::any::Any + Clone + Send + Sync + 'static>(
|
||||
&self,
|
||||
) -> Option<&T> {
|
||||
self.inner.downcast_ref::<T>()
|
||||
}
|
||||
|
||||
pub(crate) fn downcast_into<T: std::any::Any + Clone + Send + Sync>(self) -> Result<T, Self> {
|
||||
let id = self.id;
|
||||
let value =
|
||||
ok!(std::sync::Arc::downcast::<T>(self.inner).map_err(|inner| Self { inner, id }));
|
||||
let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone());
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub(crate) fn type_id(&self) -> AnyValueId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AnyValue {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
f.debug_struct("AnyValue").field("inner", &self.id).finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct AnyValueId {
|
||||
type_id: std::any::TypeId,
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: &'static str,
|
||||
}
|
||||
|
||||
impl AnyValueId {
|
||||
pub(crate) fn of<A: ?Sized + 'static>() -> Self {
|
||||
Self {
|
||||
type_id: std::any::TypeId::of::<A>(),
|
||||
#[cfg(debug_assertions)]
|
||||
type_name: std::any::type_name::<A>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for AnyValueId {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.type_id == other.type_id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for AnyValueId {}
|
||||
|
||||
impl PartialOrd for AnyValueId {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::any::TypeId> for AnyValueId {
|
||||
fn eq(&self, other: &std::any::TypeId) -> bool {
|
||||
self.type_id == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for AnyValueId {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.type_id.cmp(&other.type_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::hash::Hash for AnyValueId {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.type_id.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AnyValueId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
self.type_id.fmt(f)
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
f.debug_struct(self.type_name).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId {
|
||||
fn from(_: &'a A) -> Self {
|
||||
Self::of::<A>()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
#[cfg(debug_assertions)]
|
||||
fn debug_impl() {
|
||||
use super::*;
|
||||
|
||||
assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn eq_to_type_id() {
|
||||
use super::*;
|
||||
|
||||
let any_value_id = AnyValueId::of::<i32>();
|
||||
let type_id = std::any::TypeId::of::<i32>();
|
||||
assert_eq!(any_value_id, type_id);
|
||||
}
|
||||
}
|
116
vendor/clap_builder/src/util/color.rs
vendored
Normal file
116
vendor/clap_builder/src/util/color.rs
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
use crate::builder::PossibleValue;
|
||||
use crate::derive::ValueEnum;
|
||||
|
||||
/// Represents the color preferences for program output
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum ColorChoice {
|
||||
/// Enables colored output only when the output is going to a terminal or TTY.
|
||||
///
|
||||
/// **NOTE:** This is the default behavior of `clap`.
|
||||
///
|
||||
/// # Platform Specific
|
||||
///
|
||||
/// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Auto)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
Auto,
|
||||
|
||||
/// Enables colored output regardless of whether or not the output is going to a terminal/TTY.
|
||||
///
|
||||
/// # Platform Specific
|
||||
///
|
||||
/// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Always)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
Always,
|
||||
|
||||
/// Disables colored output no matter if the output is going to a terminal/TTY, or not.
|
||||
///
|
||||
/// # Platform Specific
|
||||
///
|
||||
/// This setting only applies to Unix, Linux, and macOS (i.e. non-Windows platforms)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[cfg(feature = "color")] {
|
||||
/// # use clap_builder as clap;
|
||||
/// # use clap::{Command, ColorChoice};
|
||||
/// Command::new("myprog")
|
||||
/// .color(ColorChoice::Never)
|
||||
/// .get_matches();
|
||||
/// # }
|
||||
/// ```
|
||||
Never,
|
||||
}
|
||||
|
||||
impl ColorChoice {
|
||||
/// Report all `possible_values`
|
||||
pub fn possible_values() -> impl Iterator<Item = PossibleValue> {
|
||||
Self::value_variants()
|
||||
.iter()
|
||||
.filter_map(ValueEnum::to_possible_value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ColorChoice {
|
||||
fn default() -> Self {
|
||||
Self::Auto
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for ColorChoice {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.to_possible_value()
|
||||
.expect("no values are skipped")
|
||||
.get_name()
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for ColorChoice {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
for variant in Self::value_variants() {
|
||||
if variant.to_possible_value().unwrap().matches(s, false) {
|
||||
return Ok(*variant);
|
||||
}
|
||||
}
|
||||
Err(format!("invalid variant: {s}"))
|
||||
}
|
||||
}
|
||||
|
||||
impl ValueEnum for ColorChoice {
|
||||
fn value_variants<'a>() -> &'a [Self] {
|
||||
&[Self::Auto, Self::Always, Self::Never]
|
||||
}
|
||||
|
||||
fn to_possible_value(&self) -> Option<PossibleValue> {
|
||||
Some(match self {
|
||||
Self::Auto => PossibleValue::new("auto"),
|
||||
Self::Always => PossibleValue::new("always"),
|
||||
Self::Never => PossibleValue::new("never"),
|
||||
})
|
||||
}
|
||||
}
|
254
vendor/clap_builder/src/util/flat_map.rs
vendored
Normal file
254
vendor/clap_builder/src/util/flat_map.rs
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Flat (Vec) backed map
|
||||
///
|
||||
/// This preserves insertion order
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct FlatMap<K, V> {
|
||||
keys: Vec<K>,
|
||||
values: Vec<V>,
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> FlatMap<K, V> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, key: K, mut value: V) -> Option<V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
std::mem::swap(&mut self.values[index], &mut value);
|
||||
return Some(value);
|
||||
}
|
||||
}
|
||||
|
||||
self.insert_unchecked(key, value);
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn insert_unchecked(&mut self, key: K, value: V) {
|
||||
self.keys.push(key);
|
||||
self.values.push(value);
|
||||
}
|
||||
|
||||
pub(crate) fn extend_unchecked(&mut self, iter: impl IntoIterator<Item = (K, V)>) {
|
||||
for (key, value) in iter {
|
||||
self.insert_unchecked(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for existing in &self.keys {
|
||||
if existing.borrow() == key {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
self.remove_entry(key).map(|(_, v)| v)
|
||||
}
|
||||
|
||||
pub fn remove_entry<Q: ?Sized>(&mut self, key: &Q) -> Option<(K, V)>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: std::hash::Hash + Eq,
|
||||
{
|
||||
let index = some!(self
|
||||
.keys
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find_map(|(i, k)| (k.borrow() == key).then_some(i)));
|
||||
let key = self.keys.remove(index);
|
||||
let value = self.values.remove(index);
|
||||
Some((key, value))
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.keys.is_empty()
|
||||
}
|
||||
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if *existing == key {
|
||||
return Entry::Occupied(OccupiedEntry { v: self, index });
|
||||
}
|
||||
}
|
||||
Entry::Vacant(VacantEntry { v: self, key })
|
||||
}
|
||||
|
||||
pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_mut<Q: ?Sized>(&mut self, k: &Q) -> Option<&mut V>
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for (index, existing) in self.keys.iter().enumerate() {
|
||||
if existing.borrow() == k {
|
||||
return Some(&mut self.values[index]);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn keys(&self) -> std::slice::Iter<'_, K> {
|
||||
self.keys.iter()
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> Iter<K, V> {
|
||||
Iter {
|
||||
keys: self.keys.iter(),
|
||||
values: self.values.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter_mut(&mut self) -> IterMut<K, V> {
|
||||
IterMut {
|
||||
keys: self.keys.iter_mut(),
|
||||
values: self.values.iter_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: PartialEq + Eq, V> Default for FlatMap<K, V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
keys: Default::default(),
|
||||
values: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum Entry<'a, K: 'a, V: 'a> {
|
||||
Vacant(VacantEntry<'a, K, V>),
|
||||
Occupied(OccupiedEntry<'a, K, V>),
|
||||
}
|
||||
|
||||
impl<'a, K: 'a, V: 'a> Entry<'a, K, V> {
|
||||
pub fn or_insert(self, default: V) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default);
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
|
||||
match self {
|
||||
Entry::Occupied(entry) => &mut entry.v.values[entry.index],
|
||||
Entry::Vacant(entry) => {
|
||||
entry.v.keys.push(entry.key);
|
||||
entry.v.values.push(default());
|
||||
entry.v.values.last_mut().unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VacantEntry<'a, K: 'a, V: 'a> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
key: K,
|
||||
}
|
||||
|
||||
pub struct OccupiedEntry<'a, K: 'a, V: 'a> {
|
||||
v: &'a mut FlatMap<K, V>,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
pub struct Iter<'a, K: 'a, V: 'a> {
|
||||
keys: std::slice::Iter<'a, K>,
|
||||
values: std::slice::Iter<'a, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for Iter<'a, K, V> {
|
||||
type Item = (&'a K, &'a V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
match self.keys.next() {
|
||||
Some(k) => {
|
||||
let v = self.values.next().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.keys.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
|
||||
match self.keys.next_back() {
|
||||
Some(k) => {
|
||||
let v = self.values.next_back().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {}
|
||||
|
||||
pub struct IterMut<'a, K: 'a, V: 'a> {
|
||||
keys: std::slice::IterMut<'a, K>,
|
||||
values: std::slice::IterMut<'a, V>,
|
||||
}
|
||||
|
||||
impl<'a, K, V> Iterator for IterMut<'a, K, V> {
|
||||
type Item = (&'a K, &'a mut V);
|
||||
|
||||
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next() {
|
||||
Some(k) => {
|
||||
let v = self.values.next().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
self.keys.size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> DoubleEndedIterator for IterMut<'a, K, V> {
|
||||
fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> {
|
||||
match self.keys.next_back() {
|
||||
Some(k) => {
|
||||
let v = self.values.next_back().unwrap();
|
||||
Some((k, v))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {}
|
107
vendor/clap_builder/src/util/flat_set.rs
vendored
Normal file
107
vendor/clap_builder/src/util/flat_set.rs
vendored
Normal file
@ -0,0 +1,107 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
/// Flat (Vec) backed set
|
||||
///
|
||||
/// This preserves insertion order
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub(crate) struct FlatSet<T> {
|
||||
inner: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> FlatSet<T> {
|
||||
pub(crate) fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, value: T) -> bool {
|
||||
for existing in &self.inner {
|
||||
if *existing == value {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
self.inner.push(value);
|
||||
true
|
||||
}
|
||||
|
||||
pub fn contains<Q: ?Sized>(&self, value: &Q) -> bool
|
||||
where
|
||||
T: Borrow<Q>,
|
||||
Q: Eq,
|
||||
{
|
||||
for existing in &self.inner {
|
||||
if existing.borrow() == value {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn retain<F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&T) -> bool,
|
||||
{
|
||||
self.inner.retain(f);
|
||||
}
|
||||
|
||||
pub(crate) fn is_empty(&self) -> bool {
|
||||
self.inner.is_empty()
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
pub fn sort_by_key<K, F>(&mut self, f: F)
|
||||
where
|
||||
F: FnMut(&T) -> K,
|
||||
K: Ord,
|
||||
{
|
||||
self.inner.sort_by_key(f);
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> Default for FlatSet<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> IntoIterator for FlatSet<T> {
|
||||
type Item = T;
|
||||
type IntoIter = std::vec::IntoIter<T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'s, T: PartialEq + Eq> IntoIterator for &'s FlatSet<T> {
|
||||
type Item = &'s T;
|
||||
type IntoIter = std::slice::Iter<'s, T>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.inner.iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> Extend<T> for FlatSet<T> {
|
||||
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
|
||||
for value in iter {
|
||||
self.insert(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PartialEq + Eq> FromIterator<T> for FlatSet<T> {
|
||||
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
let mut set = Self::new();
|
||||
for value in iter {
|
||||
set.insert(value);
|
||||
}
|
||||
set
|
||||
}
|
||||
}
|
49
vendor/clap_builder/src/util/graph.rs
vendored
Normal file
49
vendor/clap_builder/src/util/graph.rs
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
#[derive(Debug)]
|
||||
struct Child<T> {
|
||||
id: T,
|
||||
children: Vec<usize>,
|
||||
}
|
||||
|
||||
impl<T> Child<T> {
|
||||
fn new(id: T) -> Self {
|
||||
Child {
|
||||
id,
|
||||
children: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ChildGraph<T>(Vec<Child<T>>);
|
||||
|
||||
impl<T> ChildGraph<T>
|
||||
where
|
||||
T: Sized + PartialEq + Clone,
|
||||
{
|
||||
pub(crate) fn with_capacity(s: usize) -> Self {
|
||||
ChildGraph(Vec::with_capacity(s))
|
||||
}
|
||||
|
||||
pub(crate) fn insert(&mut self, req: T) -> usize {
|
||||
self.0.iter().position(|e| e.id == req).unwrap_or_else(|| {
|
||||
let idx = self.0.len();
|
||||
self.0.push(Child::new(req));
|
||||
idx
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn insert_child(&mut self, parent: usize, child: T) -> usize {
|
||||
let c_idx = self.0.len();
|
||||
self.0.push(Child::new(child));
|
||||
self.0[parent].children.push(c_idx);
|
||||
c_idx
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &T> {
|
||||
self.0.iter().map(|r| &r.id)
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, req: &T) -> bool {
|
||||
self.0.iter().any(|r| r.id == *req)
|
||||
}
|
||||
}
|
164
vendor/clap_builder/src/util/id.rs
vendored
Normal file
164
vendor/clap_builder/src/util/id.rs
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
use crate::builder::Str;
|
||||
|
||||
/// [`Arg`][crate::Arg] or [`ArgGroup`][crate::ArgGroup] identifier
|
||||
///
|
||||
/// This is used for accessing the value in [`ArgMatches`][crate::ArgMatches] or defining
|
||||
/// relationships between `Arg`s and `ArgGroup`s with functions like
|
||||
/// [`Arg::conflicts_with`][crate::Arg::conflicts_with].
|
||||
#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
|
||||
pub struct Id(Str);
|
||||
|
||||
impl Id {
|
||||
pub(crate) const HELP: &'static str = "help";
|
||||
pub(crate) const VERSION: &'static str = "version";
|
||||
pub(crate) const EXTERNAL: &'static str = "";
|
||||
|
||||
pub(crate) fn from_static_ref(name: &'static str) -> Self {
|
||||
Self(Str::from_static_ref(name))
|
||||
}
|
||||
|
||||
/// Get the raw string of the `Id`
|
||||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub(crate) fn as_internal_str(&self) -> &Str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Id> for Id {
|
||||
fn from(id: &'_ Id) -> Self {
|
||||
id.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Str> for Id {
|
||||
fn from(name: Str) -> Self {
|
||||
Self(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ Str> for Id {
|
||||
fn from(name: &'_ Str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<std::string::String> for Id {
|
||||
fn from(name: std::string::String) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "string")]
|
||||
impl From<&'_ std::string::String> for Id {
|
||||
fn from(name: &'_ std::string::String) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'static str> for Id {
|
||||
fn from(name: &'static str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&'_ &'static str> for Id {
|
||||
fn from(name: &'_ &'static str) -> Self {
|
||||
Self(name.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for Str {
|
||||
fn from(name: Id) -> Self {
|
||||
name.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for String {
|
||||
fn from(name: Id) -> Self {
|
||||
Str::from(name).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Display::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Id {
|
||||
#[inline]
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self.as_str(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Id {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<str> for Id {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&'_ str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
PartialEq::eq(self.as_str(), *other)
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for &'_ str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(*self, other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Str> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Str) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for Str {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for Id {
|
||||
#[inline]
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
PartialEq::eq(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
impl PartialEq<Id> for std::string::String {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Id) -> bool {
|
||||
PartialEq::eq(other, self)
|
||||
}
|
||||
}
|
47
vendor/clap_builder/src/util/mod.rs
vendored
Normal file
47
vendor/clap_builder/src/util/mod.rs
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
#![allow(clippy::single_component_path_imports)]
|
||||
|
||||
mod any_value;
|
||||
pub(crate) mod flat_map;
|
||||
pub(crate) mod flat_set;
|
||||
mod graph;
|
||||
mod id;
|
||||
mod str_to_bool;
|
||||
|
||||
pub use self::id::Id;
|
||||
|
||||
pub(crate) use self::any_value::AnyValue;
|
||||
pub(crate) use self::any_value::AnyValueId;
|
||||
pub(crate) use self::flat_map::Entry;
|
||||
pub(crate) use self::flat_map::FlatMap;
|
||||
pub(crate) use self::flat_set::FlatSet;
|
||||
pub(crate) use self::graph::ChildGraph;
|
||||
pub(crate) use self::str_to_bool::str_to_bool;
|
||||
pub(crate) use self::str_to_bool::FALSE_LITERALS;
|
||||
pub(crate) use self::str_to_bool::TRUE_LITERALS;
|
||||
|
||||
pub(crate) mod color;
|
||||
|
||||
pub(crate) const SUCCESS_CODE: i32 = 0;
|
||||
// While sysexists.h defines EX_USAGE as 64, this doesn't seem to be used much in practice but
|
||||
// instead 2 seems to be frequently used.
|
||||
// Examples
|
||||
// - GNU `ls` returns 2
|
||||
// - Python's `argparse` returns 2
|
||||
pub(crate) const USAGE_CODE: i32 = 2;
|
||||
|
||||
pub(crate) fn safe_exit(code: i32) -> ! {
|
||||
use std::io::Write;
|
||||
|
||||
let _ = std::io::stdout().lock().flush();
|
||||
let _ = std::io::stderr().lock().flush();
|
||||
|
||||
std::process::exit(code)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "unicode"))]
|
||||
pub(crate) fn eq_ignore_case(left: &str, right: &str) -> bool {
|
||||
left.eq_ignore_ascii_case(right)
|
||||
}
|
||||
|
||||
#[cfg(feature = "unicode")]
|
||||
pub(crate) use unicase::eq as eq_ignore_case;
|
21
vendor/clap_builder/src/util/str_to_bool.rs
vendored
Normal file
21
vendor/clap_builder/src/util/str_to_bool.rs
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/// True values are `y`, `yes`, `t`, `true`, `on`, and `1`.
|
||||
pub(crate) const TRUE_LITERALS: [&str; 6] = ["y", "yes", "t", "true", "on", "1"];
|
||||
|
||||
/// False values are `n`, `no`, `f`, `false`, `off`, and `0`.
|
||||
pub(crate) const FALSE_LITERALS: [&str; 6] = ["n", "no", "f", "false", "off", "0"];
|
||||
|
||||
/// Converts a string literal representation of truth to true or false.
|
||||
///
|
||||
/// `false` values are `n`, `no`, `f`, `false`, `off`, and `0` (case insensitive).
|
||||
///
|
||||
/// Any other value will be considered as `true`.
|
||||
pub(crate) fn str_to_bool(val: impl AsRef<str>) -> Option<bool> {
|
||||
let pat: &str = &val.as_ref().to_lowercase();
|
||||
if TRUE_LITERALS.contains(&pat) {
|
||||
Some(true)
|
||||
} else if FALSE_LITERALS.contains(&pat) {
|
||||
Some(false)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user