1 | use std::io::Write; |
2 | |
3 | use clap::builder::StyledStr; |
4 | use clap::*; |
5 | |
6 | use crate::generator::{utils, Generator}; |
7 | use crate::INTERNAL_ERROR_MSG; |
8 | |
9 | /// Generate elvish completion file |
10 | #[derive (Copy, Clone, PartialEq, Eq, Debug)] |
11 | pub struct Elvish; |
12 | |
13 | impl Generator for Elvish { |
14 | fn file_name(&self, name: &str) -> String { |
15 | format!(" {name}.elv" ) |
16 | } |
17 | |
18 | fn generate(&self, cmd: &Command, buf: &mut dyn Write) { |
19 | let bin_name = cmd |
20 | .get_bin_name() |
21 | .expect("crate::generate should have set the bin_name" ); |
22 | |
23 | let subcommands_cases = generate_inner(cmd, "" ); |
24 | |
25 | let result = format!( |
26 | r#" |
27 | use builtin; |
28 | use str; |
29 | |
30 | set edit:completion:arg-completer[ {bin_name}] = {{|@words| |
31 | fn spaces {{|n| |
32 | builtin:repeat $n ' ' | str:join '' |
33 | }} |
34 | fn cand {{|text desc| |
35 | edit:complex-candidate $text &display=$text' '(spaces (- 14 (wcswidth $text)))$desc |
36 | }} |
37 | var command = ' {bin_name}' |
38 | for word $words[1..-1] {{ |
39 | if (str:has-prefix $word '-') {{ |
40 | break |
41 | }} |
42 | set command = $command';'$word |
43 | }} |
44 | var completions = [ {subcommands_cases} |
45 | ] |
46 | $completions[$command] |
47 | }} |
48 | "# , |
49 | ); |
50 | |
51 | w!(buf, result.as_bytes()); |
52 | } |
53 | } |
54 | |
55 | // Escape string inside single quotes |
56 | fn escape_string(string: &str) -> String { |
57 | string.replace(from:' \'' , to:"''" ) |
58 | } |
59 | |
60 | fn get_tooltip<T: ToString>(help: Option<&StyledStr>, data: T) -> String { |
61 | match help { |
62 | Some(help: &StyledStr) => escape_string(&help.to_string()), |
63 | _ => data.to_string(), |
64 | } |
65 | } |
66 | |
67 | fn generate_inner(p: &Command, previous_command_name: &str) -> String { |
68 | debug!("generate_inner" ); |
69 | |
70 | let command_name = if previous_command_name.is_empty() { |
71 | p.get_bin_name().expect(INTERNAL_ERROR_MSG).to_string() |
72 | } else { |
73 | format!(" {}; {}" , previous_command_name, &p.get_name()) |
74 | }; |
75 | |
76 | let mut completions = String::new(); |
77 | let preamble = String::from(" \n cand " ); |
78 | |
79 | for option in p.get_opts() { |
80 | if let Some(shorts) = option.get_short_and_visible_aliases() { |
81 | let tooltip = get_tooltip(option.get_help(), shorts[0]); |
82 | for short in shorts { |
83 | completions.push_str(&preamble); |
84 | completions.push_str(format!("- {short} ' {tooltip}'" ).as_str()); |
85 | } |
86 | } |
87 | |
88 | if let Some(longs) = option.get_long_and_visible_aliases() { |
89 | let tooltip = get_tooltip(option.get_help(), longs[0]); |
90 | for long in longs { |
91 | completions.push_str(&preamble); |
92 | completions.push_str(format!("-- {long} ' {tooltip}'" ).as_str()); |
93 | } |
94 | } |
95 | } |
96 | |
97 | for flag in utils::flags(p) { |
98 | if let Some(shorts) = flag.get_short_and_visible_aliases() { |
99 | let tooltip = get_tooltip(flag.get_help(), shorts[0]); |
100 | for short in shorts { |
101 | completions.push_str(&preamble); |
102 | completions.push_str(format!("- {short} ' {tooltip}'" ).as_str()); |
103 | } |
104 | } |
105 | |
106 | if let Some(longs) = flag.get_long_and_visible_aliases() { |
107 | let tooltip = get_tooltip(flag.get_help(), longs[0]); |
108 | for long in longs { |
109 | completions.push_str(&preamble); |
110 | completions.push_str(format!("-- {long} ' {tooltip}'" ).as_str()); |
111 | } |
112 | } |
113 | } |
114 | |
115 | for subcommand in p.get_subcommands() { |
116 | let data = &subcommand.get_name(); |
117 | let tooltip = get_tooltip(subcommand.get_about(), data); |
118 | |
119 | completions.push_str(&preamble); |
120 | completions.push_str(format!(" {data} ' {tooltip}'" ).as_str()); |
121 | } |
122 | |
123 | let mut subcommands_cases = format!( |
124 | r" |
125 | &' {}'= {{{} |
126 | }}" , |
127 | &command_name, completions |
128 | ); |
129 | |
130 | for subcommand in p.get_subcommands() { |
131 | let subcommand_subcommands_cases = generate_inner(subcommand, &command_name); |
132 | subcommands_cases.push_str(&subcommand_subcommands_cases); |
133 | } |
134 | |
135 | subcommands_cases |
136 | } |
137 | |