blob: ecc36646d9d8affa11c344eb1ff3355761ec3b01 [file] [log] [blame]
Bram Moolenaar18144c82006-04-12 21:52:12 +00001"pythoncomplete.vim - Omni Completion for python
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00002" Maintainer: Aaron Griffin <aaronmgriffin@gmail.com>
Bram Moolenaarb52073a2010-03-17 20:02:06 +01003" Version: 0.9
4" Last Updated: 18 Jun 2009
Bram Moolenaard12f5c12006-01-25 22:10:52 +00005"
Bram Moolenaar9964e462007-05-05 17:54:07 +00006" Changes
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00007" TODO:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +00008" 'info' item output can use some formatting work
9" Add an "unsafe eval" mode, to allow for return type evaluation
Bram Moolenaar9964e462007-05-05 17:54:07 +000010" Complete basic syntax along with import statements
11" i.e. "import url<c-x,c-o>"
12" Continue parsing on invalid line??
13"
Bram Moolenaarb52073a2010-03-17 20:02:06 +010014" 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"
25"
Bram Moolenaar9964e462007-05-05 17:54:07 +000026" v 0.7
27" * Fixed function list sorting (_ and __ at the bottom)
28" * Removed newline removal from docs. It appears vim handles these better in
29" recent patches
30"
31" v 0.6:
32" * Fixed argument completion
33" * Removed the 'kind' completions, as they are better indicated
34" with real syntax
35" * Added tuple assignment parsing (whoops, that was forgotten)
36" * Fixed import handling when flattening scope
37"
38" v 0.5:
39" Yeah, I skipped a version number - 0.4 was never public.
40" It was a bugfix version on top of 0.3. This is a complete
41" rewrite.
42"
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000043
44if !has('python')
45 echo "Error: Required vim compiled with +python"
46 finish
47endif
48
Bram Moolenaar18144c82006-04-12 21:52:12 +000049function! pythoncomplete#Complete(findstart, base)
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000050 "findstart = 1 when we need to get the text length
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000051 if a:findstart == 1
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000052 let line = getline('.')
53 let idx = col('.')
54 while idx > 0
55 let idx -= 1
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000056 let c = line[idx]
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000057 if c =~ '\w'
Bram Moolenaard12f5c12006-01-25 22:10:52 +000058 continue
59 elseif ! c =~ '\.'
Bram Moolenaar9964e462007-05-05 17:54:07 +000060 let idx = -1
Bram Moolenaard12f5c12006-01-25 22:10:52 +000061 break
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000062 else
63 break
64 endif
65 endwhile
66
67 return idx
68 "findstart = 0 when we need to return the list of completions
69 else
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000070 "vim no longer moves the cursor upon completion... fix that
71 let line = getline('.')
72 let idx = col('.')
73 let cword = ''
74 while idx > 0
75 let idx -= 1
76 let c = line[idx]
Bram Moolenaarb52073a2010-03-17 20:02:06 +010077 if c =~ '\w' || c =~ '\.'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000078 let cword = c . cword
79 continue
80 elseif strlen(cword) > 0 || idx == 0
81 break
82 endif
83 endwhile
84 execute "python vimcomplete('" . cword . "', '" . a:base . "')"
Bram Moolenaar18144c82006-04-12 21:52:12 +000085 return g:pythoncomplete_completions
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000086 endif
87endfunction
88
89function! s:DefPython()
90python << PYTHONEOF
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000091import sys, tokenize, cStringIO, types
92from token import NAME, DEDENT, NEWLINE, STRING
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000093
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000094debugstmts=[]
95def dbg(s): debugstmts.append(s)
96def showdbg():
97 for d in debugstmts: print "DBG: %s " % d
Bram Moolenaara40ceaf2006-01-13 22:35:40 +000098
Bram Moolenaarfc1421e2006-04-20 22:17:20 +000099def vimcomplete(context,match):
100 global debugstmts
101 debugstmts = []
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000102 try:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000103 import vim
104 def complsort(x,y):
Bram Moolenaar9964e462007-05-05 17:54:07 +0000105 try:
106 xa = x['abbr']
107 ya = y['abbr']
108 if xa[0] == '_':
109 if xa[1] == '_' and ya[0:2] == '__':
110 return xa > ya
111 elif ya[0:2] == '__':
112 return -1
113 elif y[0] == '_':
114 return xa > ya
115 else:
116 return 1
117 elif ya[0] == '_':
118 return -1
119 else:
120 return xa > ya
121 except:
122 return 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000123 cmpl = Completer()
124 cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')"))
125 all = cmpl.get_completions(context,match)
126 all.sort(complsort)
127 dictstr = '['
128 # have to do this for double quoting
129 for cmpl in all:
130 dictstr += '{'
131 for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x])
132 dictstr += '"icase":0},'
133 if dictstr[-1] == ',': dictstr = dictstr[:-1]
134 dictstr += ']'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000135 #dbg("dict: %s" % dictstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000136 vim.command("silent let g:pythoncomplete_completions = %s" % dictstr)
137 #dbg("Completion dict:\n%s" % all)
138 except vim.error:
139 dbg("VIM Error: %s" % vim.error)
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000140
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000141class Completer(object):
142 def __init__(self):
143 self.compldict = {}
144 self.parser = PyParser()
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000145
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000146 def evalsource(self,text,line=0):
147 sc = self.parser.parse(text,line)
148 src = sc.get_code()
149 dbg("source: %s" % src)
150 try: exec(src) in self.compldict
151 except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))
152 for l in sc.locals:
153 try: exec(l) in self.compldict
154 except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000155
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000156 def _cleanstr(self,doc):
Bram Moolenaar9964e462007-05-05 17:54:07 +0000157 return doc.replace('"',' ').replace("'",' ')
Bram Moolenaard12f5c12006-01-25 22:10:52 +0000158
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000159 def get_arguments(self,func_obj):
160 def _ctor(obj):
161 try: return class_ob.__init__.im_func
162 except AttributeError:
163 for base in class_ob.__bases__:
164 rc = _find_constructor(base)
165 if rc is not None: return rc
166 return None
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000167
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000168 arg_offset = 1
169 if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj)
170 elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func
171 else: arg_offset = 0
172
Bram Moolenaar9964e462007-05-05 17:54:07 +0000173 arg_text=''
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000174 if type(func_obj) in [types.FunctionType, types.LambdaType]:
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000175 try:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000176 cd = func_obj.func_code
177 real_args = cd.co_varnames[arg_offset:cd.co_argcount]
Bram Moolenaar9964e462007-05-05 17:54:07 +0000178 defaults = func_obj.func_defaults or ''
179 defaults = map(lambda name: "=%s" % name, defaults)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000180 defaults = [""] * (len(real_args)-len(defaults)) + defaults
181 items = map(lambda a,d: a+d, real_args, defaults)
182 if func_obj.func_code.co_flags & 0x4:
183 items.append("...")
184 if func_obj.func_code.co_flags & 0x8:
185 items.append("***")
Bram Moolenaar9964e462007-05-05 17:54:07 +0000186 arg_text = (','.join(items)) + ')'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000187
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000188 except:
Bram Moolenaar9964e462007-05-05 17:54:07 +0000189 dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1]))
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000190 pass
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000191 if len(arg_text) == 0:
192 # The doc string sometimes contains the function signature
193 # this works for alot of C modules that are part of the
194 # standard library
195 doc = func_obj.__doc__
196 if doc:
197 doc = doc.lstrip()
198 pos = doc.find('\n')
199 if pos > 0:
200 sigline = doc[:pos]
201 lidx = sigline.find('(')
202 ridx = sigline.find(')')
203 if lidx > 0 and ridx > 0:
204 arg_text = sigline[lidx+1:ridx] + ')'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000205 if len(arg_text) == 0: arg_text = ')'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000206 return arg_text
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000207
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000208 def get_completions(self,context,match):
209 dbg("get_completions('%s','%s')" % (context,match))
210 stmt = ''
211 if context: stmt += str(context)
212 if match: stmt += str(match)
213 try:
214 result = None
215 all = {}
216 ridx = stmt.rfind('.')
217 if len(stmt) > 0 and stmt[-1] == '(':
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000218 result = eval(_sanitize(stmt[:-1]), self.compldict)
219 doc = result.__doc__
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100220 if doc is None: doc = ''
Bram Moolenaar9964e462007-05-05 17:54:07 +0000221 args = self.get_arguments(result)
222 return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000223 elif ridx == -1:
224 match = stmt
225 all = self.compldict
226 else:
227 match = stmt[ridx+1:]
228 stmt = _sanitize(stmt[:ridx])
229 result = eval(stmt, self.compldict)
230 all = dir(result)
231
232 dbg("completing: stmt:%s" % stmt)
233 completions = []
234
235 try: maindoc = result.__doc__
236 except: maindoc = ' '
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100237 if maindoc is None: maindoc = ' '
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000238 for m in all:
239 if m == "_PyCmplNoType": continue #this is internal
240 try:
241 dbg('possible completion: %s' % m)
242 if m.find(match) == 0:
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100243 if result is None: inst = all[m]
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000244 else: inst = getattr(result,m)
245 try: doc = inst.__doc__
246 except: doc = maindoc
247 typestr = str(inst)
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100248 if doc is None or doc == '': doc = maindoc
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000249
250 wrd = m[len(match):]
Bram Moolenaar9964e462007-05-05 17:54:07 +0000251 c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)}
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000252 if "function" in typestr:
253 c['word'] += '('
254 c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000255 elif "method" in typestr:
256 c['word'] += '('
257 c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000258 elif "module" in typestr:
259 c['word'] += '.'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000260 elif "class" in typestr:
261 c['word'] += '('
262 c['abbr'] += '('
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000263 completions.append(c)
264 except:
265 i = sys.exc_info()
266 dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
267 return completions
268 except:
269 i = sys.exc_info()
270 dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt))
271 return []
272
273class Scope(object):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100274 def __init__(self,name,indent,docstr=''):
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000275 self.subscopes = []
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100276 self.docstr = docstr
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000277 self.locals = []
278 self.parent = None
279 self.name = name
280 self.indent = indent
281
282 def add(self,sub):
283 #print 'push scope: [%s@%s]' % (sub.name,sub.indent)
284 sub.parent = self
285 self.subscopes.append(sub)
286 return sub
287
288 def doc(self,str):
289 """ Clean up a docstring """
290 d = str.replace('\n',' ')
291 d = d.replace('\t',' ')
292 while d.find(' ') > -1: d = d.replace(' ',' ')
293 while d[0] in '"\'\t ': d = d[1:]
294 while d[-1] in '"\'\t ': d = d[:-1]
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100295 dbg("Scope(%s)::docstr = %s" % (self,d))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000296 self.docstr = d
297
298 def local(self,loc):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100299 self._checkexisting(loc)
300 self.locals.append(loc)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000301
302 def copy_decl(self,indent=0):
303 """ Copy a scope's declaration only, at the specified indent level - not local variables """
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100304 return Scope(self.name,indent,self.docstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000305
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100306 def _checkexisting(self,test):
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000307 "Convienance function... keep out duplicates"
308 if test.find('=') > -1:
309 var = test.split('=')[0].strip()
310 for l in self.locals:
311 if l.find('=') > -1 and var == l.split('=')[0].strip():
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100312 self.locals.remove(l)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000313
314 def get_code(self):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100315 str = ""
316 if len(self.docstr) > 0: str += '"""'+self.docstr+'"""\n'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000317 for l in self.locals:
318 if l.startswith('import'): str += l+'\n'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000319 str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n'
320 for sub in self.subscopes:
321 str += sub.get_code()
Bram Moolenaar9964e462007-05-05 17:54:07 +0000322 for l in self.locals:
323 if not l.startswith('import'): str += l+'\n'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000324
325 return str
326
327 def pop(self,indent):
328 #print 'pop scope: [%s] to [%s]' % (self.indent,indent)
329 outer = self
330 while outer.parent != None and outer.indent >= indent:
331 outer = outer.parent
332 return outer
333
334 def currentindent(self):
335 #print 'parse current indent: %s' % self.indent
336 return ' '*self.indent
337
338 def childindent(self):
339 #print 'parse child indent: [%s]' % (self.indent+1)
340 return ' '*(self.indent+1)
341
342class Class(Scope):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100343 def __init__(self, name, supers, indent, docstr=''):
344 Scope.__init__(self,name,indent, docstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000345 self.supers = supers
346 def copy_decl(self,indent=0):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100347 c = Class(self.name,self.supers,indent, self.docstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000348 for s in self.subscopes:
349 c.add(s.copy_decl(indent+1))
350 return c
351 def get_code(self):
352 str = '%sclass %s' % (self.currentindent(),self.name)
353 if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers)
354 str += ':\n'
355 if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
356 if len(self.subscopes) > 0:
357 for s in self.subscopes: str += s.get_code()
358 else:
359 str += '%spass\n' % self.childindent()
360 return str
361
362
363class Function(Scope):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100364 def __init__(self, name, params, indent, docstr=''):
365 Scope.__init__(self,name,indent, docstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000366 self.params = params
367 def copy_decl(self,indent=0):
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100368 return Function(self.name,self.params,indent, self.docstr)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000369 def get_code(self):
370 str = "%sdef %s(%s):\n" % \
371 (self.currentindent(),self.name,','.join(self.params))
372 if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'
373 str += "%spass\n" % self.childindent()
374 return str
375
376class PyParser:
377 def __init__(self):
378 self.top = Scope('global',0)
379 self.scope = self.top
Bram Moolenaara0f849e2015-10-30 14:37:44 +0100380 self.parserline = 0
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000381
382 def _parsedotname(self,pre=None):
383 #returns (dottedname, nexttoken)
384 name = []
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100385 if pre is None:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000386 tokentype, token, indent = self.next()
387 if tokentype != NAME and token != '*':
388 return ('', token)
389 else: token = pre
390 name.append(token)
391 while True:
392 tokentype, token, indent = self.next()
393 if token != '.': break
394 tokentype, token, indent = self.next()
395 if tokentype != NAME: break
396 name.append(token)
397 return (".".join(name), token)
398
399 def _parseimportlist(self):
400 imports = []
401 while True:
402 name, token = self._parsedotname()
403 if not name: break
404 name2 = ''
405 if token == 'as': name2, token = self._parsedotname()
406 imports.append((name, name2))
407 while token != "," and "\n" not in token:
408 tokentype, token, indent = self.next()
409 if token != ",": break
410 return imports
411
412 def _parenparse(self):
413 name = ''
414 names = []
415 level = 1
416 while True:
417 tokentype, token, indent = self.next()
418 if token in (')', ',') and level == 1:
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100419 if '=' not in name: name = name.replace(' ', '')
420 names.append(name.strip())
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000421 name = ''
422 if token == '(':
423 level += 1
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100424 name += "("
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000425 elif token == ')':
426 level -= 1
427 if level == 0: break
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100428 else: name += ")"
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000429 elif token == ',' and level == 1:
430 pass
431 else:
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100432 name += "%s " % str(token)
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000433 return names
434
435 def _parsefunction(self,indent):
436 self.scope=self.scope.pop(indent)
437 tokentype, fname, ind = self.next()
438 if tokentype != NAME: return None
439
440 tokentype, open, ind = self.next()
441 if open != '(': return None
442 params=self._parenparse()
443
444 tokentype, colon, ind = self.next()
445 if colon != ':': return None
446
447 return Function(fname,params,indent)
448
449 def _parseclass(self,indent):
450 self.scope=self.scope.pop(indent)
451 tokentype, cname, ind = self.next()
452 if tokentype != NAME: return None
453
454 super = []
455 tokentype, next, ind = self.next()
456 if next == '(':
457 super=self._parenparse()
458 elif next != ':': return None
459
460 return Class(cname,super,indent)
461
462 def _parseassignment(self):
463 assign=''
464 tokentype, token, indent = self.next()
465 if tokentype == tokenize.STRING or token == 'str':
466 return '""'
Bram Moolenaar9964e462007-05-05 17:54:07 +0000467 elif token == '(' or token == 'tuple':
468 return '()'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000469 elif token == '[' or token == 'list':
470 return '[]'
471 elif token == '{' or token == 'dict':
472 return '{}'
473 elif tokentype == tokenize.NUMBER:
474 return '0'
475 elif token == 'open' or token == 'file':
476 return 'file'
477 elif token == 'None':
478 return '_PyCmplNoType()'
479 elif token == 'type':
480 return 'type(_PyCmplNoType)' #only for method resolution
481 else:
482 assign += token
483 level = 0
484 while True:
485 tokentype, token, indent = self.next()
486 if token in ('(','{','['):
487 level += 1
488 elif token in (']','}',')'):
489 level -= 1
490 if level == 0: break
491 elif level == 0:
492 if token in (';','\n'): break
493 assign += token
494 return "%s" % assign
495
496 def next(self):
497 type, token, (lineno, indent), end, self.parserline = self.gen.next()
498 if lineno == self.curline:
499 #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name)
500 self.currentscope = self.scope
501 return (type, token, indent)
502
503 def _adjustvisibility(self):
504 newscope = Scope('result',0)
505 scp = self.currentscope
506 while scp != None:
507 if type(scp) == Function:
508 slice = 0
509 #Handle 'self' params
510 if scp.parent != None and type(scp.parent) == Class:
511 slice = 1
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000512 newscope.local('%s = %s' % (scp.params[0],scp.parent.name))
513 for p in scp.params[slice:]:
514 i = p.find('=')
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100515 if len(p) == 0: continue
516 pvar = ''
517 ptype = ''
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000518 if i == -1:
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100519 pvar = p
520 ptype = '_PyCmplNoType()'
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000521 else:
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100522 pvar = p[:i]
523 ptype = _sanitize(p[i+1:])
524 if pvar.startswith('**'):
525 pvar = pvar[2:]
526 ptype = '{}'
527 elif pvar.startswith('*'):
528 pvar = pvar[1:]
529 ptype = '[]'
530
531 newscope.local('%s = %s' % (pvar,ptype))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000532
533 for s in scp.subscopes:
534 ns = s.copy_decl(0)
535 newscope.add(ns)
536 for l in scp.locals: newscope.local(l)
537 scp = scp.parent
538
539 self.currentscope = newscope
540 return self.currentscope
541
542 #p.parse(vim.current.buffer[:],vim.eval("line('.')"))
543 def parse(self,text,curline=0):
544 self.curline = int(curline)
545 buf = cStringIO.StringIO(''.join(text) + '\n')
546 self.gen = tokenize.generate_tokens(buf.readline)
547 self.currentscope = self.scope
548
549 try:
550 freshscope=True
551 while True:
552 tokentype, token, indent = self.next()
Bram Moolenaar9964e462007-05-05 17:54:07 +0000553 #dbg( 'main: token=[%s] indent=[%s]' % (token,indent))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000554
Bram Moolenaar9964e462007-05-05 17:54:07 +0000555 if tokentype == DEDENT or token == "pass":
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000556 self.scope = self.scope.pop(indent)
557 elif token == 'def':
558 func = self._parsefunction(indent)
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100559 if func is None:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000560 print "function: syntax error..."
561 continue
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100562 dbg("new scope: function")
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000563 freshscope = True
564 self.scope = self.scope.add(func)
565 elif token == 'class':
566 cls = self._parseclass(indent)
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100567 if cls is None:
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000568 print "class: syntax error..."
569 continue
570 freshscope = True
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100571 dbg("new scope: class")
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000572 self.scope = self.scope.add(cls)
573
574 elif token == 'import':
575 imports = self._parseimportlist()
576 for mod, alias in imports:
577 loc = "import %s" % mod
578 if len(alias) > 0: loc += " as %s" % alias
579 self.scope.local(loc)
580 freshscope = False
581 elif token == 'from':
582 mod, token = self._parsedotname()
583 if not mod or token != "import":
584 print "from: syntax error..."
585 continue
586 names = self._parseimportlist()
587 for name, alias in names:
588 loc = "from %s import %s" % (mod,name)
589 if len(alias) > 0: loc += " as %s" % alias
590 self.scope.local(loc)
591 freshscope = False
592 elif tokentype == STRING:
593 if freshscope: self.scope.doc(token)
594 elif tokentype == NAME:
595 name,token = self._parsedotname(token)
596 if token == '=':
597 stmt = self._parseassignment()
Bram Moolenaarb52073a2010-03-17 20:02:06 +0100598 dbg("parseassignment: %s = %s" % (name, stmt))
Bram Moolenaarfc1421e2006-04-20 22:17:20 +0000599 if stmt != None:
600 self.scope.local("%s = %s" % (name,stmt))
601 freshscope = False
602 except StopIteration: #thrown on EOF
603 pass
604 except:
605 dbg("parse error: %s, %s @ %s" %
606 (sys.exc_info()[0], sys.exc_info()[1], self.parserline))
607 return self._adjustvisibility()
608
609def _sanitize(str):
610 val = ''
611 level = 0
612 for c in str:
613 if c in ('(','{','['):
614 level += 1
615 elif c in (']','}',')'):
616 level -= 1
617 elif level == 0:
618 val += c
619 return val
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000620
621sys.path.extend(['.','..'])
622PYTHONEOF
623endfunction
624
Bram Moolenaara40ceaf2006-01-13 22:35:40 +0000625call s:DefPython()
626" vim: set et ts=4: