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