forked from pacak/bpaf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcomplete_run.rs
113 lines (106 loc) · 3.17 KB
/
complete_run.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::complete_gen::Complete;
use std::ffi::OsStr;
fn dump_bash_completer(name: &str) {
println!(
r#"_bpaf_dynamic_completion()
{{
line="$1 --bpaf-complete-rev=8 ${{COMP_WORDS[@]:1}}"
if [[ ${{COMP_WORDS[-1]}} == "" ]]; then
line="${{line}} \"\""
fi
source <( eval ${{line}})
}}
complete -o nosort -F _bpaf_dynamic_completion {name}"#,
name = name,
);
}
fn dump_zsh_completer(name: &str) {
println!(
r#"#compdef {name}
local line
line="${{words[1]}} --bpaf-complete-rev=7 ${{words[@]:1}}"
if [[ ${{words[-1]}} == "" ]]; then
line="${{line}} \"\""
fi
source <(eval ${{line}})
"#,
name = name
);
}
fn dump_fish_completer(name: &str) {
println!(
r#"function _bpaf_dynamic_completion
set -l current (commandline --tokenize --current-process)
set -l tmpline --bpaf-complete-rev=9 $current[2..]
if test (commandline --current-process) != (string trim (commandline --current-process))
set tmpline $tmpline ""
end
eval $current[1] \"$tmpline\"
end
complete --no-files --command {name} --arguments '(_bpaf_dynamic_completion)'
"#,
name = name
);
}
// I would love to support elvish better but debugger is not a thing
// and on any error in code it simply replies "no candidates" with no
// obvious way even to print "you are here"...
// https://github.com/elves/elvish/issues/803
fn dump_elvish_completer(name: &str) {
println!(
"\
set edit:completion:arg-completer[{name}] = {{ |@args| var args = $args[1..];
var @lines = ( {name} --bpaf-complete-rev={rev} $@args );
use str;
for line $lines {{
var @arg = (str:split \"\\t\" $line)
try {{
edit:complex-candidate $arg[0] &display=( printf \"%-19s %s\" $arg[0] $arg[1] )
}} catch {{
edit:complex-candidate $line
}}
}}
}}",
name = name,
rev = 1,
);
}
#[derive(Debug)]
pub(crate) struct ArgScanner<'a> {
pub(crate) revision: Option<usize>,
pub(crate) name: Option<&'a str>,
}
impl ArgScanner<'_> {
pub(crate) fn check_next(&mut self, arg: &OsStr) -> bool {
let arg = match arg.to_str() {
Some(arg) => arg,
None => return false,
};
// this only works when there's a name
if let Some(name) = &self.name {
let mut matched = true;
match arg {
"--bpaf-complete-style-zsh" => dump_zsh_completer(name),
"--bpaf-complete-style-bash" => dump_bash_completer(name),
"--bpaf-complete-style-fish" => dump_fish_completer(name),
"--bpaf-complete-style-elvish" => dump_elvish_completer(name),
_ => {
matched = false;
}
}
if matched {
std::process::exit(0)
}
}
if let Some(ver) = arg.strip_prefix("--bpaf-complete-rev=") {
if let Ok(ver) = ver.parse::<usize>() {
self.revision = Some(ver);
}
return true;
}
false
}
pub(crate) fn done(&self) -> Option<Complete> {
Some(Complete::new(self.revision?))
}
}