Skip to content

Commit

Permalink
Refactor clap_generate
Browse files Browse the repository at this point in the history
  • Loading branch information
pksunkara committed Feb 5, 2020
1 parent 509ac33 commit 3b8527f
Show file tree
Hide file tree
Showing 19 changed files with 2,619 additions and 18 deletions.
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ features = ["doc"]
[workspace]
members = [
"clap_derive",
"clap_generate",
]
default-members = [
".", "clap_derive",
".",
"clap_derive",
"clap_generate",
]
1 change: 1 addition & 0 deletions clap_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ proc-macro-error = "0.4.3"
clap = { path = "../", version = "3.0.0-beta.1" }
trybuild = "1.0.5"
rustversion = "1"
version-sync = "0.8"

[features]
default = []
Expand Down
7 changes: 1 addition & 6 deletions clap_derive/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
# Work in Progress

This crate is currently a work in progress and not meant to be used. Please use [`structopt`](https://github.com/TeXitoi/structopt)
while this crate is being built.

# clap_derive[![Build status](https://travis-ci.org/clap-rs/clap_derive.svg?branch=master)](https://travis-ci.org/clap-rs/clap_derive) [![](https://img.shields.io/crates/v/clap_derive.svg)](https://crates.io/crates/clap_derive) [![](https://docs.rs/clap_derive/badge.svg)](https://docs.rs/clap_derive)
# clap_derive

Parse command line argument by defining a struct. It combines [structopt](https://github.com/TeXitoi/structopt) and [clap](https://crates.io/crates/clap) into a single experience. This crate is used by clap, and not meant to be used directly by
consumers.
Expand Down
49 changes: 49 additions & 0 deletions clap_generate/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
[package]
name = "clap_generate"
version = "3.0.0-beta.1"
edition = "2018"
authors = [
"Kevin K. <[email protected]>"
]
include = [
"src/**/*",
"Cargo.toml",
"README.md"
]
description = "A generator library used with clap for shell completion scripts, manpage, etc."
repository = "https://github.com/clap-rs/clap/tree/master/clap_generate"
documentation = "https://docs.rs/clap_generate"
homepage = "https://clap.rs/"
keywords = [
"clap",
"cli",
"generate",
"completion",
"manpage",
"parse"
]
categories = ["command-line-interface"]
license = "MIT OR Apache-2.0"
readme = "README.md"

[badges]
is-it-maintained-issue-resolution = { repository = "clap-rs/clap" }
is-it-maintained-open-issues = { repository = "clap-rs/clap" }
maintenance = {status = "actively-developed"}

[dependencies]
clap = { path = "../", version = "3.0.0-beta.1" }

[dev-dependencies]
regex = "1.0"
version-sync = "0.8"

[features]
default = []
unstable = ["clap/unstable"]
nightly = ["clap/nightly"]
debug = ["clap/debug"]
doc = []

[package.metadata.docs.rs]
features = ["doc"]
1 change: 1 addition & 0 deletions clap_generate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# clap_generate
215 changes: 215 additions & 0 deletions clap_generate/src/generators/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
mod shells;

// Std
use std::io::Write;

// Internal
use clap::*;

pub use shells::*;

/// 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.
///
/// # Examples
///
/// ```
/// # use std::io::Write;
/// # use clap::App;
/// use clap_generate::Generator;
///
/// pub struct Fish;
///
/// impl Generator for Fish {
/// # fn generate<W: Write>(app: &app, buf: &mut W) {}
/// fn file_name(name: &str) -> String {
/// format!("{}.fish", name)
/// }
/// }
/// ```
fn file_name(name: &str) -> String;

/// Generates output out of [`clap::App`](../clap/struct.App.html).
///
/// # Examples
///
/// The following example generator displays the [`clap::App`](../clap/struct.App.html)
/// as if it is printed using [`std::println`](https://doc.rust-lang.org/std/macro.println.html).
///
/// ```
/// use std::io::Write;
/// use clap::App;
/// use clap_generate::Generator;
///
/// pub struct ClapDebug;
///
/// impl Generator for ClapDebug {
/// fn generate<W: Write>(app: &app, buf: &mut W) {
/// buf.write_all(app).unwrap();
/// }
/// # fn file_name<S: Into<String>>(name: S) -> String {
/// # name.into()
/// # }
/// }
/// ```
fn generate<W: Write>(app: &App, buf: &mut W);

/// Gets all subcommands including child subcommands in the form of 'name' where the name
/// is a single word (i.e. "install") of the path to said subcommand (i.e.
/// "rustup toolchain install")
///
/// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
/// aliasing.
fn all_subcommand_names(app: &App) -> Vec<String> {
debugln!("all_subcommand_names;");

let mut subcmds: Vec<_> = Self::subcommands_of(app)
.iter()
.map(|&(ref n, _)| n.clone())
.collect();

for sc_v in subcommands!(app).map(|s| Self::all_subcommand_names(&s)) {
subcmds.extend(sc_v);
}

subcmds.sort();
subcmds.dedup();
subcmds
}

/// Gets all subcommands including child subcommands in the form of ('name', 'bin_name') where the name
/// is a single word (i.e. "install") of the path and full bin_name of said subcommand (i.e.
/// "rustup toolchain install")
///
/// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
/// aliasing.
fn all_subcommands(app: &App) -> Vec<(String, String)> {
debugln!("all_subcommands;");

let mut subcmds: Vec<_> = Self::subcommands_of(app);

for sc_v in subcommands!(app).map(|s| Self::all_subcommands(&s)) {
subcmds.extend(sc_v);
}

subcmds
}

/// Gets all subcommands exlcuding child subcommands in the form of (name, bin_name) where the name
/// is a single word (i.e. "install") and the bin_name is a space deliniated list of the path to said
/// subcommand (i.e. "rustup toolchain install")
///
/// Also note, aliases are treated as their own subcommands but duplicates of whatever they're
/// aliasing.
fn subcommands_of(p: &App) -> Vec<(String, String)> {
debugln!(
"subcommands_of: name={}, bin_name={}",
p.name,
p.bin_name.as_ref().unwrap()
);
debugln!(
"subcommands_of: Has subcommands...{:?}",
p.has_subcommands()
);

let mut subcmds = vec![];

if !p.has_subcommands() {
let mut ret = vec![];

debugln!("subcommands_of: Looking for aliases...");

if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n);

let mut als_bin_name: Vec<_> =
p.bin_name.as_ref().unwrap().split(' ').collect();

als_bin_name.push(n);

let old = als_bin_name.len() - 2;

als_bin_name.swap_remove(old);
ret.push((n.to_owned(), als_bin_name.join(" ")));
}
}

return ret;
}

