-
Notifications
You must be signed in to change notification settings - Fork 75
Expand file tree
/
Copy pathgenerate-completion-scripts.pl
More file actions
executable file
·231 lines (205 loc) · 9.04 KB
/
Copy pathgenerate-completion-scripts.pl
File metadata and controls
executable file
·231 lines (205 loc) · 9.04 KB
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/usr/bin/env perl
use strict;
use warnings;
use lib 'blib/lib';
use lib 't';
use Template;
use Util;
# XXX special completion for --type-add?
# XXX don't complete mutually exclusive options?
# XXX don't complete repeat options? (bash)
# XXX don't do anything post -- (bash)
# XXX handle option arguments (zsh)
my %ZSH_DESCRIPTIONS = (
'--ackrc' => 'specify an alternative ackrc',
'--after-context' => 'print NUM lines of trailing context after matching lines',
'--bar' => 'check with the admiral for traps',
'--before-context' => 'print NUM lines of leading context before matching lines',
'--break' => 'print a break between results for different files',
'--cathy' => 'chocolate, chocolate, chocolate!' ,
'--color' => 'highlight matching text',
'--color-filename' => 'set color for filenames',
'--color-lineno' => 'set color for line numbers',
'--color-match' => 'set color for matches',
'--column' => 'show column number of first match',
'--context' => 'print NUM lines of context around matching lines',
'--count' => 'print a count of matching lines for each input file',
'--create-ackrc' => 'dumps default ack options to standard output',
'--dump' => 'writes the list of loaded options and where they came from',
'--files-from' => 'specifies the list of files to search within FILE',
'--files-with-matches' => 'only print filenames of matching files',
'--files-without-matches' => 'only print filenames of non-matching files',
'--filter' => 'force ack to behave as if it were receiving input via a pipe',
'--flush' => 'flushes output immediately',
'--follow' => 'follow symlinks',
'--group' => 'group matches by filename',
'--heading' => q{print a filename heading above each file's result},
'--help' => 'displays help',
'--help-types' => 'print all known types',
'--ignore-ack-defaults' => 'ignore default definitions provided with ack',
'--ignore-case' => 'ignore case in matches',
'--ignore-directory' => 'ignore directories (at any level) named DIRNAME',
'--ignore-file' => 'ignore files matching FILTERTYPE:FILTERARGS',
'--invert-match' => 'select non-matching lines',
'--literal' => 'quote all metacharacters in PATTERN',
'--man' => 'displays the ack man page',
'--match' => 'specify PATTERN explicitly',
'--max-count' => 'stop reading after NUM matches',
'--no-filename' => q{don't print filenames on output},
'--no-lineno' => q{don't print line numbers on output},
'--noenv' => q{don't consider ackrc files/environment variables for configuration},
'--output' => 'output the evaluation of EXPR for each line',
'--pager' => q{direct ack's output through PAGER},
'--passthru' => 'print all lines, whether or not they match the expression, highlighting matches',
'--print0' => 'separate output lines with NUL characters',
'--recurse' => 'recurse into subdirectories',
'--show-types' => 'outputs the filetypes that ack associates with each file',
'--smart-case' => 'ignores case in search strings if PATTERN contains no uppercase characters',
'--sort-files' => 'sorts found files lexicographically',
'--thpppt' => 'display the Bill The Cat logo.',
'--type-add' => 'add a type definition',
'--type-del' => 'removes a type definition',
'--type-set' => 'add a type definition',
'--version' => 'displays version and copyright information',
'--with-filename' => 'print the filename for each match',
'--word-regexp' => 'force PATTERN to match only whole words',
'-1' => 'stops after reporting first match',
'-f' => 'only print files that would be searched',
'-g' => 'only print files whose names match PATTERN',
'-o' => 'only print the part of each matching line that matches PATTERN',
'-s' => 'suppress error messages about nonexistent or unreadable files',
'-x' => 'search files specified on standard input',
);
my %OPTION_ALIASES = (
'--after-context' => ['-A'],
'--before-context' => ['-B'],
'--context' => ['-C'],
'--count' => ['-c'],
'--no-filename' => ['-h'],
'--with-filename' => ['-H'],
'--files-with-matches' => ['-l'],
'--files-without-matches' => ['-L'],
'--max-count' => ['-m'],
'--no-recurse' => ['-n'],
'--help' => ['-?'],
'--ignore-case' => ['-i'],
'--literal' => ['-Q'],
'--recurse' => ['-r', '-R'],
'--invert-match' => ['-v'],
'--word-regexp' => ['-w'],
'--color' => ['--colour'],
'--ignore-directory' => ['--ignore-dir'],
);
my %IS_AN_ALIAS = map { $_ => 1 } map { @$_ } values %OPTION_ALIASES;
my $BASH_TEMPLATE = <<'END_TEMPLATE';
declare -g -a _ack_options
declare -g -a _ack_types=()
_ack_options=(
[% FOREACH option IN options -%]
"[% option -%]" \
[% END -%]
)
function __setup_ack() {
local type
while read LINE; do
case $LINE in
--*)
type="${LINE%% *}"
type=${type/--\[no\]/}
_ack_options[ ${#_ack_options[@]} ]="--$type"
_ack_options[ ${#_ack_options[@]} ]="--no$type"
_ack_types[ ${#_ack_types[@]} ]="$type"
;;
esac
done < <(ack --help-types)
}
__setup_ack
unset -f __setup_ack
function _ack_complete() {
local current_word
local pattern
current_word=${COMP_WORDS[$COMP_CWORD]}
if [[ "$current_word" == -* ]]; then
pattern="${current_word}*"
for option in ${_ack_options[@]}; do
if [[ "$option" == $pattern ]]; then
COMPREPLY[ ${#COMPREPLY[@]} ]=$option
fi
done
else
local previous_word
previous_word=${COMP_WORDS[$(( $COMP_CWORD - 1 ))]}
if [[ "$previous_word" == "=" ]]; then
previous_word=${COMP_WORDS[$(( $COMP_CWORD - 2 ))]}
fi
if [ "$previous_word" == '--type' -o "$previous_word" == '--notype' ]; then
pattern="${current_word}*"
for type in ${_ack_types[@]}; do
if [[ "$type" == $pattern ]]; then
COMPREPLY[ ${#COMPREPLY[@]} ]=$type
fi
done
fi
fi
}
complete -o default -F _ack_complete ack ack2 ack-grep
END_TEMPLATE
my $ZSH_TEMPLATE = <<'END_TEMPLATE';
#compdef ack ack2 ack-grep
declare -a ack_types
declare -a arguments
local type
arguments=( \
[% FOREACH option IN options -%]
[% IF option != '--type' && option != '--notype' && !is_alias.exists(option) -%]
[% FILTER collapse -%]
[%- IF aliases.exists(option) -%]
{[% option -%],[% aliases.$option.join(',') -%]}
[%- ELSE -%]
"[% option -%]"
[%- END -%]
[%- IF descriptions.exists(option) -%]
"[[% descriptions.$option -%]]"
[%- END -%]
[% END -%]
\
[% END -%]
[% END -%]
)
while read LINE; do
case $LINE in
--*)
type="${LINE%% *}"
type=${type/--\[no\]/}
arguments[$(( ${#arguments[@]} + 1 ))]="--${type}[restrict to files of type $type]"
arguments[$(( ${#arguments[@]} + 1 ))]="--no${type}[restrict to files other than type $type]"
ack_types[$(( ${#ack_types[@]} + 1 ))]="$type"
;;
esac
done < <(ack --help-types)
arguments[$(( ${#arguments[@]} + 1 ))]="--type=[restrict to files of given type]:filetype:(${ack_types[@]})"
arguments[$(( ${#arguments[@]} + 1 ))]="--notype=[restrict to files other than given type]:notfiletype:(${ack_types[@]})"
arguments[$(( ${#arguments[@]} + 1 ))]="*:files:_files"
_arguments -S $arguments
END_TEMPLATE
my $tt = Template->new({});
# XXX do a sanity check on ZSH_DESCRIPTIONS vs get_expected_options, OPTION_ALIASES
my $vars = {
options => [ get_expected_options() ],
descriptions => \%ZSH_DESCRIPTIONS,
aliases => \%OPTION_ALIASES,
is_alias => \%IS_AN_ALIAS,
};
my ( $filename ) = @ARGV;
if ( !$filename ) {
die "usage: $0 (completion.bash|completion.zsh)\n";
}
elsif ( $filename eq 'completion.bash' ) {
$tt->process(\$BASH_TEMPLATE, $vars, 'completion.bash') || die $tt->error;
}
elsif ( $filename eq 'completion.zsh' ) {
$tt->process(\$ZSH_TEMPLATE, $vars, 'completion.zsh') || die $tt->error;
}
else {
die "I don't know how to generate $filename\n";
}