mirror of
https://github.com/clap-rs/clap
synced 2024-12-15 07:12:32 +00:00
commit
1ab5e39756
8 changed files with 259 additions and 4 deletions
|
@ -3,7 +3,7 @@ language: rust
|
||||||
cache: cargo
|
cache: cargo
|
||||||
rust:
|
rust:
|
||||||
- nightly
|
- nightly
|
||||||
- nightly-2017-10-11
|
- nightly-2018-06-19
|
||||||
- beta
|
- beta
|
||||||
- stable
|
- stable
|
||||||
- 1.20.0
|
- 1.20.0
|
||||||
|
|
|
@ -42,7 +42,7 @@ A simple to use, efficient, and full featured Command Line Argument Parser
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "kbknapp/clap-rs" }
|
travis-ci = { repository = "kbknapp/clap-rs" }
|
||||||
appveyor = { repository = "kbknapp/clap-rs" }
|
appveyor = { repository = "kbknapp/clap-rs" }
|
||||||
coveralls = { repostiory = "kbknapp/clap-rs", branch = "master" }
|
coveralls = { repository = "kbknapp/clap-rs", branch = "master" }
|
||||||
is-it-maintained-issue-resolution = { repository = "kbknapp/clap-rs" }
|
is-it-maintained-issue-resolution = { repository = "kbknapp/clap-rs" }
|
||||||
is-it-maintained-open-issues = { repository = "kbknapp/clap-rs" }
|
is-it-maintained-open-issues = { repository = "kbknapp/clap-rs" }
|
||||||
maintenance = {status = "actively-developed"}
|
maintenance = {status = "actively-developed"}
|
||||||
|
|
|
@ -1893,6 +1893,7 @@ impl<'a, 'b> App<'a, 'b> {
|
||||||
Shell::Fish => format!("{}.fish", name),
|
Shell::Fish => format!("{}.fish", name),
|
||||||
Shell::Zsh => format!("_{}", name),
|
Shell::Zsh => format!("_{}", name),
|
||||||
Shell::PowerShell => format!("_{}.ps1", name),
|
Shell::PowerShell => format!("_{}.ps1", name),
|
||||||
|
Shell::Elvish => format!("{}.elv", name),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut file = match File::create(out_dir.join(file_name)) {
|
let mut file = match File::create(out_dir.join(file_name)) {
|
||||||
|
|
126
src/completions/elvish.rs
Normal file
126
src/completions/elvish.rs
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
// Std
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
// Internal
|
||||||
|
use app::parser::Parser;
|
||||||
|
use INTERNAL_ERROR_MSG;
|
||||||
|
|
||||||
|
pub struct ElvishGen<'a, 'b>
|
||||||
|
where
|
||||||
|
'a: 'b,
|
||||||
|
{
|
||||||
|
p: &'b Parser<'a, 'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> ElvishGen<'a, 'b> {
|
||||||
|
pub fn new(p: &'b Parser<'a, 'b>) -> Self { ElvishGen { p: p } }
|
||||||
|
|
||||||
|
pub fn generate_to<W: Write>(&self, buf: &mut W) {
|
||||||
|
let bin_name = self.p.meta.bin_name.as_ref().unwrap();
|
||||||
|
|
||||||
|
let mut names = vec![];
|
||||||
|
let subcommands_cases =
|
||||||
|
generate_inner(self.p, "", &mut names);
|
||||||
|
|
||||||
|
let result = format!(r#"
|
||||||
|
edit:completion:arg-completer[{bin_name}] = [@words]{{
|
||||||
|
fn spaces [n]{{
|
||||||
|
repeat $n ' ' | joins ''
|
||||||
|
}}
|
||||||
|
fn cand [text desc]{{
|
||||||
|
edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
|
||||||
|
}}
|
||||||
|
command = '{bin_name}'
|
||||||
|
for word $words[1:-1] {{
|
||||||
|
if (has-prefix $word '-') {{
|
||||||
|
break
|
||||||
|
}}
|
||||||
|
command = $command';'$word
|
||||||
|
}}
|
||||||
|
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<'a, 'b, 'p>(
|
||||||
|
p: &'p Parser<'a, 'b>,
|
||||||
|
previous_command_name: &str,
|
||||||
|
names: &mut Vec<&'p str>,
|
||||||
|
) -> String {
|
||||||
|
debugln!("ElvishGen::generate_inner;");
|
||||||
|
let command_name = if previous_command_name.is_empty() {
|
||||||
|
p.meta.bin_name.as_ref().expect(INTERNAL_ERROR_MSG).clone()
|
||||||
|
} else {
|
||||||
|
format!("{};{}", previous_command_name, &p.meta.name)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut completions = String::new();
|
||||||
|
let preamble = String::from("\n cand ");
|
||||||
|
|
||||||
|
for option in p.opts() {
|
||||||
|
if let Some(data) = option.s.short {
|
||||||
|
let tooltip = get_tooltip(option.b.help, data);
|
||||||
|
completions.push_str(&preamble);
|
||||||
|
completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
|
||||||
|
}
|
||||||
|
if let Some(data) = option.s.long {
|
||||||
|
let tooltip = get_tooltip(option.b.help, data);
|
||||||
|
completions.push_str(&preamble);
|
||||||
|
completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for flag in p.flags() {
|
||||||
|
if let Some(data) = flag.s.short {
|
||||||
|
let tooltip = get_tooltip(flag.b.help, data);
|
||||||
|
completions.push_str(&preamble);
|
||||||
|
completions.push_str(format!("-{} '{}'", data, tooltip).as_str());
|
||||||
|
}
|
||||||
|
if let Some(data) = flag.s.long {
|
||||||
|
let tooltip = get_tooltip(flag.b.help, data);
|
||||||
|
completions.push_str(&preamble);
|
||||||
|
completions.push_str(format!("--{} '{}'", data, tooltip).as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for subcommand in &p.subcommands {
|
||||||
|
let data = &subcommand.p.meta.name;
|
||||||
|
let tooltip = get_tooltip(subcommand.p.meta.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.subcommands {
|
||||||
|
let subcommand_subcommands_cases =
|
||||||
|
generate_inner(&subcommand.p, &command_name, names);
|
||||||
|
subcommands_cases.push_str(&subcommand_subcommands_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
subcommands_cases
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ mod bash;
|
||||||
mod fish;
|
mod fish;
|
||||||
mod zsh;
|
mod zsh;
|
||||||
mod powershell;
|
mod powershell;
|
||||||
|
mod elvish;
|
||||||
mod shell;
|
mod shell;
|
||||||
|
|
||||||
// Std
|
// Std
|
||||||
|
@ -15,6 +16,7 @@ use self::bash::BashGen;
|
||||||
use self::fish::FishGen;
|
use self::fish::FishGen;
|
||||||
use self::zsh::ZshGen;
|
use self::zsh::ZshGen;
|
||||||
use self::powershell::PowerShellGen;
|
use self::powershell::PowerShellGen;
|
||||||
|
use self::elvish::ElvishGen;
|
||||||
pub use self::shell::Shell;
|
pub use self::shell::Shell;
|
||||||
|
|
||||||
pub struct ComplGen<'a, 'b>(&'b App<'a, 'b>)
|
pub struct ComplGen<'a, 'b>(&'b App<'a, 'b>)
|
||||||
|
@ -26,6 +28,7 @@ impl<'a, 'b> ComplGen<'a, 'b> {
|
||||||
|
|
||||||
pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
|
pub fn generate<W: Write>(&self, for_shell: Shell, buf: &mut W) {
|
||||||
match for_shell {
|
match for_shell {
|
||||||
|
Shell::Elvish => ElvishGen::new(self.p).generate_to(buf),
|
||||||
Shell::Bash => BashGen::new(self.0).generate_to(buf),
|
Shell::Bash => BashGen::new(self.0).generate_to(buf),
|
||||||
Shell::Fish => FishGen::new(self.0).generate_to(buf),
|
Shell::Fish => FishGen::new(self.0).generate_to(buf),
|
||||||
Shell::Zsh => ZshGen::new(self.0).generate_to(buf),
|
Shell::Zsh => ZshGen::new(self.0).generate_to(buf),
|
||||||
|
|
|
@ -15,11 +15,13 @@ pub enum Shell {
|
||||||
Zsh,
|
Zsh,
|
||||||
/// Generates a completion file for PowerShell
|
/// Generates a completion file for PowerShell
|
||||||
PowerShell,
|
PowerShell,
|
||||||
|
/// Generates a completion file for Elvish
|
||||||
|
Elvish,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shell {
|
impl Shell {
|
||||||
/// A list of possible variants in `&'static str` form
|
/// A list of possible variants in `&'static str` form
|
||||||
pub fn variants() -> [&'static str; 4] { ["zsh", "bash", "fish", "powershell"] }
|
pub fn variants() -> [&'static str; 5] { ["zsh", "bash", "fish", "powershell", "elvish"] }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Shell {
|
impl FromStr for Shell {
|
||||||
|
@ -31,7 +33,8 @@ impl FromStr for Shell {
|
||||||
"FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish),
|
"FISH" | _ if s.eq_ignore_ascii_case("fish") => Ok(Shell::Fish),
|
||||||
"BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash),
|
"BASH" | _ if s.eq_ignore_ascii_case("bash") => Ok(Shell::Bash),
|
||||||
"POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell),
|
"POWERSHELL" | _ if s.eq_ignore_ascii_case("powershell") => Ok(Shell::PowerShell),
|
||||||
_ => Err(String::from("[valid values: bash, fish, zsh, powershell]")),
|
"ELVISH" | _ if s.eq_ignore_ascii_case("elvish") => Ok(Shell::Elvish),
|
||||||
|
_ => Err(String::from("[valid values: bash, fish, zsh, powershell, elvish]")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +46,7 @@ impl fmt::Display for Shell {
|
||||||
Shell::Fish => write!(f, "FISH"),
|
Shell::Fish => write!(f, "FISH"),
|
||||||
Shell::Zsh => write!(f, "ZSH"),
|
Shell::Zsh => write!(f, "ZSH"),
|
||||||
Shell::PowerShell => write!(f, "POWERSHELL"),
|
Shell::PowerShell => write!(f, "POWERSHELL"),
|
||||||
|
Shell::Elvish => write!(f, "ELVISH"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -858,6 +858,8 @@ impl<'a> DoubleEndedIterator for OsValues<'a> {
|
||||||
fn next_back(&mut self) -> Option<&'a OsStr> { self.iter.next_back() }
|
fn next_back(&mut self) -> Option<&'a OsStr> { self.iter.next_back() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> ExactSizeIterator for OsValues<'a> {}
|
||||||
|
|
||||||
/// Creates an empty iterator.
|
/// Creates an empty iterator.
|
||||||
impl<'a> Default for OsValues<'a> {
|
impl<'a> Default for OsValues<'a> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
|
@ -228,6 +228,105 @@ Register-ArgumentCompleter -Native -CommandName 'my_app' -ScriptBlock {
|
||||||
}
|
}
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
static ELVISH: &'static str = r#"
|
||||||
|
edit:completion:arg-completer[my_app] = [@words]{
|
||||||
|
fn spaces [n]{
|
||||||
|
repeat $n ' ' | joins ''
|
||||||
|
}
|
||||||
|
fn cand [text desc]{
|
||||||
|
edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
|
||||||
|
}
|
||||||
|
command = 'my_app'
|
||||||
|
for word $words[1:-1] {
|
||||||
|
if (has-prefix $word '-') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
command = $command';'$word
|
||||||
|
}
|
||||||
|
completions = [
|
||||||
|
&'my_app'= {
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
cand test 'tests things'
|
||||||
|
cand help 'Prints this message or the help of the given subcommand(s)'
|
||||||
|
}
|
||||||
|
&'my_app;test'= {
|
||||||
|
cand --case 'the case to test'
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
&'my_app;help'= {
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
$completions[$command]
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
|
static ELVISH_SPECIAL_CMDS: &'static str = r#"
|
||||||
|
edit:completion:arg-completer[my_app] = [@words]{
|
||||||
|
fn spaces [n]{
|
||||||
|
repeat $n ' ' | joins ''
|
||||||
|
}
|
||||||
|
fn cand [text desc]{
|
||||||
|
edit:complex-candidate $text &display-suffix=' '(spaces (- 14 (wcswidth $text)))$desc
|
||||||
|
}
|
||||||
|
command = 'my_app'
|
||||||
|
for word $words[1:-1] {
|
||||||
|
if (has-prefix $word '-') {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
command = $command';'$word
|
||||||
|
}
|
||||||
|
completions = [
|
||||||
|
&'my_app'= {
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
cand test 'tests things'
|
||||||
|
cand some_cmd 'tests other things'
|
||||||
|
cand some-cmd-with-hypens 'some-cmd-with-hypens'
|
||||||
|
cand help 'Prints this message or the help of the given subcommand(s)'
|
||||||
|
}
|
||||||
|
&'my_app;test'= {
|
||||||
|
cand --case 'the case to test'
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
&'my_app;some_cmd'= {
|
||||||
|
cand --config 'the other case to test'
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
&'my_app;some-cmd-with-hypens'= {
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
&'my_app;help'= {
|
||||||
|
cand -h 'Prints help information'
|
||||||
|
cand --help 'Prints help information'
|
||||||
|
cand -V 'Prints version information'
|
||||||
|
cand --version 'Prints version information'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
$completions[$command]
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
|
static POWERSHELL_SPECIAL_CMDS: &'static str = r#"
|
||||||
using namespace System.Management.Automation
|
using namespace System.Management.Automation
|
||||||
using namespace System.Management.Automation.Language
|
using namespace System.Management.Automation.Language
|
||||||
|
@ -703,6 +802,26 @@ fn powershell() {
|
||||||
assert!(compare(&*string, POWERSHELL));
|
assert!(compare(&*string, POWERSHELL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn elvish() {
|
||||||
|
let mut app = build_app();
|
||||||
|
let mut buf = vec![];
|
||||||
|
app.gen_completions_to("my_app", Shell::Elvish, &mut buf);
|
||||||
|
let string = String::from_utf8(buf).unwrap();
|
||||||
|
|
||||||
|
assert!(compare(&*string, ELVISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn elvish_with_special_commands() {
|
||||||
|
let mut app = build_app_special_commands();
|
||||||
|
let mut buf = vec![];
|
||||||
|
app.gen_completions_to("my_app", Shell::Elvish, &mut buf);
|
||||||
|
let string = String::from_utf8(buf).unwrap();
|
||||||
|
|
||||||
|
assert!(compare(&*string, ELVISH_SPECIAL_CMDS));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn powershell_with_special_commands() {
|
fn powershell_with_special_commands() {
|
||||||
let mut app = build_app_special_commands();
|
let mut app = build_app_special_commands();
|
||||||
|
|
Loading…
Reference in a new issue