for sc in subcommands!(p) {
debugln!(
"subcommands_of:iter: name={}, bin_name={}",
sc.name,
sc.bin_name.as_ref().unwrap()
);
debugln!("subcommands_of:iter: Looking for aliases...");

if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases {
debugln!("subcommands_of:iter:iter: Found alias...{}", n);

let mut als_bin_name: Vec<_> =
p.bin_name.as_ref().unwrap().split(' ').collect();

als_bin_name.push(n);

let old = als_bin_name.len() - 2;

als_bin_name.swap_remove(old);
subcmds.push((n.to_owned(), als_bin_name.join(" ")));
}
}

subcmds.push((sc.name.clone(), sc.get_bin_name().unwrap().to_string()));
}

subcmds
}

/// TODO
fn get_all_subcommand_paths(p: &App, first: bool) -> Vec<String> {
debugln!("get_all_subcommand_paths;");

let mut subcmds = vec![];

if !p.has_subcommands() {
if !first {
let name = &*p.name;
let path = p.get_bin_name().unwrap().to_string().replace(" ", "__");
let mut ret = vec![path.clone()];

if let Some(ref aliases) = p.aliases {
for &(n, _) in aliases {
ret.push(path.replace(name, n));
}
}

return ret;
}

return vec![];
}

for sc in subcommands!(p) {
let name = &*sc.name;
let path = sc.get_bin_name().unwrap().to_string().replace(" ", "__");

subcmds.push(path.clone());

if let Some(ref aliases) = sc.aliases {
for &(n, _) in aliases {
subcmds.push(path.replace(name, n));
}
}
}

for sc_v in subcommands!(p).map(|s| Self::get_all_subcommand_paths(&s, false)) {
subcmds.extend(sc_v);
}

subcmds
}
}
Loading

0 comments on commit 3b8527f

Please sign in to comment.