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 """Automatic completion for optparse module.
34
35 This module provide automatic bash completion support for programs that use the
36 optparse module. The premise is that the optparse options parser specifies
37 enough information (and more) for us to be able to generate completion strings
38 esily. Another advantage of this over traditional completion schemes where the
39 completion strings are hard-coded in a separate bash source file, is that the
40 same code that parses the options is used to generate the completions, so the
41 completions is always up-to-date with the program itself.
42
43 In addition, we allow you specify a list of regular expressions or code that
44 define what kinds of files should be proposed as completions to this file if
45 needed. If you want to implement more complex behaviour, you can instead
46 specify a function, which will be called with the current directory as an
47 argument.
48
49 You need to activate bash completion using the shell script function that comes
50 with optcomplete (see http://furius.ca/optcomplete for more details).
51
52 """
53
54 __version__ = "$Revision$"
55 __author__ = "Martin Blais <blais@furius.ca>"
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 import os
92 import sys
93 import types
94 import re
95
96 from pprint import pformat
97
98 from optparse import OptionParser
99
100 debugfn = '/tmp/completion-debug.log'
101
102
104
105 """Completes by listing all possible files in current directory."""
106
107 - def __call__(self, pwd, line, point, prefix, suffix):
108 return os.listdir(pwd)
109
110
112
113 """Generates empty completion list."""
114
115 - def __call__(self, pwd, line, point, prefix, suffix):
117
118
120
121 """Completes by listing subdirectories only."""
122
123 - def __call__(self, pwd, line, point, prefix, suffix):
124 return filter(os.path.isdir, os.listdir(pwd))
125
126
128
129 """Completes by filtering all possible files with the given list of
130 regexps."""
131
132 - def __init__(self, regexlist, always_dirs=True):
133 self.always_dirs = always_dirs
134
135 if isinstance(regexlist, types.StringType):
136 regexlist = [regexlist]
137 self.regexlist = []
138 for r in regexlist:
139 if isinstance(r, types.StringType):
140 r = re.compile(r)
141 self.regexlist.append(r)
142
143 - def __call__(self, pwd, line, point, prefix, suffix):
144 dn = os.path.dirname(prefix)
145 if dn:
146 pwd = dn
147 files = os.listdir(pwd)
148 ofiles = []
149 for fn in files:
150 for r in self.regexlist:
151 if r.match(fn):
152 if dn:
153 fn = os.path.join(dn, fn)
154 ofiles.append(fn)
155 break
156 if self.always_dirs and os.path.isdir(fn):
157 ofiles.append(fn + '/')
158 return ofiles
159
160
162
163 """Completes by filtering using a fixed list of strings."""
164
166 self.olist = stringlist
167
168 - def __call__(self, pwd, line, point, prefix, suffix):
170
171
173
174 """Return a prefix and suffix of the enclosing word. The character under
175 the cursor is the first character of the suffix."""
176
177 wsre = re.compile('[ \t]')
178
179 if point < 0 or point > len(line):
180 return '', ''
181
182 preii = point - 1
183 while preii >= 0:
184 if wsre.match(line[preii]):
185 break
186 preii -= 1
187 preii += 1
188
189 sufii = point
190 while sufii < len(line):
191 if wsre.match(line[sufii]):
192 break
193 sufii += 1
194
195 return line[preii:point], line[point:sufii]
196
197
198 -def autocomplete(parser,
199 arg_completer=None,
200 opt_completer=None,
201 subcmd_completer=None,
202 subcommands=None):
203
204 """Automatically detect if we are requested completing and if so generate
205 completion automatically from given parser.
206
207 'parser' is the options parser to use.
208
209 'arg_completer' is a callable object that gets invoked to produce a list of
210 completions for arguments completion (oftentimes files).
211
212 'opt_completer' is the default completer to the options that require a
213 value. 'subcmd_completer' is the default completer for the subcommand
214 arguments.
215
216 If 'subcommands' is specified, the script expects it to be a map of
217 command-name to an object of any kind. We are assuming that this object is
218 a map from command name to a pair of (options parser, completer) for the
219 command. If the value is not such a tuple, the method
220 'autocomplete(completer)' is invoked on the resulting object.
221
222 This will attempt to match the first non-option argument into a subcommand
223 name and if so will use the local parser in the corresponding map entry's
224 value. This is used to implement completion for subcommand syntax and will
225 not be needed in most cases."""
226
227
228
229 if 'OPTPARSE_AUTO_COMPLETE' not in os.environ:
230 return
231
232
233 if arg_completer is None:
234 arg_completer = NoneCompleter()
235 if opt_completer is None:
236 opt_completer = NoneCompleter()
237 if subcmd_completer is None:
238
239 subcmd_completer = NoneCompleter()
240
241
242
243 completer = arg_completer
244
245
246
247
248
249
250
251
252
253 if not 'COMP_WORDS' in os.environ:
254 os.environ['COMP_WORDS'] = os.environ['COMP_LINE']
255
256 cwords = os.environ['COMP_WORDS'].split()
257 cline = os.environ['COMP_LINE']
258 cpoint = int(os.environ['COMP_POINT'])
259 cword = int(os.environ['COMP_CWORD'])
260
261
262
263 if subcommands:
264 assert isinstance(subcommands, types.DictType)
265 value = guess_first_nonoption(parser, subcommands)
266 if value:
267 if isinstance(value, types.ListType) or \
268 isinstance(value, types.TupleType):
269 parser = value[0]
270 if len(value) > 1 and value[1]:
271
272 completer = value[1]
273 else:
274 completer = subcmd_completer
275 return autocomplete(parser, completer)
276 else:
277
278
279 if hasattr(value, 'autocomplete'):
280 return value.autocomplete(subcmd_completer)
281 else:
282 sys.exit(1)
283
284
285 prefix, suffix = extract_word(cline, cpoint)
286
287
288
289
290
291
292
293 optarg = False
294 try:
295
296
297 prev = None
298 if cword < len(cwords):
299 mo = re.search('(--.*)=(.*)', cwords[cword])
300 if mo:
301 prev, prefix = mo.groups()
302 if not prev:
303 prev = cwords[cword - 1]
304
305 if prev and prev.startswith('-'):
306 option = parser.get_option(prev)
307 if option:
308 if option.nargs > 0:
309 optarg = True
310 if hasattr(option, 'completer'):
311 completer = option.completer
312 elif option.type != 'string':
313 completer = NoneCompleter()
314 else:
315 completer = opt_completer
316
317 elif hasattr(option, 'completer'):
318 raise SystemExit(
319 "Error: optparse option with a completer "
320 "does not take arguments: %s" % str(option))
321 except KeyError:
322 pass
323
324 completions = []
325
326
327 if not optarg and (not prefix or prefix.startswith('-')):
328 completions += parser._short_opt.keys()
329 completions += parser._long_opt.keys()
330
331
332
333 if completer and (not prefix or not prefix.startswith('-')):
334
335
336 if isinstance(completer, types.StringType) or \
337 isinstance(completer, types.ListType) or \
338 isinstance(completer, types.TupleType):
339 completer = RegexCompleter(completer)
340 completions += completer(os.getcwd(), cline,
341 cpoint, prefix, suffix)
342 elif isinstance(completer, types.FunctionType) or \
343 isinstance(completer, types.LambdaType) or \
344 isinstance(completer, types.ClassType) or \
345 isinstance(completer, types.ObjectType):
346 completions += completer(os.getcwd(), cline,
347 cpoint, prefix, suffix)
348
349
350 if prefix:
351 completions = filter(lambda x: x.startswith(prefix), completions)
352
353
354 print ' '.join(completions)
355
356
357
358 if debugfn:
359 f = open(debugfn, 'a')
360 print >> f, '---------------------------------------------------------'
361 print >> f, 'CWORDS', cwords
362 print >> f, 'CLINE', cline
363 print >> f, 'CPOINT', cpoint
364 print >> f, 'CWORD', cword
365 print >> f, '\nShort options'
366 print >> f, pformat(parser._short_opt)
367 print >> f, '\nLong options'
368 print >> f, pformat(parser._long_opt)
369 print >> f, 'Prefix/Suffix:', prefix, suffix
370 print >> f, 'completions', completions
371 f.close()
372
373
374
375 sys.exit(1)
376
377
379 """Hack to keep OptionParser from writing to sys.stderr when
380 calling self.exit from self.error"""
381 self.exit(2, msg=None)
382
383
385
386 """Given a global options parser, try to guess the first non-option without
387 generating an exception. This is used for scripts that implement a
388 subcommand syntax, so that we can generate the appropriate completions for
389 the subcommand."""
390
391 import copy
392 gparser = copy.deepcopy(gparser)
393
394 def print_usage_nousage(self, file=None):
395 pass
396 gparser.print_usage = print_usage_nousage
397
398
399 prev_interspersed = gparser.allow_interspersed_args
400 gparser.disable_interspersed_args()
401
402 cwords = os.environ['COMP_WORDS'].split()
403
404
405 error_func = gparser.error
406 try:
407 try:
408 instancemethod = type(OptionParser.error)
409
410 gparser.error = instancemethod(error_override,
411 gparser, OptionParser)
412 gopts, args = gparser.parse_args(cwords[1:])
413 except SystemExit:
414 return None
415 finally:
416
417 gparser.error = instancemethod(error_func, gparser, OptionParser)
418
419 value = None
420 if args:
421 subcmdname = args[0]
422 try:
423 value = subcmds_map[subcmdname]
424 except KeyError:
425 pass
426
427 gparser.allow_interspersed_args = prev_interspersed
428
429 return value
430
431
433
434 """Simple default base class implementation for a subcommand that supports
435 command completion. This class is assuming that there might be a method
436 addopts(self, parser) to declare options for this subcommand, and an
437 optional completer data member to contain command-specific completion. Of
438 course, you don't really have to use this, but if you do it is convenient
439 to have it here."""
440
452
453
464
465 if __name__ == '__main__':
466 test()
467