##// END OF EJS Templates
bzr completer now gets commands from 'bzr help commands' (includes all commands provided by exensions also)
vivainio2 -
Show More
@@ -1,359 +1,354
1 1 #!/usr/bin/env python
2 2
3 3 """ Implementations for various useful completers
4 4
5 5 See Extensions/ipy_stock_completers.py on examples of how to enable a completer,
6 6 but the basic idea is to do:
7 7
8 8 ip.set_hook('complete_command', svn_completer, str_key = 'svn')
9 9
10 10 """
11 11 import IPython.ipapi
12 12 import glob,os,shlex,sys
13 13 import inspect
14 14 from time import time
15 15 ip = IPython.ipapi.get()
16 16
17 17 try:
18 18 set
19 19 except:
20 20 from sets import Set as set
21 21
22 22 TIMEOUT_STORAGE = 3 #Time in seconds after which the rootmodules will be stored
23 23 TIMEOUT_GIVEUP = 20 #Time in seconds after which we give up
24 24
25 25 def quick_completer(cmd, completions):
26 26 """ Easily create a trivial completer for a command.
27 27
28 28 Takes either a list of completions, or all completions in string
29 29 (that will be split on whitespace)
30 30
31 31 Example::
32 32
33 33 [d:\ipython]|1> import ipy_completers
34 34 [d:\ipython]|2> ipy_completers.quick_completer('foo', ['bar','baz'])
35 35 [d:\ipython]|3> foo b<TAB>
36 36 bar baz
37 37 [d:\ipython]|3> foo ba
38 38 """
39 39 if isinstance(completions, basestring):
40 40
41 41 completions = completions.split()
42 42 def do_complete(self,event):
43 43 return completions
44 44
45 45 ip.set_hook('complete_command',do_complete, str_key = cmd)
46 46
47 47 def getRootModules():
48 48 """
49 49 Returns a list containing the names of all the modules available in the
50 50 folders of the pythonpath.
51 51 """
52 52 modules = []
53 53 if ip.db.has_key('rootmodules'):
54 54 return ip.db['rootmodules']
55 55 t = time()
56 56 store = False
57 57 for path in sys.path:
58 58 modules += moduleList(path)
59 59 if time() - t >= TIMEOUT_STORAGE and not store:
60 60 store = True
61 61 print "\nCaching the list of root modules, please wait!"
62 62 print "(This will only be done once - type '%rehashx' to " + \
63 63 "reset cache!)"
64 64 print
65 65 if time() - t > TIMEOUT_GIVEUP:
66 66 print "This is taking too long, we give up."
67 67 print
68 68 ip.db['rootmodules'] = []
69 69 return []
70 70
71 71 modules += sys.builtin_module_names
72 72
73 73 modules = list(set(modules))
74 74 if '__init__' in modules:
75 75 modules.remove('__init__')
76 76 modules = list(set(modules))
77 77 if store:
78 78 ip.db['rootmodules'] = modules
79 79 return modules
80 80
81 81 def moduleList(path):
82 82 """
83 83 Return the list containing the names of the modules available in the given
84 84 folder.
85 85 """
86 86
87 87 if os.path.isdir(path):
88 88 folder_list = os.listdir(path)
89 89 else:
90 90 folder_list = []
91 91 #folder_list = glob.glob(os.path.join(path,'*'))
92 92 folder_list = [p for p in folder_list \
93 93 if os.path.exists(os.path.join(path, p,'__init__.py'))\
94 94 or p[-3:] in ('.py','.so')\
95 95 or p[-4:] in ('.pyc','.pyo')]
96 96
97 97 folder_list = [os.path.basename(p).split('.')[0] for p in folder_list]
98 98 return folder_list
99 99
100 100 def moduleCompletion(line):
101 101 """
102 102 Returns a list containing the completion possibilities for an import line.
103 103 The line looks like this :
104 104 'import xml.d'
105 105 'from xml.dom import'
106 106 """
107 107 def tryImport(mod, only_modules=False):
108 108 def isImportable(module, attr):
109 109 if only_modules:
110 110 return inspect.ismodule(getattr(module, attr))
111 111 else:
112 112 return not(attr[:2] == '__' and attr[-2:] == '__')
113 113 try:
114 114 m = __import__(mod)
115 115 except:
116 116 return []
117 117 mods = mod.split('.')
118 118 for module in mods[1:]:
119 119 m = getattr(m,module)
120 120 if (not hasattr(m, '__file__')) or (not only_modules) or\
121 121 (hasattr(m, '__file__') and '__init__' in m.__file__):
122 122 completion_list = [attr for attr in dir(m) if isImportable(m, attr)]
123 123 completion_list.extend(getattr(m,'__all__',[]))
124 124 if hasattr(m, '__file__') and '__init__' in m.__file__:
125 125 completion_list.extend(moduleList(os.path.dirname(m.__file__)))
126 126 completion_list = list(set(completion_list))
127 127 if '__init__' in completion_list:
128 128 completion_list.remove('__init__')
129 129 return completion_list
130 130
131 131 words = line.split(' ')
132 132 if len(words) == 3 and words[0] == 'from':
133 133 return ['import ']
134 134 if len(words) < 3 and (words[0] in ['import','from']) :
135 135 if len(words) == 1:
136 136 return getRootModules()
137 137 mod = words[1].split('.')
138 138 if len(mod) < 2:
139 139 return getRootModules()
140 140 completion_list = tryImport('.'.join(mod[:-1]), True)
141 141 completion_list = ['.'.join(mod[:-1] + [el]) for el in completion_list]
142 142 return completion_list
143 143 if len(words) >= 3 and words[0] == 'from':
144 144 mod = words[1]
145 145 return tryImport(mod)
146 146
147 147 def vcs_completer(commands, event):
148 148 """ utility to make writing typical version control app completers easier
149 149
150 150 VCS command line apps typically have the format:
151 151
152 152 [sudo ]PROGNAME [help] [command] file file...
153 153
154 154 """
155 155
156 156
157 157 cmd_param = event.line.split()
158 158 if event.line.endswith(' '):
159 159 cmd_param.append('')
160 160
161 161 if cmd_param[0] == 'sudo':
162 162 cmd_param = cmd_param[1:]
163 163
164 164 if len(cmd_param) == 2 or 'help' in cmd_param:
165 165 return commands.split()
166 166
167 167 return ip.IP.Completer.file_matches(event.symbol)
168 168
169 169
170 170 pkg_cache = None
171 171
172 172 def module_completer(self,event):
173 173 """ Give completions after user has typed 'import ...' or 'from ...'"""
174 174
175 175 # This works in all versions of python. While 2.5 has
176 176 # pkgutil.walk_packages(), that particular routine is fairly dangerous,
177 177 # since it imports *EVERYTHING* on sys.path. That is: a) very slow b) full
178 178 # of possibly problematic side effects.
179 179 # This search the folders in the sys.path for available modules.
180 180
181 181 return moduleCompletion(event.line)
182 182
183 183
184 184 svn_commands = """\
185 185 add blame praise annotate ann cat checkout co cleanup commit ci copy
186 186 cp delete del remove rm diff di export help ? h import info list ls
187 187 lock log merge mkdir move mv rename ren propdel pdel pd propedit pedit
188 188 pe propget pget pg proplist plist pl propset pset ps resolved revert
189 189 status stat st switch sw unlock update
190 190 """
191 191
192 192 def svn_completer(self,event):
193 193 return vcs_completer(svn_commands, event)
194 194
195 195
196 196 hg_commands = """
197 197 add addremove annotate archive backout branch branches bundle cat
198 198 clone commit copy diff export grep heads help identify import incoming
199 199 init locate log manifest merge outgoing parents paths pull push
200 200 qapplied qclone qcommit qdelete qdiff qfold qguard qheader qimport
201 201 qinit qnew qnext qpop qprev qpush qrefresh qrename qrestore qsave
202 202 qselect qseries qtop qunapplied recover remove rename revert rollback
203 203 root serve showconfig status strip tag tags tip unbundle update verify
204 204 version
205 205 """
206 206
207 207 def hg_completer(self,event):
208 208 """ Completer for mercurial commands """
209 209
210 210 return vcs_completer(hg_commands, event)
211 211
212 212
213 213
214 bzr_commands = """
215 add annotate bind branch break-lock bundle-revisions cat check
216 checkout commit conflicts deleted diff export gannotate gbranch
217 gcommit gdiff help ignore ignored info init init-repository inventory
218 log merge missing mkdir mv nick pull push reconcile register-branch
219 remerge remove renames resolve revert revno root serve sign-my-commits
220 status testament unbind uncommit unknowns update upgrade version
221 version-info visualise whoami
222 """
214 def bzr_commands():
215 out = os.popen('bzr help commands')
216 return [l.split()[0] for l in out]
217
223 218
224 219 def bzr_completer(self,event):
225 220 """ Completer for bazaar commands """
226 221 cmd_param = event.line.split()
227 222 if event.line.endswith(' '):
228 223 cmd_param.append('')
229 224
230 225 if len(cmd_param) > 2:
231 226 cmd = cmd_param[1]
232 227 param = cmd_param[-1]
233 228 output_file = (param == '--output=')
234 229 if cmd == 'help':
235 return bzr_commands.split()
230 return bzr_commands()
236 231 elif cmd in ['bundle-revisions','conflicts',
237 232 'deleted','nick','register-branch',
238 233 'serve','unbind','upgrade','version',
239 234 'whoami'] and not output_file:
240 235 return []
241 236 else:
242 237 # the rest are probably file names
243 238 return ip.IP.Completer.file_matches(event.symbol)
244 239
245 return bzr_commands.split()
240 return bzr_commands()
246 241
247 242
248 243 def shlex_split(x):
249 244 """Helper function to split lines into segments."""
250 245 #shlex.split raise exception if syntax error in sh syntax
251 246 #for example if no closing " is found. This function keeps dropping
252 247 #the last character of the line until shlex.split does not raise
253 248 #exception. Adds end of the line to the result of shlex.split
254 249 #example: %run "c:/python -> ['%run','"c:/python']
255 250 endofline=[]
256 251 while x!="":
257 252 try:
258 253 comps=shlex.split(x)
259 254 if len(endofline)>=1:
260 255 comps.append("".join(endofline))
261 256 return comps
262 257 except ValueError:
263 258 endofline=[x[-1:]]+endofline
264 259 x=x[:-1]
265 260 return ["".join(endofline)]
266 261
267 262 def runlistpy(self, event):
268 263 comps = shlex_split(event.line)
269 264 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
270 265
271 266 #print "\nev=",event # dbg
272 267 #print "rp=",relpath # dbg
273 268 #print 'comps=',comps # dbg
274 269
275 270 lglob = glob.glob
276 271 isdir = os.path.isdir
277 272 if relpath.startswith('~'):
278 273 relpath = os.path.expanduser(relpath)
279 274 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
280 275 if isdir(f)]
281 276
282 277 # Find if the user has already typed the first filename, after which we
283 278 # should complete on all files, since after the first one other files may
284 279 # be arguments to the input script.
285 280 #filter(
286 281 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or
287 282 f.endswith('.pyw'),comps):
288 283 pys = [f.replace('\\','/') for f in lglob('*')]
289 284 else:
290 285 pys = [f.replace('\\','/')
291 286 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
292 287 lglob(relpath + '*.pyw')]
293 288 return dirs + pys
294 289
295 290
296 291 def cd_completer(self, event):
297 292 relpath = event.symbol
298 293 #print event # dbg
299 294 if '-b' in event.line:
300 295 # return only bookmark completions
301 296 bkms = self.db.get('bookmarks',{})
302 297 return bkms.keys()
303 298
304 299
305 300 if event.symbol == '-':
306 301 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
307 302 # jump in directory history by number
308 303 fmt = '-%0' + width_dh +'d [%s]'
309 304 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
310 305 if len(ents) > 1:
311 306 return ents
312 307 return []
313 308
314 309 if relpath.startswith('~'):
315 310 relpath = os.path.expanduser(relpath).replace('\\','/')
316 311 found = []
317 312 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
318 313 if os.path.isdir(f)]:
319 314 if ' ' in d:
320 315 # we don't want to deal with any of that, complex code
321 316 # for this is elsewhere
322 317 raise IPython.ipapi.TryNext
323 318 found.append( d )
324 319
325 320 if not found:
326 321 if os.path.isdir(relpath):
327 322 return [relpath]
328 323 raise IPython.ipapi.TryNext
329 324 return found
330 325
331 326 def apt_get_packages(prefix):
332 327 out = os.popen('apt-cache pkgnames')
333 328 for p in out:
334 329 if p.startswith(prefix):
335 330 yield p.rstrip()
336 331
337 332
338 333 apt_commands = """\
339 334 update upgrade install remove purge source build-dep dist-upgrade
340 335 dselect-upgrade clean autoclean check"""
341 336
342 337 def apt_completer(self, event):
343 338 """ Completer for apt-get (uses apt-cache internally)
344 339
345 340 """
346 341
347 342
348 343 cmd_param = event.line.split()
349 344 if event.line.endswith(' '):
350 345 cmd_param.append('')
351 346
352 347 if cmd_param[0] == 'sudo':
353 348 cmd_param = cmd_param[1:]
354 349
355 350 if len(cmd_param) == 2 or 'help' in cmd_param:
356 351 return apt_commands.split()
357 352
358 353 return list(apt_get_packages(event.symbol))
359 354
General Comments 0
You need to be logged in to leave comments. Login now