Mercurial > vim
comparison runtime/autoload/pythoncomplete.vim @ 2120:f63ace015c63
Updated runtime and language files.
author | Bram Moolenaar <bram@zimbu.org> |
---|---|
date | Wed, 17 Mar 2010 20:02:06 +0100 |
parents | e63691e7c504 |
children | ffad29dc7eee |
comparison
equal
deleted
inserted
replaced
2119:111554354870 | 2120:f63ace015c63 |
---|---|
1 "pythoncomplete.vim - Omni Completion for python | 1 "pythoncomplete.vim - Omni Completion for python |
2 " Maintainer: Aaron Griffin <aaronmgriffin@gmail.com> | 2 " Maintainer: Aaron Griffin <aaronmgriffin@gmail.com> |
3 " Version: 0.7 | 3 " Version: 0.9 |
4 " Last Updated: 19 Oct 2006 | 4 " Last Updated: 18 Jun 2009 |
5 " | 5 " |
6 " Changes | 6 " Changes |
7 " TODO: | 7 " TODO: |
8 " User defined docstrings aren't handled right... | |
9 " 'info' item output can use some formatting work | 8 " 'info' item output can use some formatting work |
10 " Add an "unsafe eval" mode, to allow for return type evaluation | 9 " Add an "unsafe eval" mode, to allow for return type evaluation |
11 " Complete basic syntax along with import statements | 10 " Complete basic syntax along with import statements |
12 " i.e. "import url<c-x,c-o>" | 11 " i.e. "import url<c-x,c-o>" |
13 " Continue parsing on invalid line?? | 12 " Continue parsing on invalid line?? |
13 " | |
14 " v 0.9 | |
15 " * Fixed docstring parsing for classes and functions | |
16 " * Fixed parsing of *args and **kwargs type arguments | |
17 " * Better function param parsing to handle things like tuples and | |
18 " lambda defaults args | |
19 " | |
20 " v 0.8 | |
21 " * Fixed an issue where the FIRST assignment was always used instead of | |
22 " using a subsequent assignment for a variable | |
23 " * Fixed a scoping issue when working inside a parameterless function | |
24 " | |
14 " | 25 " |
15 " v 0.7 | 26 " v 0.7 |
16 " * Fixed function list sorting (_ and __ at the bottom) | 27 " * Fixed function list sorting (_ and __ at the bottom) |
17 " * Removed newline removal from docs. It appears vim handles these better in | 28 " * Removed newline removal from docs. It appears vim handles these better in |
18 " recent patches | 29 " recent patches |
61 let idx = col('.') | 72 let idx = col('.') |
62 let cword = '' | 73 let cword = '' |
63 while idx > 0 | 74 while idx > 0 |
64 let idx -= 1 | 75 let idx -= 1 |
65 let c = line[idx] | 76 let c = line[idx] |
66 if c =~ '\w' || c =~ '\.' || c == '(' | 77 if c =~ '\w' || c =~ '\.' |
67 let cword = c . cword | 78 let cword = c . cword |
68 continue | 79 continue |
69 elseif strlen(cword) > 0 || idx == 0 | 80 elseif strlen(cword) > 0 || idx == 0 |
70 break | 81 break |
71 endif | 82 endif |
204 all = {} | 215 all = {} |
205 ridx = stmt.rfind('.') | 216 ridx = stmt.rfind('.') |
206 if len(stmt) > 0 and stmt[-1] == '(': | 217 if len(stmt) > 0 and stmt[-1] == '(': |
207 result = eval(_sanitize(stmt[:-1]), self.compldict) | 218 result = eval(_sanitize(stmt[:-1]), self.compldict) |
208 doc = result.__doc__ | 219 doc = result.__doc__ |
209 if doc == None: doc = '' | 220 if doc is None: doc = '' |
210 args = self.get_arguments(result) | 221 args = self.get_arguments(result) |
211 return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}] | 222 return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}] |
212 elif ridx == -1: | 223 elif ridx == -1: |
213 match = stmt | 224 match = stmt |
214 all = self.compldict | 225 all = self.compldict |
221 dbg("completing: stmt:%s" % stmt) | 232 dbg("completing: stmt:%s" % stmt) |
222 completions = [] | 233 completions = [] |
223 | 234 |
224 try: maindoc = result.__doc__ | 235 try: maindoc = result.__doc__ |
225 except: maindoc = ' ' | 236 except: maindoc = ' ' |
226 if maindoc == None: maindoc = ' ' | 237 if maindoc is None: maindoc = ' ' |
227 for m in all: | 238 for m in all: |
228 if m == "_PyCmplNoType": continue #this is internal | 239 if m == "_PyCmplNoType": continue #this is internal |
229 try: | 240 try: |
230 dbg('possible completion: %s' % m) | 241 dbg('possible completion: %s' % m) |
231 if m.find(match) == 0: | 242 if m.find(match) == 0: |
232 if result == None: inst = all[m] | 243 if result is None: inst = all[m] |
233 else: inst = getattr(result,m) | 244 else: inst = getattr(result,m) |
234 try: doc = inst.__doc__ | 245 try: doc = inst.__doc__ |
235 except: doc = maindoc | 246 except: doc = maindoc |
236 typestr = str(inst) | 247 typestr = str(inst) |
237 if doc == None or doc == '': doc = maindoc | 248 if doc is None or doc == '': doc = maindoc |
238 | 249 |
239 wrd = m[len(match):] | 250 wrd = m[len(match):] |
240 c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)} | 251 c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)} |
241 if "function" in typestr: | 252 if "function" in typestr: |
242 c['word'] += '(' | 253 c['word'] += '(' |
258 i = sys.exc_info() | 269 i = sys.exc_info() |
259 dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) | 270 dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) |
260 return [] | 271 return [] |
261 | 272 |
262 class Scope(object): | 273 class Scope(object): |
263 def __init__(self,name,indent): | 274 def __init__(self,name,indent,docstr=''): |
264 self.subscopes = [] | 275 self.subscopes = [] |
265 self.docstr = '' | 276 self.docstr = docstr |
266 self.locals = [] | 277 self.locals = [] |
267 self.parent = None | 278 self.parent = None |
268 self.name = name | 279 self.name = name |
269 self.indent = indent | 280 self.indent = indent |
270 | 281 |
279 d = str.replace('\n',' ') | 290 d = str.replace('\n',' ') |
280 d = d.replace('\t',' ') | 291 d = d.replace('\t',' ') |
281 while d.find(' ') > -1: d = d.replace(' ',' ') | 292 while d.find(' ') > -1: d = d.replace(' ',' ') |
282 while d[0] in '"\'\t ': d = d[1:] | 293 while d[0] in '"\'\t ': d = d[1:] |
283 while d[-1] in '"\'\t ': d = d[:-1] | 294 while d[-1] in '"\'\t ': d = d[:-1] |
295 dbg("Scope(%s)::docstr = %s" % (self,d)) | |
284 self.docstr = d | 296 self.docstr = d |
285 | 297 |
286 def local(self,loc): | 298 def local(self,loc): |
287 if not self._hasvaralready(loc): | 299 self._checkexisting(loc) |
288 self.locals.append(loc) | 300 self.locals.append(loc) |
289 | 301 |
290 def copy_decl(self,indent=0): | 302 def copy_decl(self,indent=0): |
291 """ Copy a scope's declaration only, at the specified indent level - not local variables """ | 303 """ Copy a scope's declaration only, at the specified indent level - not local variables """ |
292 return Scope(self.name,indent) | 304 return Scope(self.name,indent,self.docstr) |
293 | 305 |
294 def _hasvaralready(self,test): | 306 def _checkexisting(self,test): |
295 "Convienance function... keep out duplicates" | 307 "Convienance function... keep out duplicates" |
296 if test.find('=') > -1: | 308 if test.find('=') > -1: |
297 var = test.split('=')[0].strip() | 309 var = test.split('=')[0].strip() |
298 for l in self.locals: | 310 for l in self.locals: |
299 if l.find('=') > -1 and var == l.split('=')[0].strip(): | 311 if l.find('=') > -1 and var == l.split('=')[0].strip(): |
300 return True | 312 self.locals.remove(l) |
301 return False | |
302 | 313 |
303 def get_code(self): | 314 def get_code(self): |
304 # we need to start with this, to fix up broken completions | 315 str = "" |
305 # hopefully this name is unique enough... | 316 if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n' |
306 str = '"""'+self.docstr+'"""\n' | |
307 for l in self.locals: | 317 for l in self.locals: |
308 if l.startswith('import'): str += l+'\n' | 318 if l.startswith('import'): str += l+'\n' |
309 str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' | 319 str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' |
310 for sub in self.subscopes: | 320 for sub in self.subscopes: |
311 str += sub.get_code() | 321 str += sub.get_code() |
328 def childindent(self): | 338 def childindent(self): |
329 #print 'parse child indent: [%s]' % (self.indent+1) | 339 #print 'parse child indent: [%s]' % (self.indent+1) |
330 return ' '*(self.indent+1) | 340 return ' '*(self.indent+1) |
331 | 341 |
332 class Class(Scope): | 342 class Class(Scope): |
333 def __init__(self, name, supers, indent): | 343 def __init__(self, name, supers, indent, docstr=''): |
334 Scope.__init__(self,name,indent) | 344 Scope.__init__(self,name,indent, docstr) |
335 self.supers = supers | 345 self.supers = supers |
336 def copy_decl(self,indent=0): | 346 def copy_decl(self,indent=0): |
337 c = Class(self.name,self.supers,indent) | 347 c = Class(self.name,self.supers,indent, self.docstr) |
338 for s in self.subscopes: | 348 for s in self.subscopes: |
339 c.add(s.copy_decl(indent+1)) | 349 c.add(s.copy_decl(indent+1)) |
340 return c | 350 return c |
341 def get_code(self): | 351 def get_code(self): |
342 str = '%sclass %s' % (self.currentindent(),self.name) | 352 str = '%sclass %s' % (self.currentindent(),self.name) |
349 str += '%spass\n' % self.childindent() | 359 str += '%spass\n' % self.childindent() |
350 return str | 360 return str |
351 | 361 |
352 | 362 |
353 class Function(Scope): | 363 class Function(Scope): |
354 def __init__(self, name, params, indent): | 364 def __init__(self, name, params, indent, docstr=''): |
355 Scope.__init__(self,name,indent) | 365 Scope.__init__(self,name,indent, docstr) |
356 self.params = params | 366 self.params = params |
357 def copy_decl(self,indent=0): | 367 def copy_decl(self,indent=0): |
358 return Function(self.name,self.params,indent) | 368 return Function(self.name,self.params,indent, self.docstr) |
359 def get_code(self): | 369 def get_code(self): |
360 str = "%sdef %s(%s):\n" % \ | 370 str = "%sdef %s(%s):\n" % \ |
361 (self.currentindent(),self.name,','.join(self.params)) | 371 (self.currentindent(),self.name,','.join(self.params)) |
362 if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' | 372 if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' |
363 str += "%spass\n" % self.childindent() | 373 str += "%spass\n" % self.childindent() |
369 self.scope = self.top | 379 self.scope = self.top |
370 | 380 |
371 def _parsedotname(self,pre=None): | 381 def _parsedotname(self,pre=None): |
372 #returns (dottedname, nexttoken) | 382 #returns (dottedname, nexttoken) |
373 name = [] | 383 name = [] |
374 if pre == None: | 384 if pre is None: |
375 tokentype, token, indent = self.next() | 385 tokentype, token, indent = self.next() |
376 if tokentype != NAME and token != '*': | 386 if tokentype != NAME and token != '*': |
377 return ('', token) | 387 return ('', token) |
378 else: token = pre | 388 else: token = pre |
379 name.append(token) | 389 name.append(token) |
403 names = [] | 413 names = [] |
404 level = 1 | 414 level = 1 |
405 while True: | 415 while True: |
406 tokentype, token, indent = self.next() | 416 tokentype, token, indent = self.next() |
407 if token in (')', ',') and level == 1: | 417 if token in (')', ',') and level == 1: |
408 names.append(name) | 418 if '=' not in name: name = name.replace(' ', '') |
419 names.append(name.strip()) | |
409 name = '' | 420 name = '' |
410 if token == '(': | 421 if token == '(': |
411 level += 1 | 422 level += 1 |
423 name += "(" | |
412 elif token == ')': | 424 elif token == ')': |
413 level -= 1 | 425 level -= 1 |
414 if level == 0: break | 426 if level == 0: break |
427 else: name += ")" | |
415 elif token == ',' and level == 1: | 428 elif token == ',' and level == 1: |
416 pass | 429 pass |
417 else: | 430 else: |
418 name += str(token) | 431 name += "%s " % str(token) |
419 return names | 432 return names |
420 | 433 |
421 def _parsefunction(self,indent): | 434 def _parsefunction(self,indent): |
422 self.scope=self.scope.pop(indent) | 435 self.scope=self.scope.pop(indent) |
423 tokentype, fname, ind = self.next() | 436 tokentype, fname, ind = self.next() |
493 if type(scp) == Function: | 506 if type(scp) == Function: |
494 slice = 0 | 507 slice = 0 |
495 #Handle 'self' params | 508 #Handle 'self' params |
496 if scp.parent != None and type(scp.parent) == Class: | 509 if scp.parent != None and type(scp.parent) == Class: |
497 slice = 1 | 510 slice = 1 |
498 p = scp.params[0] | |
499 i = p.find('=') | |
500 if i != -1: p = p[:i] | |
501 newscope.local('%s = %s' % (scp.params[0],scp.parent.name)) | 511 newscope.local('%s = %s' % (scp.params[0],scp.parent.name)) |
502 for p in scp.params[slice:]: | 512 for p in scp.params[slice:]: |
503 i = p.find('=') | 513 i = p.find('=') |
514 if len(p) == 0: continue | |
515 pvar = '' | |
516 ptype = '' | |
504 if i == -1: | 517 if i == -1: |
505 newscope.local('%s = _PyCmplNoType()' % p) | 518 pvar = p |
519 ptype = '_PyCmplNoType()' | |
506 else: | 520 else: |
507 newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1]))) | 521 pvar = p[:i] |
522 ptype = _sanitize(p[i+1:]) | |
523 if pvar.startswith('**'): | |
524 pvar = pvar[2:] | |
525 ptype = '{}' | |
526 elif pvar.startswith('*'): | |
527 pvar = pvar[1:] | |
528 ptype = '[]' | |
529 | |
530 newscope.local('%s = %s' % (pvar,ptype)) | |
508 | 531 |
509 for s in scp.subscopes: | 532 for s in scp.subscopes: |
510 ns = s.copy_decl(0) | 533 ns = s.copy_decl(0) |
511 newscope.add(ns) | 534 newscope.add(ns) |
512 for l in scp.locals: newscope.local(l) | 535 for l in scp.locals: newscope.local(l) |
530 | 553 |
531 if tokentype == DEDENT or token == "pass": | 554 if tokentype == DEDENT or token == "pass": |
532 self.scope = self.scope.pop(indent) | 555 self.scope = self.scope.pop(indent) |
533 elif token == 'def': | 556 elif token == 'def': |
534 func = self._parsefunction(indent) | 557 func = self._parsefunction(indent) |
535 if func == None: | 558 if func is None: |
536 print "function: syntax error..." | 559 print "function: syntax error..." |
537 continue | 560 continue |
561 dbg("new scope: function") | |
538 freshscope = True | 562 freshscope = True |
539 self.scope = self.scope.add(func) | 563 self.scope = self.scope.add(func) |
540 elif token == 'class': | 564 elif token == 'class': |
541 cls = self._parseclass(indent) | 565 cls = self._parseclass(indent) |
542 if cls == None: | 566 if cls is None: |
543 print "class: syntax error..." | 567 print "class: syntax error..." |
544 continue | 568 continue |
545 freshscope = True | 569 freshscope = True |
570 dbg("new scope: class") | |
546 self.scope = self.scope.add(cls) | 571 self.scope = self.scope.add(cls) |
547 | 572 |
548 elif token == 'import': | 573 elif token == 'import': |
549 imports = self._parseimportlist() | 574 imports = self._parseimportlist() |
550 for mod, alias in imports: | 575 for mod, alias in imports: |
567 if freshscope: self.scope.doc(token) | 592 if freshscope: self.scope.doc(token) |
568 elif tokentype == NAME: | 593 elif tokentype == NAME: |
569 name,token = self._parsedotname(token) | 594 name,token = self._parsedotname(token) |
570 if token == '=': | 595 if token == '=': |
571 stmt = self._parseassignment() | 596 stmt = self._parseassignment() |
597 dbg("parseassignment: %s = %s" % (name, stmt)) | |
572 if stmt != None: | 598 if stmt != None: |
573 self.scope.local("%s = %s" % (name,stmt)) | 599 self.scope.local("%s = %s" % (name,stmt)) |
574 freshscope = False | 600 freshscope = False |
575 except StopIteration: #thrown on EOF | 601 except StopIteration: #thrown on EOF |
576 pass | 602 pass |