summaryrefslogtreecommitdiffstats
path: root/vendor/clap_complete
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/clap_complete')
-rw-r--r--vendor/clap_complete/.cargo-checksum.json1
-rw-r--r--vendor/clap_complete/Cargo.toml79
-rw-r--r--vendor/clap_complete/LICENSE-APACHE201
-rw-r--r--vendor/clap_complete/LICENSE-MIT21
-rw-r--r--vendor/clap_complete/README.md23
-rw-r--r--vendor/clap_complete/src/generator/mod.rs242
-rw-r--r--vendor/clap_complete/src/generator/utils.rs267
-rw-r--r--vendor/clap_complete/src/lib.rs70
-rw-r--r--vendor/clap_complete/src/macros.rs21
-rw-r--r--vendor/clap_complete/src/shells/bash.rs218
-rw-r--r--vendor/clap_complete/src/shells/elvish.rs142
-rw-r--r--vendor/clap_complete/src/shells/fish.rs192
-rw-r--r--vendor/clap_complete/src/shells/mod.rs15
-rw-r--r--vendor/clap_complete/src/shells/powershell.rs178
-rw-r--r--vendor/clap_complete/src/shells/shell.rs99
-rw-r--r--vendor/clap_complete/src/shells/zsh.rs663
16 files changed, 2432 insertions, 0 deletions
diff --git a/vendor/clap_complete/.cargo-checksum.json b/vendor/clap_complete/.cargo-checksum.json
new file mode 100644
index 000000000..e45184732
--- /dev/null
+++ b/vendor/clap_complete/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"78b091c02d2d903bba91b0bbb8d769a294a4be411caf9ef358b38b7fe2aed844","LICENSE-APACHE":"c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4","LICENSE-MIT":"6725d1437fc6c77301f2ff0e7d52914cf4f9509213e1078dc77d9356dbe6eac5","README.md":"29992473eab9cc65cb87acd7f8d9e76de780f7a7bf1cf8d225b1da5019b92461","src/generator/mod.rs":"63a0952a41e3d46769be84e6f6f6efebe187a9982090d0ec59100f2b0df79991","src/generator/utils.rs":"20fd8a7e18c66cf004f03cdd2af46b3f9fcee4b6d86d6f7bb94f2e15e98b2942","src/lib.rs":"4c1205e68ed8e12208ec96a430d9ca25982ff99c7d69dce73f28f9a48f680ca8","src/macros.rs":"63f96b4cf6e0704fb7df1335310e480bbcc5438b19337d46edfe587b393987b9","src/shells/bash.rs":"85823ec1abc1cb7fd5bd05387f19ae796bfba59edc5dba11860b3c3b2410f063","src/shells/elvish.rs":"d59f34254ca188ac2c0c96af9f0c14c55e579db1e97c6bd55699b4d50f365f66","src/shells/fish.rs":"e5c61b237c8b90d0ec582566d7aefef97fc90efcd964111a5bb987d0663d04e7","src/shells/mod.rs":"002352299be1ece75540e7b1502120590f4635f69a925b19484d272bd5491505","src/shells/powershell.rs":"95215c05d45a634150cc5dcd403f8468a47e316aa465e48c92775b2349cf2116","src/shells/shell.rs":"0c96280a1f7f1f4d14d62a958fca237825aa5e1b8b8f55f961972a2098f15e55","src/shells/zsh.rs":"2984c66f920ca5c91ad761ef9944e8fca3b73089e48a58ef605edb70e71af045"},"package":"df6f3613c0a3cddfd78b41b10203eb322cb29b600cbdf808a7d3db95691b8e25"} \ No newline at end of file
diff --git a/vendor/clap_complete/Cargo.toml b/vendor/clap_complete/Cargo.toml
new file mode 100644
index 000000000..175767620
--- /dev/null
+++ b/vendor/clap_complete/Cargo.toml
@@ -0,0 +1,79 @@
+# 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 = "2018"
+name = "clap_complete"
+version = "3.1.1"
+include = ["src/**/*", "Cargo.toml", "LICENSE-*", "README.md"]
+description = "Generate shell completion scripts for your clap::Command"
+documentation = "https://docs.rs/clap_complete"
+readme = "README.md"
+keywords = ["clap", "cli", "completion", "bash"]
+categories = ["command-line-interface"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/clap-rs/clap/tree/master/clap_complete"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+[[package.metadata.release.pre-release-replacements]]
+file = "CHANGELOG.md"
+min = 1
+replace = "{{version}}"
+search = "Unreleased"
+
+[[package.metadata.release.pre-release-replacements]]
+exactly = 1
+file = "CHANGELOG.md"
+replace = "...{{tag_name}}"
+search = "\\.\\.\\.HEAD"
+
+[[package.metadata.release.pre-release-replacements]]
+file = "CHANGELOG.md"
+min = 1
+replace = "{{date}}"
+search = "ReleaseDate"
+
+[[package.metadata.release.pre-release-replacements]]
+exactly = 1
+file = "CHANGELOG.md"
+replace = "<!-- next-header -->\n## [Unreleased] - ReleaseDate\n"
+search = "<!-- next-header -->"
+
+[[package.metadata.release.pre-release-replacements]]
+exactly = 1
+file = "CHANGELOG.md"
+replace = "<!-- next-url -->\n[Unreleased]: https://github.com/clap-rs/clap/compare/{{tag_name}}...HEAD"
+search = "<!-- next-url -->"
+
+[[package.metadata.release.pre-release-replacements]]
+exactly = 4
+file = "README.md"
+prerelease = true
+replace = "github.com/clap-rs/clap/blob/{{tag_name}}/"
+search = "github.com/clap-rs/clap/blob/[^/]+/"
+
+[lib]
+bench = false
+[dependencies.clap]
+version = "3.1.0"
+features = ["std"]
+default-features = false
+[dev-dependencies.clap]
+version = "3.1.0"
+features = ["std", "derive"]
+default-features = false
+
+[dev-dependencies.pretty_assertions]
+version = "1.0"
+
+[features]
+debug = ["clap/debug"]
+default = []
diff --git a/vendor/clap_complete/LICENSE-APACHE b/vendor/clap_complete/LICENSE-APACHE
new file mode 100644
index 000000000..261eeb9e9
--- /dev/null
+++ b/vendor/clap_complete/LICENSE-APACHE
@@ -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.
diff --git a/vendor/clap_complete/LICENSE-MIT b/vendor/clap_complete/LICENSE-MIT
new file mode 100644
index 000000000..5acedf041
--- /dev/null
+++ b/vendor/clap_complete/LICENSE-MIT
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015-2016 Kevin B. Knapp
+
+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.
diff --git a/vendor/clap_complete/README.md b/vendor/clap_complete/README.md
new file mode 100644
index 000000000..5336af86b
--- /dev/null
+++ b/vendor/clap_complete/README.md
@@ -0,0 +1,23 @@
+<!-- omit in TOC -->
+# clap_complete
+
+> **Shell completion generation for `clap`**
+
+[![Crates.io](https://img.shields.io/crates/v/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
+[![Crates.io](https://img.shields.io/crates/d/clap_complete?style=flat-square)](https://crates.io/crates/clap_complete)
+[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v3.1.1/LICENSE-APACHE)
+[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/clap-rs/clap/blob/clap_complete-v3.1.1/LICENSE-MIT)
+
+Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
+
+1. [About](#about)
+2. [API Reference](https://docs.rs/clap_complete)
+3. [Questions & Discussions](https://github.com/clap-rs/clap/discussions)
+4. [CONTRIBUTING](https://github.com/clap-rs/clap/blob/clap_complete-v3.1.1/clap_complete/CONTRIBUTING.md)
+5. [Sponsors](https://github.com/clap-rs/clap/blob/clap_complete-v3.1.1/README.md#sponsors)
+
+## About
+
+### Related Projects
+
+- [clap_complete_fig](https://crates.io/crates/clap_complete_fig) for [fig](https://fig.io/) shell completion support
diff --git a/vendor/clap_complete/src/generator/mod.rs b/vendor/clap_complete/src/generator/mod.rs
new file mode 100644
index 000000000..2d00c281d
--- /dev/null
+++ b/vendor/clap_complete/src/generator/mod.rs
@@ -0,0 +1,242 @@
+//! Shell completion machinery
+
+pub mod utils;
+
+use std::ffi::OsString;
+use std::fs::File;
+use std::io::Error;
+use std::io::Write;
+use std::path::PathBuf;
+
+use clap::Command;
+
+/// Generator trait which can be used to write generators
+pub trait Generator {
+ /// Returns the file name that is created when this generator is called during compile time.
+ ///
+ /// # Panics
+ ///
+ /// May panic when called outside of the context of [`generate`] or [`generate_to`]
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use std::io::Write;
+ /// # use clap::Command;
+ /// use clap_complete::Generator;
+ ///
+ /// pub struct Fish;
+ ///
+ /// impl Generator for Fish {
+ /// # fn generate(&self, cmd: &Command, buf: &mut dyn Write) {}
+ /// fn file_name(&self, name: &str) -> String {
+ /// format!("{}.fish", name)
+ /// }
+ /// }
+ /// ```
+ fn file_name(&self, name: &str) -> String;
+
+ /// Generates output out of [`clap::Command`](Command).
+ ///
+ /// # Panics
+ ///
+ /// May panic when called outside of the context of [`generate`] or [`generate_to`]
+ ///
+ /// # Examples
+ ///
+ /// The following example generator displays the [`clap::Command`](Command)
+ /// as if it is printed using [`std::println`].
+ ///
+ /// ```
+ /// use std::{io::Write, fmt::write};
+ /// use clap::Command;
+ /// use clap_complete::Generator;
+ ///
+ /// pub struct ClapDebug;
+ ///
+ /// impl Generator for ClapDebug {
+ /// fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ /// write!(buf, "{}", cmd).unwrap();
+ /// }
+ /// # fn file_name(&self, name: &str) -> String {
+ /// # name.into()
+ /// # }
+ /// }
+ /// ```
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write);
+}
+
+/// Generate a completions file for a specified shell at compile-time.
+///
+/// **NOTE:** to generate the file at compile time you must use a `build.rs` "Build Script" or a
+/// [`cargo-xtask`](https://github.com/matklad/cargo-xtask)
+///
+/// # Examples
+///
+/// The following example generates a bash completion script via a `build.rs` script. In this
+/// simple example, we'll demo a very small application with only a single subcommand and two
+/// args. Real applications could be many multiple levels deep in subcommands, and have tens or
+/// potentially hundreds of arguments.
+///
+/// First, it helps if we separate out our `Command` definition into a separate file. Whether you
+/// do this as a function, or bare Command definition is a matter of personal preference.
+///
+/// ```
+/// // src/cli.rs
+///
+/// use clap::{Command, Arg};
+///
+/// pub fn build_cli() -> Command<'static> {
+/// Command::new("compl")
+/// .about("Tests completions")
+/// .arg(Arg::new("file")
+/// .help("some input file"))
+/// .subcommand(Command::new("test")
+/// .about("tests things")
+/// .arg(Arg::new("case")
+/// .long("case")
+/// .takes_value(true)
+/// .help("the case to test")))
+/// }
+/// ```
+///
+/// In our regular code, we can simply call this `build_cli()` function, then call
+/// `get_matches()`, or any of the other normal methods directly after. For example:
+///
+/// ```ignore
+/// // src/main.rs
+///
+/// mod cli;
+///
+/// fn main() {
+/// let _m = cli::build_cli().get_matches();
+///
+/// // normal logic continues...
+/// }
+/// ```
+///
+/// Next, we set up our `Cargo.toml` to use a `build.rs` build script.
+///
+/// ```toml
+/// # Cargo.toml
+/// build = "build.rs"
+///
+/// [dependencies]
+/// clap = "*"
+///
+/// [build-dependencies]
+/// clap = "*"
+/// clap_complete = "*"
+/// ```
+///
+/// Next, we place a `build.rs` in our project root.
+///
+/// ```ignore
+/// use clap_complete::{generate_to, shells::Bash};
+/// use std::env;
+/// use std::io::Error;
+///
+/// include!("src/cli.rs");
+///
+/// fn main() -> Result<(), Error> {
+/// let outdir = match env::var_os("OUT_DIR") {
+/// None => return Ok(()),
+/// Some(outdir) => outdir,
+/// };
+///
+/// let mut cmd = build_cli();
+/// let path = generate_to(
+/// Bash,
+/// &mut cmd, // We need to specify what generator to use
+/// "myapp", // We need to specify the bin name manually
+/// outdir, // We need to specify where to write to
+/// )?;
+///
+/// println!("cargo:warning=completion file is generated: {:?}", path);
+///
+/// Ok(())
+/// }
+/// ```
+///
+/// Now, once we compile there will be a `{bin_name}.bash` file in the directory.
+/// Assuming we compiled with debug mode, it would be somewhere similar to
+/// `<project>/target/debug/build/myapp-<hash>/out/myapp.bash`.
+///
+/// **NOTE:** Please look at the individual [shells][crate::shells]
+/// to see the name of the files generated.
+pub fn generate_to<G, S, T>(
+ gen: G,
+ cmd: &mut clap::Command,
+ bin_name: S,
+ out_dir: T,
+) -> Result<PathBuf, Error>
+where
+ G: Generator,
+ S: Into<String>,
+ T: Into<OsString>,
+{
+ cmd.set_bin_name(bin_name);
+
+ let out_dir = PathBuf::from(out_dir.into());
+ let file_name = gen.file_name(cmd.get_bin_name().unwrap());
+
+ let path = out_dir.join(file_name);
+ let mut file = File::create(&path)?;
+
+ _generate::<G, S>(gen, cmd, &mut file);
+ Ok(path)
+}
+
+/// Generate a completions file for a specified shell at runtime.
+///
+/// Until `cargo install` can install extra files like a completion script, this may be
+/// used e.g. in a command that outputs the contents of the completion script, to be
+/// redirected into a file by the user.
+///
+/// # Examples
+///
+/// Assuming a separate `cli.rs` like the [example above](generate_to()),
+/// we can let users generate a completion script using a command:
+///
+/// ```ignore
+/// // src/main.rs
+///
+/// mod cli;
+/// use std::io;
+/// use clap_complete::{generate, shells::Bash};
+///
+/// fn main() {
+/// let matches = cli::build_cli().get_matches();
+///
+/// if matches.is_present("generate-bash-completions") {
+/// generate(Bash, &mut cli::build_cli(), "myapp", &mut io::stdout());
+/// }
+///
+/// // normal logic continues...
+/// }
+///
+/// ```
+///
+/// Usage:
+///
+/// ```shell
+/// $ myapp generate-bash-completions > /usr/share/bash-completion/completions/myapp.bash
+/// ```
+pub fn generate<G, S>(gen: G, cmd: &mut clap::Command, bin_name: S, buf: &mut dyn Write)
+where
+ G: Generator,
+ S: Into<String>,
+{
+ cmd.set_bin_name(bin_name);
+ _generate::<G, S>(gen, cmd, buf)
+}
+
+fn _generate<G, S>(gen: G, cmd: &mut clap::Command, buf: &mut dyn Write)
+where
+ G: Generator,
+ S: Into<String>,
+{
+ cmd._build_all();
+
+ gen.generate(cmd, buf)
+}
diff --git a/vendor/clap_complete/src/generator/utils.rs b/vendor/clap_complete/src/generator/utils.rs
new file mode 100644
index 000000000..b8aaa4bd5
--- /dev/null
+++ b/vendor/clap_complete/src/generator/utils.rs
@@ -0,0 +1,267 @@
+//! Helpers for writing generators
+
+use clap::{Arg, Command};
+
+/// Gets all subcommands including child subcommands in the form of `("name", "bin_name")`.
+///
+/// Subcommand `rustup toolchain install` would be converted to
+/// `("install", "rustup toolchain install")`.
+pub fn all_subcommands(cmd: &Command) -> Vec<(String, String)> {
+ let mut subcmds: Vec<_> = subcommands(cmd);
+
+ for sc_v in cmd.get_subcommands().map(all_subcommands) {
+ subcmds.extend(sc_v);
+ }
+
+ subcmds
+}
+
+/// Finds the subcommand [`clap::Command`] from the given [`clap::Command`] with the given path.
+///
+/// **NOTE:** `path` should not contain the root `bin_name`.
+pub fn find_subcommand_with_path<'help, 'cmd>(
+ p: &'cmd Command<'help>,
+ path: Vec<&str>,
+) -> &'cmd Command<'help> {
+ let mut cmd = p;
+
+ for sc in path {
+ cmd = cmd.find_subcommand(sc).unwrap();
+ }
+
+ cmd
+}
+
+/// Gets subcommands of [`clap::Command`] in the form of `("name", "bin_name")`.
+///
+/// Subcommand `rustup toolchain install` would be converted to
+/// `("install", "rustup toolchain install")`.
+pub fn subcommands(p: &Command) -> Vec<(String, String)> {
+ debug!("subcommands: name={}", p.get_name());
+ debug!("subcommands: Has subcommands...{:?}", p.has_subcommands());
+
+ let mut subcmds = vec![];
+
+ if !p.has_subcommands() {
+ return subcmds;
+ }
+
+ for sc in p.get_subcommands() {
+ let sc_bin_name = sc.get_bin_name().unwrap();
+
+ debug!(
+ "subcommands:iter: name={}, bin_name={}",
+ sc.get_name(),
+ sc_bin_name
+ );
+
+ subcmds.push((sc.get_name().to_string(), sc_bin_name.to_string()));
+ }
+
+ subcmds
+}
+
+/// Gets all the short options, their visible aliases and flags of a [`clap::Command`].
+/// Includes `h` and `V` depending on the [`clap::AppSettings`].
+pub fn shorts_and_visible_aliases(p: &Command) -> Vec<char> {
+ debug!("shorts: name={}", p.get_name());
+
+ p.get_arguments()
+ .filter_map(|a| {
+ if !a.is_positional() {
+ if a.get_visible_short_aliases().is_some() && a.get_short().is_some() {
+ let mut shorts_and_visible_aliases = a.get_visible_short_aliases().unwrap();
+ shorts_and_visible_aliases.push(a.get_short().unwrap());
+ Some(shorts_and_visible_aliases)
+ } else if a.get_visible_short_aliases().is_none() && a.get_short().is_some() {
+ Some(vec![a.get_short().unwrap()])
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })
+ .flatten()
+ .collect()
+}
+
+/// Gets all the long options, their visible aliases and flags of a [`clap::Command`].
+/// Includes `help` and `version` depending on the [`clap::AppSettings`].
+pub fn longs_and_visible_aliases(p: &Command) -> Vec<String> {
+ debug!("longs: name={}", p.get_name());
+
+ p.get_arguments()
+ .filter_map(|a| {
+ if !a.is_positional() {
+ if a.get_visible_aliases().is_some() && a.get_long().is_some() {
+ let mut visible_aliases: Vec<_> = a
+ .get_visible_aliases()
+ .unwrap()
+ .into_iter()
+ .map(|s| s.to_string())
+ .collect();
+ visible_aliases.push(a.get_long().unwrap().to_string());
+ Some(visible_aliases)
+ } else if a.get_visible_aliases().is_none() && a.get_long().is_some() {
+ Some(vec![a.get_long().unwrap().to_string()])
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })
+ .flatten()
+ .collect()
+}
+
+/// Gets all the flags of a [`clap::Command`](Command).
+/// Includes `help` and `version` depending on the [`clap::AppSettings`].
+pub fn flags<'help>(p: &Command<'help>) -> Vec<Arg<'help>> {
+ debug!("flags: name={}", p.get_name());
+ p.get_arguments()
+ .filter(|a| !a.is_takes_value_set() && !a.is_positional())
+ .cloned()
+ .collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use clap::Arg;
+ use pretty_assertions::assert_eq;
+
+ fn common_app() -> Command<'static> {
+ Command::new("myapp")
+ .subcommand(
+ Command::new("test").subcommand(Command::new("config")).arg(
+ Arg::new("file")
+ .short('f')
+ .short_alias('c')
+ .visible_short_alias('p')
+ .long("file")
+ .visible_alias("path"),
+ ),
+ )
+ .subcommand(Command::new("hello"))
+ .bin_name("my-cmd")
+ }
+
+ fn built() -> Command<'static> {
+ let mut cmd = common_app();
+
+ cmd._build_all();
+ cmd
+ }
+
+ fn built_with_version() -> Command<'static> {
+ let mut cmd = common_app().version("3.0");
+
+ cmd._build_all();
+ cmd
+ }
+
+ #[test]
+ fn test_subcommands() {
+ let cmd = built_with_version();
+
+ assert_eq!(
+ subcommands(&cmd),
+ vec![
+ ("test".to_string(), "my-cmd test".to_string()),
+ ("hello".to_string(), "my-cmd hello".to_string()),
+ ("help".to_string(), "my-cmd help".to_string()),
+ ]
+ );
+ }
+
+ #[test]
+ fn test_all_subcommands() {
+ let cmd = built_with_version();
+
+ assert_eq!(
+ all_subcommands(&cmd),
+ vec![
+ ("test".to_string(), "my-cmd test".to_string()),
+ ("hello".to_string(), "my-cmd hello".to_string()),
+ ("help".to_string(), "my-cmd help".to_string()),
+ ("config".to_string(), "my-cmd test config".to_string()),
+ ("help".to_string(), "my-cmd test help".to_string()),
+ ]
+ );
+ }
+
+ #[test]
+ fn test_find_subcommand_with_path() {
+ let cmd = built_with_version();
+ let sc_app = find_subcommand_with_path(&cmd, "test config".split(' ').collect());
+
+ assert_eq!(sc_app.get_name(), "config");
+ }
+
+ #[test]
+ fn test_flags() {
+ let cmd = built_with_version();
+ let actual_flags = flags(&cmd);
+
+ assert_eq!(actual_flags.len(), 2);
+ assert_eq!(actual_flags[0].get_long(), Some("help"));
+ assert_eq!(actual_flags[1].get_long(), Some("version"));
+
+ let sc_flags = flags(find_subcommand_with_path(&cmd, vec!["test"]));
+
+ assert_eq!(sc_flags.len(), 2);
+ assert_eq!(sc_flags[0].get_long(), Some("file"));
+ assert_eq!(sc_flags[1].get_long(), Some("help"));
+ }
+
+ #[test]
+ fn test_flag_subcommand() {
+ let cmd = built();
+ let actual_flags = flags(&cmd);
+
+ assert_eq!(actual_flags.len(), 1);
+ assert_eq!(actual_flags[0].get_long(), Some("help"));
+
+ let sc_flags = flags(find_subcommand_with_path(&cmd, vec!["test"]));
+
+ assert_eq!(sc_flags.len(), 2);
+ assert_eq!(sc_flags[0].get_long(), Some("file"));
+ assert_eq!(sc_flags[1].get_long(), Some("help"));
+ }
+
+ #[test]
+ fn test_shorts() {
+ let cmd = built_with_version();
+ let shorts = shorts_and_visible_aliases(&cmd);
+
+ assert_eq!(shorts.len(), 2);
+ assert_eq!(shorts[0], 'h');
+ assert_eq!(shorts[1], 'V');
+
+ let sc_shorts = shorts_and_visible_aliases(find_subcommand_with_path(&cmd, vec!["test"]));
+
+ assert_eq!(sc_shorts.len(), 3);
+ assert_eq!(sc_shorts[0], 'p');
+ assert_eq!(sc_shorts[1], 'f');
+ assert_eq!(sc_shorts[2], 'h');
+ }
+
+ #[test]
+ fn test_longs() {
+ let cmd = built_with_version();
+ let longs = longs_and_visible_aliases(&cmd);
+
+ assert_eq!(longs.len(), 2);
+ assert_eq!(longs[0], "help");
+ assert_eq!(longs[1], "version");
+
+ let sc_longs = longs_and_visible_aliases(find_subcommand_with_path(&cmd, vec!["test"]));
+
+ assert_eq!(sc_longs.len(), 3);
+ assert_eq!(sc_longs[0], "path");
+ assert_eq!(sc_longs[1], "file");
+ assert_eq!(sc_longs[2], "help");
+ }
+}
diff --git a/vendor/clap_complete/src/lib.rs b/vendor/clap_complete/src/lib.rs
new file mode 100644
index 000000000..a22ff9ac3
--- /dev/null
+++ b/vendor/clap_complete/src/lib.rs
@@ -0,0 +1,70 @@
+// Copyright â“’ 2015-2018 Kevin B. Knapp
+//
+// `clap_complete` is distributed under the terms of both the MIT license and the Apache License
+// (Version 2.0).
+// See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files in this repository
+// for more information.
+
+#![doc(html_logo_url = "https://raw.githubusercontent.com/clap-rs/clap/master/assets/clap.png")]
+#![doc = include_str!("../README.md")]
+#![warn(missing_docs, trivial_casts, unused_allocation, trivial_numeric_casts)]
+#![forbid(unsafe_code)]
+#![allow(clippy::needless_doctest_main)]
+
+//! ## Quick Start
+//!
+//! - For generating at compile-time, see [`generate_to`]
+//! - For generating at runtime, see [`generate`]
+//!
+//! [`Shell`] is a convenience `enum` for an argument value type that implements `Generator`
+//! for each natively-supported shell type.
+//!
+//! ## Example
+//!
+//! ```rust,no_run
+//! use clap::{Command, AppSettings, Arg, ValueHint};
+//! use clap_complete::{generate, Generator, Shell};
+//! use std::io;
+//!
+//! fn build_cli() -> Command<'static> {
+//! Command::new("example")
+//! .arg(Arg::new("file")
+//! .help("some input file")
+//! .value_hint(ValueHint::AnyPath),
+//! )
+//! .arg(
+//! Arg::new("generator")
+//! .long("generate")
+//! .possible_values(Shell::possible_values()),
+//! )
+//! }
+//!
+//! fn print_completions<G: Generator>(gen: G, cmd: &mut Command) {
+//! generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout());
+//! }
+//!
+//! fn main() {
+//! let matches = build_cli().get_matches();
+//!
+//! if let Ok(generator) = matches.value_of_t::<Shell>("generator") {
+//! let mut cmd = build_cli();
+//! eprintln!("Generating completion file for {}...", generator);
+//! print_completions(generator, &mut cmd);
+//! }
+//! }
+//! ```
+
+const INTERNAL_ERROR_MSG: &str = "Fatal internal error. Please consider filing a bug \
+ report at https://github.com/clap-rs/clap/issues";
+
+#[macro_use]
+#[allow(missing_docs)]
+mod macros;
+
+pub mod generator;
+pub mod shells;
+
+pub use generator::generate;
+pub use generator::generate_to;
+pub use generator::Generator;
+pub use shells::Shell;
diff --git a/vendor/clap_complete/src/macros.rs b/vendor/clap_complete/src/macros.rs
new file mode 100644
index 000000000..def051434
--- /dev/null
+++ b/vendor/clap_complete/src/macros.rs
@@ -0,0 +1,21 @@
+macro_rules! w {
+ ($buf:expr, $to_w:expr) => {
+ match $buf.write_all($to_w) {
+ Ok(..) => (),
+ Err(..) => panic!("Failed to write to generated file"),
+ }
+ };
+}
+
+#[cfg(feature = "debug")]
+macro_rules! debug {
+ ($($arg:tt)*) => {
+ print!("[{:>w$}] \t", module_path!(), w = 28);
+ println!($($arg)*)
+ }
+}
+
+#[cfg(not(feature = "debug"))]
+macro_rules! debug {
+ ($($arg:tt)*) => {};
+}
diff --git a/vendor/clap_complete/src/shells/bash.rs b/vendor/clap_complete/src/shells/bash.rs
new file mode 100644
index 000000000..08bf1190c
--- /dev/null
+++ b/vendor/clap_complete/src/shells/bash.rs
@@ -0,0 +1,218 @@
+use std::{fmt::Write as _, io::Write};
+
+use clap::*;
+
+use crate::generator::{utils, Generator};
+
+/// Generate bash completion file
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Bash;
+
+impl Generator for Bash {
+ fn file_name(&self, name: &str) -> String {
+ format!("{}.bash", name)
+ }
+
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ let bin_name = cmd
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ w!(
+ buf,
+ format!(
+ "_{name}() {{
+ local i cur prev opts cmds
+ COMPREPLY=()
+ cur=\"${{COMP_WORDS[COMP_CWORD]}}\"
+ prev=\"${{COMP_WORDS[COMP_CWORD-1]}}\"
+ cmd=\"\"
+ opts=\"\"
+
+ for i in ${{COMP_WORDS[@]}}
+ do
+ case \"${{i}}\" in
+ \"$1\")
+ cmd=\"{cmd}\"
+ ;;{subcmds}
+ *)
+ ;;
+ esac
+ done
+
+ case \"${{cmd}}\" in
+ {cmd})
+ opts=\"{name_opts}\"
+ if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq 1 ]] ; then
+ COMPREPLY=( $(compgen -W \"${{opts}}\" -- \"${{cur}}\") )
+ return 0
+ fi
+ case \"${{prev}}\" in{name_opts_details}
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W \"${{opts}}\" -- \"${{cur}}\") )
+ return 0
+ ;;{subcmd_details}
+ esac
+}}
+
+complete -F _{name} -o bashdefault -o default {name}
+",
+ name = bin_name,
+ cmd = bin_name.replace('-', "__"),
+ name_opts = all_options_for_path(cmd, bin_name),
+ name_opts_details = option_details_for_path(cmd, bin_name),
+ subcmds = all_subcommands(cmd),
+ subcmd_details = subcommand_details(cmd)
+ )
+ .as_bytes()
+ );
+ }
+}
+
+fn all_subcommands(cmd: &Command) -> String {
+ debug!("all_subcommands");
+
+ let mut subcmds = vec![String::new()];
+ let mut scs = utils::all_subcommands(cmd)
+ .iter()
+ .map(|x| x.0.clone())
+ .collect::<Vec<_>>();
+
+ scs.sort();
+ scs.dedup();
+
+ subcmds.extend(scs.iter().map(|sc| {
+ format!(
+ "{name})
+ cmd+=\"__{fn_name}\"
+ ;;",
+ name = sc,
+ fn_name = sc.replace('-', "__")
+ )
+ }));
+
+ subcmds.join("\n ")
+}
+
+fn subcommand_details(cmd: &Command) -> String {
+ debug!("subcommand_details");
+
+ let mut subcmd_dets = vec![String::new()];
+ let mut scs = utils::all_subcommands(cmd)
+ .iter()
+ .map(|x| x.1.replace(' ', "__"))
+ .collect::<Vec<_>>();
+
+ scs.sort();
+
+ subcmd_dets.extend(scs.iter().map(|sc| {
+ format!(
+ "{subcmd})
+ opts=\"{sc_opts}\"
+ if [[ ${{cur}} == -* || ${{COMP_CWORD}} -eq {level} ]] ; then
+ COMPREPLY=( $(compgen -W \"${{opts}}\" -- \"${{cur}}\") )
+ return 0
+ fi
+ case \"${{prev}}\" in{opts_details}
+ *)
+ COMPREPLY=()
+ ;;
+ esac
+ COMPREPLY=( $(compgen -W \"${{opts}}\" -- \"${{cur}}\") )
+ return 0
+ ;;",
+ subcmd = sc.replace('-', "__"),
+ sc_opts = all_options_for_path(cmd, &*sc),
+ level = sc.split("__").map(|_| 1).sum::<u64>(),
+ opts_details = option_details_for_path(cmd, &*sc)
+ )
+ }));
+
+ subcmd_dets.join("\n ")
+}
+
+fn option_details_for_path(cmd: &Command, path: &str) -> String {
+ debug!("option_details_for_path: path={}", path);
+
+ let p = utils::find_subcommand_with_path(cmd, path.split("__").skip(1).collect());
+ let mut opts = vec![String::new()];
+
+ for o in p.get_opts() {
+ if let Some(longs) = o.get_long_and_visible_aliases() {
+ opts.extend(longs.iter().map(|long| {
+ format!(
+ "--{})
+ COMPREPLY=({})
+ return 0
+ ;;",
+ long,
+ vals_for(o)
+ )
+ }));
+ }
+
+ if let Some(shorts) = o.get_short_and_visible_aliases() {
+ opts.extend(shorts.iter().map(|short| {
+ format!(
+ "-{})
+ COMPREPLY=({})
+ return 0
+ ;;",
+ short,
+ vals_for(o)
+ )
+ }));
+ }
+ }
+
+ opts.join("\n ")
+}
+
+fn vals_for(o: &Arg) -> String {
+ debug!("vals_for: o={}", o.get_id());
+
+ if let Some(vals) = o.get_possible_values() {
+ format!(
+ "$(compgen -W \"{}\" -- \"${{cur}}\")",
+ vals.iter()
+ .filter(|pv| pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>()
+ .join(" ")
+ )
+ } else {
+ String::from("$(compgen -f \"${cur}\")")
+ }
+}
+
+fn all_options_for_path(cmd: &Command, path: &str) -> String {
+ debug!("all_options_for_path: path={}", path);
+
+ let p = utils::find_subcommand_with_path(cmd, path.split("__").skip(1).collect());
+
+ let mut opts = String::new();
+ for short in utils::shorts_and_visible_aliases(p) {
+ write!(&mut opts, "-{} ", short).unwrap();
+ }
+ for long in utils::longs_and_visible_aliases(p) {
+ write!(&mut opts, "--{} ", long).unwrap();
+ }
+ for pos in p.get_positionals() {
+ if let Some(vals) = pos.get_possible_values() {
+ for value in vals {
+ write!(&mut opts, "{} ", value.get_name()).unwrap();
+ }
+ } else {
+ write!(&mut opts, "{} ", pos).unwrap();
+ }
+ }
+ for (sc, _) in utils::subcommands(p) {
+ write!(&mut opts, "{} ", sc).unwrap();
+ }
+ opts.pop();
+
+ opts
+}
diff --git a/vendor/clap_complete/src/shells/elvish.rs b/vendor/clap_complete/src/shells/elvish.rs
new file mode 100644
index 000000000..959372087
--- /dev/null
+++ b/vendor/clap_complete/src/shells/elvish.rs
@@ -0,0 +1,142 @@
+use std::io::Write;
+
+use clap::*;
+
+use crate::generator::{utils, Generator};
+use crate::INTERNAL_ERROR_MSG;
+
+/// Generate elvish completion file
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Elvish;
+
+impl Generator for Elvish {
+ fn file_name(&self, name: &str) -> String {
+ format!("{}.elv", name)
+ }
+
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ let bin_name = cmd
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ let mut names = vec![];
+ let subcommands_cases = generate_inner(cmd, "", &mut names);
+
+ let result = format!(
+ r#"
+use builtin;
+use str;
+
+set edit:completion:arg-completer[{bin_name}] = {{|@words|
+ fn spaces {{|n|
+ builtin:repeat $n ' ' | str:join ''
+ }}
+ fn cand {{|text desc|
+ edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc
+ }}
+ var command = '{bin_name}'
+ for word $words[1..-1] {{
+ if (str:has-prefix $word '-') {{
+ break
+ }}
+ set command = $command';'$word
+ }}
+ var completions = [{subcommands_cases}
+ ]
+ $completions[$command]
+}}
+"#,
+ bin_name = bin_name,
+ subcommands_cases = subcommands_cases
+ );
+
+ w!(buf, result.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String {
+ string.replace('\'', "''")
+}
+
+fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
+ match help {
+ Some(help) => escape_string(help),
+ _ => data.to_string(),
+ }
+}
+
+fn generate_inner<'help>(
+ p: &Command<'help>,
+ previous_command_name: &str,
+ names: &mut Vec<&'help str>,
+) -> String {
+ debug!("generate_inner");
+
+ let command_name = if previous_command_name.is_empty() {
+ p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string()
+ } else {
+ format!("{};{}", previous_command_name, &p.get_name())
+ };
+
+ let mut completions = String::new();
+ let preamble = String::from("\n cand ");
+
+ for option in p.get_opts() {
+ if let Some(shorts) = option.get_short_and_visible_aliases() {
+ let tooltip = get_tooltip(option.get_help(), shorts[0]);
+ for short in shorts {
+ completions.push_str(&preamble);
+ completions.push_str(format!("-{} '{}'", short, tooltip).as_str());
+ }
+ }
+
+ if let Some(longs) = option.get_long_and_visible_aliases() {
+ let tooltip = get_tooltip(option.get_help(), longs[0]);
+ for long in longs {
+ completions.push_str(&preamble);
+ completions.push_str(format!("--{} '{}'", long, tooltip).as_str());
+ }
+ }
+ }
+
+ for flag in utils::flags(p) {
+ if let Some(shorts) = flag.get_short_and_visible_aliases() {
+ let tooltip = get_tooltip(flag.get_help(), shorts[0]);
+ for short in shorts {
+ completions.push_str(&preamble);
+ completions.push_str(format!("-{} '{}'", short, tooltip).as_str());
+ }
+ }
+
+ if let Some(longs) = flag.get_long_and_visible_aliases() {
+ let tooltip = get_tooltip(flag.get_help(), longs[0]);
+ for long in longs {
+ completions.push_str(&preamble);
+ completions.push_str(format!("--{} '{}'", long, tooltip).as_str());
+ }
+ }
+ }
+
+ for subcommand in p.get_subcommands() {
+ let data = &subcommand.get_name();
+ let tooltip = get_tooltip(subcommand.get_about(), data);
+
+ completions.push_str(&preamble);
+ completions.push_str(format!("{} '{}'", data, tooltip).as_str());
+ }
+
+ let mut subcommands_cases = format!(
+ r"
+ &'{}'= {{{}
+ }}",
+ &command_name, completions
+ );
+
+ for subcommand in p.get_subcommands() {
+ let subcommand_subcommands_cases = generate_inner(subcommand, &command_name, names);
+ subcommands_cases.push_str(&subcommand_subcommands_cases);
+ }
+
+ subcommands_cases
+}
diff --git a/vendor/clap_complete/src/shells/fish.rs b/vendor/clap_complete/src/shells/fish.rs
new file mode 100644
index 000000000..9b516084b
--- /dev/null
+++ b/vendor/clap_complete/src/shells/fish.rs
@@ -0,0 +1,192 @@
+use std::io::Write;
+
+use clap::*;
+
+use crate::generator::{utils, Generator};
+
+/// Generate fish completion file
+///
+/// Note: The fish generator currently only supports named options (-o/--option), not positional arguments.
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Fish;
+
+impl Generator for Fish {
+ fn file_name(&self, name: &str) -> String {
+ format!("{}.fish", name)
+ }
+
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ let bin_name = cmd
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ let mut buffer = String::new();
+ gen_fish_inner(bin_name, &[], cmd, &mut buffer);
+ w!(buf, buffer.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String {
+ string.replace('\\', "\\\\").replace('\'', "\\'")
+}
+
+fn gen_fish_inner(
+ root_command: &str,
+ parent_commands: &[&str],
+ cmd: &Command,
+ buffer: &mut String,
+) {
+ debug!("gen_fish_inner");
+ // example :
+ //
+ // complete
+ // -c {command}
+ // -d "{description}"
+ // -s {short}
+ // -l {long}
+ // -a "{possible_arguments}"
+ // -r # if require parameter
+ // -f # don't use file completion
+ // -n "__fish_use_subcommand" # complete for command "myprog"
+ // -n "__fish_seen_subcommand_from subcmd1" # complete for command "myprog subcmd1"
+
+ let mut basic_template = format!("complete -c {}", root_command);
+
+ if parent_commands.is_empty() {
+ if cmd.has_subcommands() {
+ basic_template.push_str(" -n \"__fish_use_subcommand\"");
+ }
+ } else {
+ basic_template.push_str(
+ format!(
+ " -n \"{}\"",
+ parent_commands
+ .iter()
+ .map(|command| format!("__fish_seen_subcommand_from {}", command))
+ .chain(
+ cmd.get_subcommands()
+ .map(|command| format!("not __fish_seen_subcommand_from {}", command))
+ )
+ .collect::<Vec<_>>()
+ .join("; and ")
+ )
+ .as_str(),
+ );
+ }
+
+ debug!("gen_fish_inner: parent_commands={:?}", parent_commands);
+
+ for option in cmd.get_opts() {
+ let mut template = basic_template.clone();
+
+ if let Some(shorts) = option.get_short_and_visible_aliases() {
+ for short in shorts {
+ template.push_str(format!(" -s {}", short).as_str());
+ }
+ }
+
+ if let Some(longs) = option.get_long_and_visible_aliases() {
+ for long in longs {
+ template.push_str(format!(" -l {}", escape_string(long)).as_str());
+ }
+ }
+
+ if let Some(data) = option.get_help() {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ }
+
+ template.push_str(value_completion(option).as_str());
+
+ buffer.push_str(template.as_str());
+ buffer.push('\n');
+ }
+
+ for flag in utils::flags(cmd) {
+ let mut template = basic_template.clone();
+
+ if let Some(shorts) = flag.get_short_and_visible_aliases() {
+ for short in shorts {
+ template.push_str(format!(" -s {}", short).as_str());
+ }
+ }
+
+ if let Some(longs) = flag.get_long_and_visible_aliases() {
+ for long in longs {
+ template.push_str(format!(" -l {}", escape_string(long)).as_str());
+ }
+ }
+
+ if let Some(data) = flag.get_help() {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str());
+ }
+
+ buffer.push_str(template.as_str());
+ buffer.push('\n');
+ }
+
+ for subcommand in cmd.get_subcommands() {
+ let mut template = basic_template.clone();
+
+ template.push_str(" -f");
+ template.push_str(format!(" -a \"{}\"", &subcommand.get_name()).as_str());
+
+ if let Some(data) = subcommand.get_about() {
+ template.push_str(format!(" -d '{}'", escape_string(data)).as_str())
+ }
+
+ buffer.push_str(template.as_str());
+ buffer.push('\n');
+ }
+
+ // generate options of subcommands
+ for subcommand in cmd.get_subcommands() {
+ let mut parent_commands: Vec<_> = parent_commands.into();
+ parent_commands.push(subcommand.get_name());
+ gen_fish_inner(root_command, &parent_commands, subcommand, buffer);
+ }
+}
+
+fn value_completion(option: &Arg) -> String {
+ if !option.is_takes_value_set() {
+ return "".to_string();
+ }
+
+ if let Some(data) = option.get_possible_values() {
+ // We return the possible values with their own empty description e.g. {a\t,b\t}
+ // this makes sure that a and b don't get the description of the option or argument
+ format!(
+ " -r -f -a \"{{{}}}\"",
+ data.iter()
+ .filter_map(|value| if value.is_hide_set() {
+ None
+ } else {
+ Some(format!(
+ "{}\t{}",
+ escape_string(value.get_name()).as_str(),
+ escape_string(value.get_help().unwrap_or_default()).as_str()
+ ))
+ })
+ .collect::<Vec<_>>()
+ .join(",")
+ )
+ } else {
+ // NB! If you change this, please also update the table in `ValueHint` documentation.
+ match option.get_value_hint() {
+ ValueHint::Unknown => " -r",
+ // fish has no built-in support to distinguish these
+ ValueHint::AnyPath | ValueHint::FilePath | ValueHint::ExecutablePath => " -r -F",
+ ValueHint::DirPath => " -r -f -a \"(__fish_complete_directories)\"",
+ // It seems fish has no built-in support for completing command + arguments as
+ // single string (CommandString). Complete just the command name.
+ ValueHint::CommandString | ValueHint::CommandName => {
+ " -r -f -a \"(__fish_complete_command)\""
+ }
+ ValueHint::Username => " -r -f -a \"(__fish_complete_users)\"",
+ ValueHint::Hostname => " -r -f -a \"(__fish_print_hostnames)\"",
+ // Disable completion for others
+ _ => " -r -f",
+ }
+ .to_string()
+ }
+}
diff --git a/vendor/clap_complete/src/shells/mod.rs b/vendor/clap_complete/src/shells/mod.rs
new file mode 100644
index 000000000..a08aa878b
--- /dev/null
+++ b/vendor/clap_complete/src/shells/mod.rs
@@ -0,0 +1,15 @@
+//! Shell-specific generators
+
+mod bash;
+mod elvish;
+mod fish;
+mod powershell;
+mod shell;
+mod zsh;
+
+pub use bash::Bash;
+pub use elvish::Elvish;
+pub use fish::Fish;
+pub use powershell::PowerShell;
+pub use shell::Shell;
+pub use zsh::Zsh;
diff --git a/vendor/clap_complete/src/shells/powershell.rs b/vendor/clap_complete/src/shells/powershell.rs
new file mode 100644
index 000000000..d35e61c7d
--- /dev/null
+++ b/vendor/clap_complete/src/shells/powershell.rs
@@ -0,0 +1,178 @@
+use std::io::Write;
+
+use clap::*;
+
+use crate::generator::{utils, Generator};
+use crate::INTERNAL_ERROR_MSG;
+
+/// Generate powershell completion file
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct PowerShell;
+
+impl Generator for PowerShell {
+ fn file_name(&self, name: &str) -> String {
+ format!("_{}.ps1", name)
+ }
+
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ let bin_name = cmd
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ let mut names = vec![];
+ let subcommands_cases = generate_inner(cmd, "", &mut names);
+
+ let result = format!(
+ r#"
+using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+
+Register-ArgumentCompleter -Native -CommandName '{bin_name}' -ScriptBlock {{
+ param($wordToComplete, $commandAst, $cursorPosition)
+
+ $commandElements = $commandAst.CommandElements
+ $command = @(
+ '{bin_name}'
+ for ($i = 1; $i -lt $commandElements.Count; $i++) {{
+ $element = $commandElements[$i]
+ if ($element -isnot [StringConstantExpressionAst] -or
+ $element.StringConstantType -ne [StringConstantType]::BareWord -or
+ $element.Value.StartsWith('-') -or
+ $element.Value -eq $wordToComplete) {{
+ break
+ }}
+ $element.Value
+ }}) -join ';'
+
+ $completions = @(switch ($command) {{{subcommands_cases}
+ }})
+
+ $completions.Where{{ $_.CompletionText -like "$wordToComplete*" }} |
+ Sort-Object -Property ListItemText
+}}
+"#,
+ bin_name = bin_name,
+ subcommands_cases = subcommands_cases
+ );
+
+ w!(buf, result.as_bytes());
+ }
+}
+
+// Escape string inside single quotes
+fn escape_string(string: &str) -> String {
+ string.replace('\'', "''")
+}
+
+fn get_tooltip<T: ToString>(help: Option<&str>, data: T) -> String {
+ match help {
+ Some(help) => escape_string(help),
+ _ => data.to_string(),
+ }
+}
+
+fn generate_inner<'help>(
+ p: &Command<'help>,
+ previous_command_name: &str,
+ names: &mut Vec<&'help str>,
+) -> String {
+ debug!("generate_inner");
+
+ let command_name = if previous_command_name.is_empty() {
+ p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string()
+ } else {
+ format!("{};{}", previous_command_name, &p.get_name())
+ };
+
+ let mut completions = String::new();
+ let preamble = String::from("\n [CompletionResult]::new(");
+
+ for option in p.get_opts() {
+ if let Some(shorts) = option.get_short_and_visible_aliases() {
+ let tooltip = get_tooltip(option.get_help(), shorts[0]);
+ for short in shorts {
+ completions.push_str(&preamble);
+ completions.push_str(
+ format!(
+ "'-{}', '{}', {}, '{}')",
+ short, short, "[CompletionResultType]::ParameterName", tooltip
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ if let Some(longs) = option.get_long_and_visible_aliases() {
+ let tooltip = get_tooltip(option.get_help(), longs[0]);
+ for long in longs {
+ completions.push_str(&preamble);
+ completions.push_str(
+ format!(
+ "'--{}', '{}', {}, '{}')",
+ long, long, "[CompletionResultType]::ParameterName", tooltip
+ )
+ .as_str(),
+ );
+ }
+ }
+ }
+
+ for flag in utils::flags(p) {
+ if let Some(shorts) = flag.get_short_and_visible_aliases() {
+ let tooltip = get_tooltip(flag.get_help(), shorts[0]);
+ for short in shorts {
+ completions.push_str(&preamble);
+ completions.push_str(
+ format!(
+ "'-{}', '{}', {}, '{}')",
+ short, short, "[CompletionResultType]::ParameterName", tooltip
+ )
+ .as_str(),
+ );
+ }
+ }
+
+ if let Some(longs) = flag.get_long_and_visible_aliases() {
+ let tooltip = get_tooltip(flag.get_help(), longs[0]);
+ for long in longs {
+ completions.push_str(&preamble);
+ completions.push_str(
+ format!(
+ "'--{}', '{}', {}, '{}')",
+ long, long, "[CompletionResultType]::ParameterName", tooltip
+ )
+ .as_str(),
+ );
+ }
+ }
+ }
+
+ for subcommand in p.get_subcommands() {
+ let data = &subcommand.get_name();
+ let tooltip = get_tooltip(subcommand.get_about(), data);
+
+ completions.push_str(&preamble);
+ completions.push_str(
+ format!(
+ "'{}', '{}', {}, '{}')",
+ data, data, "[CompletionResultType]::ParameterValue", tooltip
+ )
+ .as_str(),
+ );
+ }
+
+ let mut subcommands_cases = format!(
+ r"
+ '{}' {{{}
+ break
+ }}",
+ &command_name, completions
+ );
+
+ for subcommand in p.get_subcommands() {
+ let subcommand_subcommands_cases = generate_inner(subcommand, &command_name, names);
+ subcommands_cases.push_str(&subcommand_subcommands_cases);
+ }
+
+ subcommands_cases
+}
diff --git a/vendor/clap_complete/src/shells/shell.rs b/vendor/clap_complete/src/shells/shell.rs
new file mode 100644
index 000000000..63063bb7c
--- /dev/null
+++ b/vendor/clap_complete/src/shells/shell.rs
@@ -0,0 +1,99 @@
+use std::fmt::Display;
+use std::str::FromStr;
+
+use clap::{ArgEnum, PossibleValue};
+
+use crate::shells;
+use crate::Generator;
+
+/// Shell with auto-generated completion script available.
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
+#[non_exhaustive]
+pub enum Shell {
+ /// Bourne Again SHell (bash)
+ Bash,
+ /// Elvish shell
+ Elvish,
+ /// Friendly Interactive SHell (fish)
+ Fish,
+ /// PowerShell
+ PowerShell,
+ /// Z SHell (zsh)
+ Zsh,
+}
+
+impl Shell {
+ /// Report all `possible_values`
+ pub fn possible_values() -> impl Iterator<Item = PossibleValue<'static>> {
+ Shell::value_variants()
+ .iter()
+ .filter_map(ArgEnum::to_possible_value)
+ }
+}
+
+impl Display for Shell {
+ 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 FromStr for Shell {
+ 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))
+ }
+}
+
+// Hand-rolled so it can work even when `derive` feature is disabled
+impl ArgEnum for Shell {
+ fn value_variants<'a>() -> &'a [Self] {
+ &[
+ Shell::Bash,
+ Shell::Elvish,
+ Shell::Fish,
+ Shell::PowerShell,
+ Shell::Zsh,
+ ]
+ }
+
+ fn to_possible_value<'a>(&self) -> Option<PossibleValue<'a>> {
+ Some(match self {
+ Shell::Bash => PossibleValue::new("bash"),
+ Shell::Elvish => PossibleValue::new("elvish"),
+ Shell::Fish => PossibleValue::new("fish"),
+ Shell::PowerShell => PossibleValue::new("powershell"),
+ Shell::Zsh => PossibleValue::new("zsh"),
+ })
+ }
+}
+
+impl Generator for Shell {
+ fn file_name(&self, name: &str) -> String {
+ match self {
+ Shell::Bash => shells::Bash.file_name(name),
+ Shell::Elvish => shells::Elvish.file_name(name),
+ Shell::Fish => shells::Fish.file_name(name),
+ Shell::PowerShell => shells::PowerShell.file_name(name),
+ Shell::Zsh => shells::Zsh.file_name(name),
+ }
+ }
+
+ fn generate(&self, cmd: &clap::Command, buf: &mut dyn std::io::Write) {
+ match self {
+ Shell::Bash => shells::Bash.generate(cmd, buf),
+ Shell::Elvish => shells::Elvish.generate(cmd, buf),
+ Shell::Fish => shells::Fish.generate(cmd, buf),
+ Shell::PowerShell => shells::PowerShell.generate(cmd, buf),
+ Shell::Zsh => shells::Zsh.generate(cmd, buf),
+ }
+ }
+}
diff --git a/vendor/clap_complete/src/shells/zsh.rs b/vendor/clap_complete/src/shells/zsh.rs
new file mode 100644
index 000000000..2b64739ce
--- /dev/null
+++ b/vendor/clap_complete/src/shells/zsh.rs
@@ -0,0 +1,663 @@
+use std::io::Write;
+
+use clap::*;
+
+use crate::generator::{utils, Generator};
+use crate::INTERNAL_ERROR_MSG;
+
+/// Generate zsh completion file
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct Zsh;
+
+impl Generator for Zsh {
+ fn file_name(&self, name: &str) -> String {
+ format!("_{}", name)
+ }
+
+ fn generate(&self, cmd: &Command, buf: &mut dyn Write) {
+ let bin_name = cmd
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ w!(
+ buf,
+ format!(
+ "#compdef {name}
+
+autoload -U is-at-least
+
+_{name}() {{
+ typeset -A opt_args
+ typeset -a _arguments_options
+ local ret=1
+
+ if is-at-least 5.2; then
+ _arguments_options=(-s -S -C)
+ else
+ _arguments_options=(-s -C)
+ fi
+
+ local context curcontext=\"$curcontext\" state line
+ {initial_args}{subcommands}
+}}
+
+{subcommand_details}
+
+_{name} \"$@\"
+",
+ name = bin_name,
+ initial_args = get_args_of(cmd, None),
+ subcommands = get_subcommands_of(cmd),
+ subcommand_details = subcommand_details(cmd)
+ )
+ .as_bytes()
+ );
+ }
+}
+
+// Displays the commands of a subcommand
+// (( $+functions[_[bin_name_underscore]_commands] )) ||
+// _[bin_name_underscore]_commands() {
+// local commands; commands=(
+// '[arg_name]:[arg_help]'
+// )
+// _describe -t commands '[bin_name] commands' commands "$@"
+//
+// Where the following variables are present:
+// [bin_name_underscore]: The full space delineated bin_name, where spaces have been replaced by
+// underscore characters
+// [arg_name]: The name of the subcommand
+// [arg_help]: The help message of the subcommand
+// [bin_name]: The full space delineated bin_name
+//
+// Here's a snippet from rustup:
+//
+// (( $+functions[_rustup_commands] )) ||
+// _rustup_commands() {
+// local commands; commands=(
+// 'show:Show the active and installed toolchains'
+// 'update:Update Rust toolchains'
+// # ... snip for brevity
+// 'help:Print this message or the help of the given subcommand(s)'
+// )
+// _describe -t commands 'rustup commands' commands "$@"
+//
+fn subcommand_details(p: &Command) -> String {
+ debug!("subcommand_details");
+
+ let bin_name = p
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ let mut ret = vec![];
+
+ // First we do ourself
+ let parent_text = format!(
+ "\
+(( $+functions[_{bin_name_underscore}_commands] )) ||
+_{bin_name_underscore}_commands() {{
+ local commands; commands=({subcommands_and_args})
+ _describe -t commands '{bin_name} commands' commands \"$@\"
+}}",
+ bin_name_underscore = bin_name.replace(' ', "__"),
+ bin_name = bin_name,
+ subcommands_and_args = subcommands_of(p)
+ );
+ ret.push(parent_text);
+
+ // Next we start looping through all the children, grandchildren, etc.
+ let mut all_subcommands = utils::all_subcommands(p);
+
+ all_subcommands.sort();
+ all_subcommands.dedup();
+
+ for &(_, ref bin_name) in &all_subcommands {
+ debug!("subcommand_details:iter: bin_name={}", bin_name);
+
+ ret.push(format!(
+ "\
+(( $+functions[_{bin_name_underscore}_commands] )) ||
+_{bin_name_underscore}_commands() {{
+ local commands; commands=({subcommands_and_args})
+ _describe -t commands '{bin_name} commands' commands \"$@\"
+}}",
+ bin_name_underscore = bin_name.replace(' ', "__"),
+ bin_name = bin_name,
+ subcommands_and_args =
+ subcommands_of(parser_of(p, bin_name).expect(INTERNAL_ERROR_MSG))
+ ));
+ }
+
+ ret.join("\n")
+}
+
+// Generates subcommand completions in form of
+//
+// '[arg_name]:[arg_help]'
+//
+// Where:
+// [arg_name]: the subcommand's name
+// [arg_help]: the help message of the subcommand
+//
+// A snippet from rustup:
+// 'show:Show the active and installed toolchains'
+// 'update:Update Rust toolchains'
+fn subcommands_of(p: &Command) -> String {
+ debug!("subcommands_of");
+
+ let mut segments = vec![];
+
+ fn add_subcommands(subcommand: &Command, name: &str, ret: &mut Vec<String>) {
+ debug!("add_subcommands");
+
+ let text = format!(
+ "'{name}:{help}' \\",
+ name = name,
+ help = escape_help(subcommand.get_about().unwrap_or(""))
+ );
+
+ if !text.is_empty() {
+ ret.push(text);
+ }
+ }
+
+ // The subcommands
+ for command in p.get_subcommands() {
+ debug!("subcommands_of:iter: subcommand={}", command.get_name());
+
+ add_subcommands(command, command.get_name(), &mut segments);
+
+ for alias in command.get_visible_aliases() {
+ add_subcommands(command, alias, &mut segments);
+ }
+ }
+
+ // Surround the text with newlines for proper formatting.
+ // We need this to prevent weirdly formatted `command=(\n \n)` sections.
+ // When there are no (sub-)commands.
+ if !segments.is_empty() {
+ segments.insert(0, "".to_string());
+ segments.push(" ".to_string());
+ }
+
+ segments.join("\n")
+}
+
+// Get's the subcommand section of a completion file
+// This looks roughly like:
+//
+// case $state in
+// ([bin_name]_args)
+// curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
+// case $line[1] in
+//
+// ([name])
+// _arguments -C -s -S \
+// [subcommand_args]
+// && ret=0
+//
+// [RECURSIVE_CALLS]
+//
+// ;;",
+//
+// [repeat]
+//
+// esac
+// ;;
+// esac",
+//
+// Where the following variables are present:
+// [name] = The subcommand name in the form of "install" for "rustup toolchain install"
+// [bin_name] = The full space delineated bin_name such as "rustup toolchain install"
+// [name_hyphen] = The full space delineated bin_name, but replace spaces with hyphens
+// [repeat] = From the same recursive calls, but for all subcommands
+// [subcommand_args] = The same as zsh::get_args_of
+fn get_subcommands_of(parent: &Command) -> String {
+ debug!(
+ "get_subcommands_of: Has subcommands...{:?}",
+ parent.has_subcommands()
+ );
+
+ if !parent.has_subcommands() {
+ return String::new();
+ }
+
+ let subcommand_names = utils::subcommands(parent);
+ let mut all_subcommands = vec![];
+
+ for &(ref name, ref bin_name) in &subcommand_names {
+ debug!(
+ "get_subcommands_of:iter: parent={}, name={}, bin_name={}",
+ parent.get_name(),
+ name,
+ bin_name,
+ );
+ let mut segments = vec![format!("({})", name)];
+ let subcommand_args = get_args_of(
+ parser_of(parent, &*bin_name).expect(INTERNAL_ERROR_MSG),
+ Some(parent),
+ );
+
+ if !subcommand_args.is_empty() {
+ segments.push(subcommand_args);
+ }
+
+ // Get the help text of all child subcommands.
+ let children = get_subcommands_of(parser_of(parent, &*bin_name).expect(INTERNAL_ERROR_MSG));
+
+ if !children.is_empty() {
+ segments.push(children);
+ }
+
+ segments.push(String::from(";;"));
+ all_subcommands.push(segments.join("\n"));
+ }
+
+ let parent_bin_name = parent
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+
+ format!(
+ "
+ case $state in
+ ({name})
+ words=($line[{pos}] \"${{words[@]}}\")
+ (( CURRENT += 1 ))
+ curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$line[{pos}]:\"
+ case $line[{pos}] in
+ {subcommands}
+ esac
+ ;;
+esac",
+ name = parent.get_name(),
+ name_hyphen = parent_bin_name.replace(' ', "-"),
+ subcommands = all_subcommands.join("\n"),
+ pos = parent.get_positionals().count() + 1
+ )
+}
+
+// Get the Command for a given subcommand tree.
+//
+// Given the bin_name "a b c" and the Command for "a" this returns the "c" Command.
+// Given the bin_name "a b c" and the Command for "b" this returns the "c" Command.
+fn parser_of<'help, 'cmd>(
+ parent: &'cmd Command<'help>,
+ bin_name: &str,
+) -> Option<&'cmd Command<'help>> {
+ debug!("parser_of: p={}, bin_name={}", parent.get_name(), bin_name);
+
+ if bin_name == parent.get_bin_name().unwrap_or(&String::new()) {
+ return Some(parent);
+ }
+
+ for subcommand in parent.get_subcommands() {
+ if let Some(ret) = parser_of(subcommand, bin_name) {
+ return Some(ret);
+ }
+ }
+
+ None
+}
+
+// Writes out the args section, which ends up being the flags, opts and positionals, and a jump to
+// another ZSH function if there are subcommands.
+// The structure works like this:
+// ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
+// ^-- list '-v -h' ^--'*' ^--'+' ^-- list 'one two three'
+//
+// An example from the rustup command:
+//
+// _arguments -C -s -S \
+// '(-h --help --verbose)-v[Enable verbose output]' \
+// '(-V -v --version --verbose --help)-h[Print help information]' \
+// # ... snip for brevity
+// ':: :_rustup_commands' \ # <-- displays subcommands
+// '*::: :->rustup' \ # <-- displays subcommand args and child subcommands
+// && ret=0
+//
+// The args used for _arguments are as follows:
+// -C: modify the $context internal variable
+// -s: Allow stacking of short args (i.e. -a -b -c => -abc)
+// -S: Do not complete anything after '--' and treat those as argument values
+fn get_args_of(parent: &Command, p_global: Option<&Command>) -> String {
+ debug!("get_args_of");
+
+ let mut segments = vec![String::from("_arguments \"${_arguments_options[@]}\" \\")];
+ let opts = write_opts_of(parent, p_global);
+ let flags = write_flags_of(parent, p_global);
+ let positionals = write_positionals_of(parent);
+
+ if !opts.is_empty() {
+ segments.push(opts);
+ }
+
+ if !flags.is_empty() {
+ segments.push(flags);
+ }
+
+ if !positionals.is_empty() {
+ segments.push(positionals);
+ }
+
+ if parent.has_subcommands() {
+ let parent_bin_name = parent
+ .get_bin_name()
+ .expect("crate::generate should have set the bin_name");
+ let subcommand_bin_name = format!(
+ "\":: :_{name}_commands\" \\",
+ name = parent_bin_name.replace(' ', "__")
+ );
+ segments.push(subcommand_bin_name);
+
+ let subcommand_text = format!("\"*::: :->{name}\" \\", name = parent.get_name());
+ segments.push(subcommand_text);
+ };
+
+ segments.push(String::from("&& ret=0"));
+ segments.join("\n")
+}
+
+// Uses either `possible_vals` or `value_hint` to give hints about possible argument values
+fn value_completion(arg: &Arg) -> Option<String> {
+ if let Some(values) = &arg.get_possible_values() {
+ if values
+ .iter()
+ .any(|value| !value.is_hide_set() && value.get_help().is_some())
+ {
+ Some(format!(
+ "(({}))",
+ values
+ .iter()
+ .filter_map(|value| {
+ if value.is_hide_set() {
+ None
+ } else {
+ Some(format!(
+ r#"{name}\:"{tooltip}""#,
+ name = escape_value(value.get_name()),
+ tooltip = value.get_help().map(escape_help).unwrap_or_default()
+ ))
+ }
+ })
+ .collect::<Vec<_>>()
+ .join("\n")
+ ))
+ } else {
+ Some(format!(
+ "({})",
+ values
+ .iter()
+ .filter(|pv| !pv.is_hide_set())
+ .map(PossibleValue::get_name)
+ .collect::<Vec<_>>()
+ .join(" ")
+ ))
+ }
+ } else {
+ // NB! If you change this, please also update the table in `ValueHint` documentation.
+ Some(
+ match arg.get_value_hint() {
+ ValueHint::Unknown => {
+ return None;
+ }
+ ValueHint::Other => "( )",
+ ValueHint::AnyPath => "_files",
+ ValueHint::FilePath => "_files",
+ ValueHint::DirPath => "_files -/",
+ ValueHint::ExecutablePath => "_absolute_command_paths",
+ ValueHint::CommandName => "_command_names -e",
+ ValueHint::CommandString => "_cmdstring",
+ ValueHint::CommandWithArguments => "_cmdambivalent",
+ ValueHint::Username => "_users",
+ ValueHint::Hostname => "_hosts",
+ ValueHint::Url => "_urls",
+ ValueHint::EmailAddress => "_email_addresses",
+ _ => {
+ return None;
+ }
+ }
+ .to_string(),
+ )
+ }
+}
+
+/// Escape help string inside single quotes and brackets
+fn escape_help(string: &str) -> String {
+ string
+ .replace('\\', "\\\\")
+ .replace('\'', "'\\''")
+ .replace('[', "\\[")
+ .replace(']', "\\]")
+}
+
+/// Escape value string inside single quotes and parentheses
+fn escape_value(string: &str) -> String {
+ string
+ .replace('\\', "\\\\")
+ .replace('\'', "'\\''")
+ .replace('(', "\\(")
+ .replace(')', "\\)")
+ .replace(' ', "\\ ")
+}
+
+fn write_opts_of(p: &Command, p_global: Option<&Command>) -> String {
+ debug!("write_opts_of");
+
+ let mut ret = vec![];
+
+ for o in p.get_opts() {
+ debug!("write_opts_of:iter: o={}", o.get_id());
+
+ let help = o.get_help().map_or(String::new(), escape_help);
+ let conflicts = arg_conflicts(p, o, p_global);
+
+ let multiple = if o.is_multiple_occurrences_set() {
+ "*"
+ } else {
+ ""
+ };
+
+ let vn = match o.get_value_names() {
+ None => " ".to_string(),
+ Some(val) => val[0].to_string(),
+ };
+ let vc = match value_completion(o) {
+ Some(val) => format!(":{}:{}", vn, val),
+ None => format!(":{}: ", vn),
+ };
+ let vc = match o.get_num_vals() {
+ Some(num_vals) => vc.repeat(num_vals),
+ None => vc,
+ };
+
+ if let Some(shorts) = o.get_short_and_visible_aliases() {
+ for short in shorts {
+ let s = format!(
+ "'{conflicts}{multiple}-{arg}+[{help}]{value_completion}' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = short,
+ value_completion = vc,
+ help = help
+ );
+
+ debug!("write_opts_of:iter: Wrote...{}", &*s);
+ ret.push(s);
+ }
+ }
+ if let Some(longs) = o.get_long_and_visible_aliases() {
+ for long in longs {
+ let l = format!(
+ "'{conflicts}{multiple}--{arg}=[{help}]{value_completion}' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = long,
+ value_completion = vc,
+ help = help
+ );
+
+ debug!("write_opts_of:iter: Wrote...{}", &*l);
+ ret.push(l);
+ }
+ }
+ }
+
+ ret.join("\n")
+}
+
+fn arg_conflicts(cmd: &Command, arg: &Arg, app_global: Option<&Command>) -> String {
+ fn push_conflicts(conflicts: &[&Arg], res: &mut Vec<String>) {
+ for conflict in conflicts {
+ if let Some(s) = conflict.get_short() {
+ res.push(format!("-{}", s));
+ }
+
+ if let Some(l) = conflict.get_long() {
+ res.push(format!("--{}", l));
+ }
+ }
+ }
+
+ let mut res = vec![];
+ match (app_global, arg.is_global_set()) {
+ (Some(x), true) => {
+ let conflicts = x.get_arg_conflicts_with(arg);
+
+ if conflicts.is_empty() {
+ return String::new();
+ }
+
+ push_conflicts(&conflicts, &mut res);
+ }
+ (_, _) => {
+ let conflicts = cmd.get_arg_conflicts_with(arg);
+
+ if conflicts.is_empty() {
+ return String::new();
+ }
+
+ push_conflicts(&conflicts, &mut res);
+ }
+ };
+
+ format!("({})", res.join(" "))
+}
+
+fn write_flags_of(p: &Command, p_global: Option<&Command>) -> String {
+ debug!("write_flags_of;");
+
+ let mut ret = vec![];
+
+ for f in utils::flags(p) {
+ debug!("write_flags_of:iter: f={}", f.get_id());
+
+ let help = f.get_help().map_or(String::new(), escape_help);
+ let conflicts = arg_conflicts(p, &f, p_global);
+
+ let multiple = if f.is_multiple_occurrences_set() {
+ "*"
+ } else {
+ ""
+ };
+
+ if let Some(short) = f.get_short() {
+ let s = format!(
+ "'{conflicts}{multiple}-{arg}[{help}]' \\",
+ multiple = multiple,
+ conflicts = conflicts,
+ arg = short,
+ help = help
+ );
+
+ debug!("write_flags_of:iter: Wrote...{}", &*s);
+
+ ret.push(s);
+
+ if let Some(short_aliases) = f.get_visible_short_aliases() {
+ for alias in short_aliases {
+ let s = format!(
+ "'{conflicts}{multiple}-{arg}[{help}]' \\",
+ multiple = multiple,
+ conflicts = conflicts,
+ arg = alias,
+ help = help
+ );
+
+ debug!("write_flags_of:iter: Wrote...{}", &*s);
+
+ ret.push(s);
+ }
+ }
+ }
+
+ if let Some(long) = f.get_long() {
+ let l = format!(
+ "'{conflicts}{multiple}--{arg}[{help}]' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = long,
+ help = help
+ );
+
+ debug!("write_flags_of:iter: Wrote...{}", &*l);
+
+ ret.push(l);
+
+ if let Some(aliases) = f.get_visible_aliases() {
+ for alias in aliases {
+ let l = format!(
+ "'{conflicts}{multiple}--{arg}[{help}]' \\",
+ conflicts = conflicts,
+ multiple = multiple,
+ arg = alias,
+ help = help
+ );
+
+ debug!("write_flags_of:iter: Wrote...{}", &*l);
+
+ ret.push(l);
+ }
+ }
+ }
+ }
+
+ ret.join("\n")
+}
+
+fn write_positionals_of(p: &Command) -> String {
+ debug!("write_positionals_of;");
+
+ let mut ret = vec![];
+
+ for arg in p.get_positionals() {
+ debug!("write_positionals_of:iter: arg={}", arg.get_id());
+
+ let cardinality = if arg.is_multiple_values_set() || arg.is_multiple_occurrences_set() {
+ "*:"
+ } else if !arg.is_required_set() {
+ ":"
+ } else {
+ ""
+ };
+
+ let a = format!(
+ "'{cardinality}:{name}{help}:{value_completion}' \\",
+ cardinality = cardinality,
+ name = arg.get_id(),
+ help = arg
+ .get_help()
+ .map_or("".to_owned(), |v| " -- ".to_owned() + v)
+ .replace('[', "\\[")
+ .replace(']', "\\]")
+ .replace('\'', "'\\''")
+ .replace(':', "\\:"),
+ value_completion = value_completion(arg).unwrap_or_else(|| "".to_string())
+ );
+
+ debug!("write_positionals_of:iter: Wrote...{}", a);
+
+ ret.push(a);
+ }
+
+ ret.join("\n")
+}