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