aboutsummaryrefslogtreecommitdiff
path: root/clap/src/completions/elvish.rs
diff options
context:
space:
mode:
Diffstat (limited to 'clap/src/completions/elvish.rs')
-rw-r--r--clap/src/completions/elvish.rs126
1 files changed, 126 insertions, 0 deletions
diff --git a/clap/src/completions/elvish.rs b/clap/src/completions/elvish.rs
new file mode 100644
index 0000000..9a5f21a
--- /dev/null
+++ b/clap/src/completions/elvish.rs
@@ -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
+}