##// END OF EJS Templates
.pyw support for %run completer
vivainio -
Show More
@@ -1,357 +1,359 b''
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 214 bzr_commands = """
215 215 add annotate bind branch break-lock bundle-revisions cat check
216 216 checkout commit conflicts deleted diff export gannotate gbranch
217 217 gcommit gdiff help ignore ignored info init init-repository inventory
218 218 log merge missing mkdir mv nick pull push reconcile register-branch
219 219 remerge remove renames resolve revert revno root serve sign-my-commits
220 220 status testament unbind uncommit unknowns update upgrade version
221 221 version-info visualise whoami
222 222 """
223 223
224 224 def bzr_completer(self,event):
225 225 """ Completer for bazaar commands """
226 226 cmd_param = event.line.split()
227 227 if event.line.endswith(' '):
228 228 cmd_param.append('')
229 229
230 230 if len(cmd_param) > 2:
231 231 cmd = cmd_param[1]
232 232 param = cmd_param[-1]
233 233 output_file = (param == '--output=')
234 234 if cmd == 'help':
235 235 return bzr_commands.split()
236 236 elif cmd in ['bundle-revisions','conflicts',
237 237 'deleted','nick','register-branch',
238 238 'serve','unbind','upgrade','version',
239 239 'whoami'] and not output_file:
240 240 return []
241 241 else:
242 242 # the rest are probably file names
243 243 return ip.IP.Completer.file_matches(event.symbol)
244 244
245 245 return bzr_commands.split()
246 246
247 247
248 248 def shlex_split(x):
249 249 """Helper function to split lines into segments."""
250 250 #shlex.split raise exception if syntax error in sh syntax
251 251 #for example if no closing " is found. This function keeps dropping
252 252 #the last character of the line until shlex.split does not raise
253 253 #exception. Adds end of the line to the result of shlex.split
254 254 #example: %run "c:/python -> ['%run','"c:/python']
255 255 endofline=[]
256 256 while x!="":
257 257 try:
258 258 comps=shlex.split(x)
259 259 if len(endofline)>=1:
260 260 comps.append("".join(endofline))
261 261 return comps
262 262 except ValueError:
263 263 endofline=[x[-1:]]+endofline
264 264 x=x[:-1]
265 265 return ["".join(endofline)]
266 266
267 267 def runlistpy(self, event):
268 268 comps = shlex_split(event.line)
269 269 relpath = (len(comps) > 1 and comps[-1] or '').strip("'\"")
270 270
271 271 #print "\nev=",event # dbg
272 272 #print "rp=",relpath # dbg
273 273 #print 'comps=',comps # dbg
274 274
275 275 lglob = glob.glob
276 276 isdir = os.path.isdir
277 277 if relpath.startswith('~'):
278 278 relpath = os.path.expanduser(relpath)
279 279 dirs = [f.replace('\\','/') + "/" for f in lglob(relpath+'*')
280 280 if isdir(f)]
281 281
282 282 # Find if the user has already typed the first filename, after which we
283 283 # should complete on all files, since after the first one other files may
284 284 # be arguments to the input script.
285 285 #filter(
286 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy'),comps):
286 if filter(lambda f: f.endswith('.py') or f.endswith('.ipy') or
287 f.endswith('.pyw'),comps):
287 288 pys = [f.replace('\\','/') for f in lglob('*')]
288 289 else:
289 290 pys = [f.replace('\\','/')
290 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy')]
291 for f in lglob(relpath+'*.py') + lglob(relpath+'*.ipy') +
292 lglob(relpath + '*.pyw')]
291 293 return dirs + pys
292 294
293 295
294 296 def cd_completer(self, event):
295 297 relpath = event.symbol
296 298 #print event # dbg
297 299 if '-b' in event.line:
298 300 # return only bookmark completions
299 301 bkms = self.db.get('bookmarks',{})
300 302 return bkms.keys()
301 303
302 304
303 305 if event.symbol == '-':
304 306 width_dh = str(len(str(len(ip.user_ns['_dh']) + 1)))
305 307 # jump in directory history by number
306 308 fmt = '-%0' + width_dh +'d [%s]'
307 309 ents = [ fmt % (i,s) for i,s in enumerate(ip.user_ns['_dh'])]
308 310 if len(ents) > 1:
309 311 return ents
310 312 return []
311 313
312 314 if relpath.startswith('~'):
313 315 relpath = os.path.expanduser(relpath).replace('\\','/')
314 316 found = []
315 317 for d in [f.replace('\\','/') + '/' for f in glob.glob(relpath+'*')
316 318 if os.path.isdir(f)]:
317 319 if ' ' in d:
318 320 # we don't want to deal with any of that, complex code
319 321 # for this is elsewhere
320 322 raise IPython.ipapi.TryNext
321 323 found.append( d )
322 324
323 325 if not found:
324 326 if os.path.isdir(relpath):
325 327 return [relpath]
326 328 raise IPython.ipapi.TryNext
327 329 return found
328 330
329 331 def apt_get_packages(prefix):
330 332 out = os.popen('apt-cache pkgnames')
331 333 for p in out:
332 334 if p.startswith(prefix):
333 335 yield p.rstrip()
334 336
335 337
336 338 apt_commands = """\
337 339 update upgrade install remove purge source build-dep dist-upgrade
338 340 dselect-upgrade clean autoclean check"""
339 341
340 342 def apt_completer(self, event):
341 343 """ Completer for apt-get (uses apt-cache internally)
342 344
343 345 """
344 346
345 347
346 348 cmd_param = event.line.split()
347 349 if event.line.endswith(' '):
348 350 cmd_param.append('')
349 351
350 352 if cmd_param[0] == 'sudo':
351 353 cmd_param = cmd_param[1:]
352 354
353 355 if len(cmd_param) == 2 or 'help' in cmd_param:
354 356 return apt_commands.split()
355 357
356 358 return list(apt_get_packages(event.symbol))
357 359
General Comments 0
You need to be logged in to leave comments. Login now