11" pythoncomplete.vim - Omni Completion for python
22" Maintainer: Aaron Griffin <[email protected] >3- " Version: 0.8
4- " Last Updated: 8 Oct 2007
3+ " Version: 0.9
4+ " Last Updated: 18 Jun 2009
55"
66" Changes
77" TODO:
8- " User defined docstrings aren't handled right...
98" 'info' item output can use some formatting work
109" Add an "unsafe eval" mode, to allow for return type evaluation
1110" Complete basic syntax along with import statements
1211" i.e. "import url<c-x,c-o>"
1312" Continue parsing on invalid line??
1413"
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+ "
1520" v 0.8
1621" * Fixed an issue where the FIRST assignment was always used instead of
1722" using a subsequent assignment for a variable
@@ -69,7 +74,7 @@ function! pythoncomplete#Complete(findstart, base)
6974 while idx > 0
7075 let idx -= 1
7176 let c = line [idx]
72- if c = ~ ' \w' || c = ~ ' \.' || c == ' ( '
77+ if c = ~ ' \w' || c = ~ ' \.'
7378 let cword = c . cword
7479 continue
7580 elseif strlen (cword) > 0 || idx == 0
@@ -212,7 +217,7 @@ class Completer(object):
212217 if len (stmt) > 0 and stmt[-1 ] == ' (' :
213218 result = eval (_sanitize (stmt[:-1 ]), self .compldict)
214219 doc = result.__doc__
215- if doc == None: doc = ' '
220+ if doc is None: doc = ' '
216221 args = self .get_arguments (result)
217222 return [{' word' :self ._cleanstr (args ),' info' :self ._cleanstr (doc)}]
218223 elif ridx == -1 :
@@ -229,18 +234,18 @@ class Completer(object):
229234
230235 try : maindoc = result.__doc__
231236 except: maindoc = ' '
232- if maindoc == None: maindoc = ' '
237+ if maindoc is None: maindoc = ' '
233238 for m in all :
234239 if m == " _PyCmplNoType" : continue #this is internal
235240 try :
236241 dbg (' possible completion: %s' % m )
237242 if m .find (match ) == 0 :
238- if result == None: inst = all [m ]
243+ if result is None: inst = all [m ]
239244 else : inst = getattr (result,m )
240245 try : doc = inst.__doc__
241246 except: doc = maindoc
242247 typestr = str (inst)
243- if doc == None or doc == ' ' : doc = maindoc
248+ if doc is None or doc == ' ' : doc = maindoc
244249
245250 wrd = m [len (match ):]
246251 c = {' word' :wrd, ' abbr' :m , ' info' :self ._cleanstr (doc)}
@@ -266,9 +271,9 @@ class Completer(object):
266271 return []
267272
268273class Scope (object):
269- def __init__ (self ,name,indent ):
274+ def __init__ (self ,name,indent ,docstr = ' ' ):
270275 self .subscopes = []
271- self .docstr = ' '
276+ self .docstr = docstr
272277 self .locals = []
273278 self .parent = None
274279 self .name = name
@@ -287,6 +292,7 @@ class Scope(object):
287292 while d .find (' ' ) > -1 : d = d .replace (' ' ,' ' )
288293 while d [0 ] in ' "\' \t ': d = d [1 :]
289294 while d [-1 ] in ' "\' \t ': d = d [:-1 ]
295+ dbg (" Scope(%s)::docstr = %s" % (self ,d ))
290296 self .docstr = d
291297
292298 def local (self ,loc ):
@@ -295,7 +301,7 @@ class Scope(object):
295301
296302 def copy_decl (self ,indent = 0 ):
297303 " "" Copy a scope's declaration only, at the specified indent level - not local variables """
298- return Scope (self .name,indent )
304+ return Scope (self .name,indent , self .docstr )
299305
300306 def _checkexisting (self ,test):
301307 " Convienance function... keep out duplicates"
@@ -306,9 +312,8 @@ class Scope(object):
306312 self .locals.remove (l )
307313
308314 def get_code (self ):
309- # we need to start with this, to fix up broken completions
310- # hopefully this name is unique enough...
311- str = ' """' + self .docstr+ ' """\n'
315+ str = " "
316+ if len (self .docstr) > 0 : str += ' """' + self .docstr+ ' """\n'
312317 for l in self .locals:
313318 if l .startswith (' import' ): str += l + ' \n'
314319 str += ' class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
@@ -335,11 +340,11 @@ class Scope(object):
335340 return ' ' * (self .indent + 1 )
336341
337342class Class (Scope):
338- def __init__ (self , name, supers, indent ):
339- Scope.__init__ (self ,name,indent )
343+ def __init__ (self , name, supers, indent , docstr = ' ' ):
344+ Scope.__init__ (self ,name,indent , docstr )
340345 self .supers = supers
341346 def copy_decl (self ,indent = 0 ):
342- c = Class (self .name,self .supers,indent )
347+ c = Class (self .name,self .supers,indent , self .docstr )
343348 for s in self .subscopes:
344349 c .add (s .copy_decl (indent + 1 ))
345350 return c
@@ -356,11 +361,11 @@ class Class(Scope):
356361
357362
358363class Function (Scope):
359- def __init__ (self , name, params, indent ):
360- Scope.__init__ (self ,name,indent )
364+ def __init__ (self , name, params, indent , docstr = ' ' ):
365+ Scope.__init__ (self ,name,indent , docstr )
361366 self .params = params
362367 def copy_decl (self ,indent = 0 ):
363- return Function (self .name,self .params,indent )
368+ return Function (self .name,self .params,indent , self .docstr )
364369 def get_code (self ):
365370 str = " %sdef %s(%s):\n " % \
366371 (self .currentindent (),self .name,' ,' .join (self .params))
@@ -376,7 +381,7 @@ class PyParser:
376381 def _parsedotname (self ,pre = None):
377382 #returns (dottedname, nexttoken)
378383 name = []
379- if pre == None:
384+ if pre is None:
380385 tokentype, token, indent = self .next ()
381386 if tokentype != NAME and token != ' *' :
382387 return (' ' , token)
@@ -410,17 +415,20 @@ class PyParser:
410415 while True:
411416 tokentype, token, indent = self .next ()
412417 if token in (' )' , ' ,' ) and level == 1 :
413- names.append (name)
418+ if ' =' not in name: name = name.replace (' ' , ' ' )
419+ names.append (name.strip ())
414420 name = ' '
415421 if token == ' (' :
416422 level += 1
423+ name += " ("
417424 elif token == ' )' :
418425 level -= 1
419426 if level == 0 : break
427+ else : name += " )"
420428 elif token == ' ,' and level == 1 :
421429 pass
422430 else :
423- name += str (token)
431+ name += " %s " % str (token)
424432 return names
425433
426434 def _parsefunction (self ,indent ):
@@ -500,17 +508,26 @@ class PyParser:
500508 #Handle ' self' params
501509 if scp .parent != None and type (scp .parent) == Class:
502510 slice = 1
503- p = scp .params[0 ]
504- i = p .find (' =' )
505- if i != -1 : p = p [:i ]
506511 newscope.local (' %s = %s' % (scp .params[0 ],scp .parent.name))
507512 for p in scp .params[slice :]:
508513 i = p .find (' =' )
509514 if len (p ) == 0 : continue
515+ pvar = ' '
516+ ptype = ' '
510517 if i == -1 :
511- newscope.local (' %s = _PyCmplNoType()' % p )
518+ pvar = p
519+ ptype = ' _PyCmplNoType()'
512520 else :
513- 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))
514531
515532 for s in scp .subscopes:
516533 ns = s .copy_decl (0 )
@@ -538,17 +555,19 @@ class PyParser:
538555 self .scope = self .scope.pop (indent )
539556 elif token == ' def' :
540557 func = self ._parsefunction (indent )
541- if func == None:
558+ if func is None:
542559 print " function: syntax error..."
543560 continue
561+ dbg (" new scope: function" )
544562 freshscope = True
545563 self .scope = self .scope.add (func )
546564 elif token == ' class' :
547565 cls = self ._parseclass (indent )
548- if cls == None:
566+ if cls is None:
549567 print " class: syntax error..."
550568 continue
551569 freshscope = True
570+ dbg (" new scope: class" )
552571 self .scope = self .scope.add (cls)
553572
554573 elif token == ' import' :
0 commit comments