Showing the changes to lib/vimfiles/autoload/pythoncomplete.vim (1 of 1336 files). Show all
Unified · Split
| @@ -0,0 +1,599 @@ | |||
| 1 | "pythoncomplete.vim - Omni Completion for python | ||
| 2 | " Maintainer: Aaron Griffin <aaronmgriffin@gmail.com> | ||
| 3 | " Version: 0.7 | ||
| 4 | " Last Updated: 19 Oct 2006 | ||
| 5 | " | ||
| 6 | " Changes | ||
| 7 | " TODO: | ||
| 8 | " User defined docstrings aren't handled right... | ||
| 9 | " 'info' item output can use some formatting work | ||
| 10 | " Add an "unsafe eval" mode, to allow for return type evaluation | ||
| 11 | " Complete basic syntax along with import statements | ||
| 12 | " i.e. "import url<c-x,c-o>" | ||
| 13 | " Continue parsing on invalid line?? | ||
| 14 | " | ||
| 15 | " v 0.7 | ||
| 16 | " * Fixed function list sorting (_ and __ at the bottom) | ||
| 17 | " * Removed newline removal from docs. It appears vim handles these better in | ||
| 18 | " recent patches | ||
| 19 | " | ||
| 20 | " v 0.6: | ||
| 21 | " * Fixed argument completion | ||
| 22 | " * Removed the 'kind' completions, as they are better indicated | ||
| 23 | " with real syntax | ||
| 24 | " * Added tuple assignment parsing (whoops, that was forgotten) | ||
| 25 | " * Fixed import handling when flattening scope | ||
| 26 | " | ||
| 27 | " v 0.5: | ||
| 28 | " Yeah, I skipped a version number - 0.4 was never public. | ||
| 29 | " It was a bugfix version on top of 0.3. This is a complete | ||
| 30 | " rewrite. | ||
| 31 | " | ||
| 32 | |||
| 33 | if !has('python') | ||
| 34 | echo "Error: Required vim compiled with +python" | ||
| 35 | finish | ||
| 36 | endif | ||
| 37 | |||
| 38 | function! pythoncomplete#Complete(findstart, base) | ||
| 39 | "findstart = 1 when we need to get the text length | ||
| 40 | if a:findstart == 1 | ||
| 41 | let line = getline('.') | ||
| 42 | let idx = col('.') | ||
| 43 | while idx > 0 | ||
| 44 | let idx -= 1 | ||
| 45 | let c = line[idx] | ||
| 46 | if c =~ '\w' | ||
| 47 | continue | ||
| 48 | elseif ! c =~ '\.' | ||
| 49 | let idx = -1 | ||
| 50 | break | ||
| 51 | else | ||
| 52 | break | ||
| 53 | endif | ||
| 54 | endwhile | ||
| 55 | |||
| 56 | return idx | ||
| 57 | "findstart = 0 when we need to return the list of completions | ||
| 58 | else | ||
| 59 | "vim no longer moves the cursor upon completion... fix that | ||
| 60 | let line = getline('.') | ||
| 61 | let idx = col('.') | ||
| 62 | let cword = '' | ||
| 63 | while idx > 0 | ||
| 64 | let idx -= 1 | ||
| 65 | let c = line[idx] | ||
| 66 | if c =~ '\w' || c =~ '\.' || c == '(' | ||
| 67 | let cword = c . cword | ||
| 68 | continue | ||
| 69 | elseif strlen(cword) > 0 || idx == 0 | ||
| 70 | break | ||
| 71 | endif | ||
| 72 | endwhile | ||
| 73 | execute "python vimcomplete('" . cword . "', '" . a:base . "')" | ||
| 74 | return g:pythoncomplete_completions | ||
| 75 | endif | ||
| 76 | endfunction | ||
| 77 | |||
| 78 | function! s:DefPython() | ||
| 79 | python << PYTHONEOF | ||
| 80 | import sys, tokenize, cStringIO, types | ||
| 81 | from token import NAME, DEDENT, NEWLINE, STRING | ||
| 82 | |||
| 83 | debugstmts=[] | ||
| 84 | def dbg(s): debugstmts.append(s) | ||
| 85 | def showdbg(): | ||
| 86 | for d in debugstmts: print "DBG: %s " % d | ||
| 87 | |||
| 88 | def vimcomplete(context,match): | ||
| 89 | global debugstmts | ||
| 90 | debugstmts = [] | ||
| 91 | try: | ||
| 92 | import vim | ||
| 93 | def complsort(x,y): | ||
| 94 | try: | ||
| 95 | xa = x['abbr'] | ||
| 96 | ya = y['abbr'] | ||
| 97 | if xa[0] == '_': | ||
| 98 | if xa[1] == '_' and ya[0:2] == '__': | ||
| 99 | return xa > ya | ||
| 100 | elif ya[0:2] == '__': | ||
| 101 | return -1 | ||
| 102 | elif y[0] == '_': | ||
| 103 | return xa > ya | ||
| 104 | else: | ||
| 105 | return 1 | ||
| 106 | elif ya[0] == '_': | ||
| 107 | return -1 | ||
| 108 | else: | ||
| 109 | return xa > ya | ||
| 110 | except: | ||
| 111 | return 0 | ||
| 112 | cmpl = Completer() | ||
| 113 | cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')")) | ||
| 114 | all = cmpl.get_completions(context,match) | ||
| 115 | all.sort(complsort) | ||
| 116 | dictstr = '[' | ||
| 117 | # have to do this for double quoting | ||
| 118 | for cmpl in all: | ||
| 119 | dictstr += '{' | ||
| 120 | for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x]) | ||
| 121 | dictstr += '"icase":0},' | ||
| 122 | if dictstr[-1] == ',': dictstr = dictstr[:-1] | ||
| 123 | dictstr += ']' | ||
| 124 | #dbg("dict: %s" % dictstr) | ||
| 125 | vim.command("silent let g:pythoncomplete_completions = %s" % dictstr) | ||
| 126 | #dbg("Completion dict:\n%s" % all) | ||
| 127 | except vim.error: | ||
| 128 | dbg("VIM Error: %s" % vim.error) | ||
| 129 | |||
| 130 | class Completer(object): | ||
| 131 | def __init__(self): | ||
| 132 | self.compldict = {} | ||
| 133 | self.parser = PyParser() | ||
| 134 | |||
| 135 | def evalsource(self,text,line=0): | ||
| 136 | sc = self.parser.parse(text,line) | ||
| 137 | src = sc.get_code() | ||
| 138 | dbg("source: %s" % src) | ||
| 139 | try: exec(src) in self.compldict | ||
| 140 | except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) | ||
| 141 | for l in sc.locals: | ||
| 142 | try: exec(l) in self.compldict | ||
| 143 | except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) | ||
| 144 | |||
| 145 | def _cleanstr(self,doc): | ||
| 146 | return doc.replace('"',' ').replace("'",' ') | ||
| 147 | |||
| 148 | def get_arguments(self,func_obj): | ||
| 149 | def _ctor(obj): | ||
| 150 | try: return class_ob.__init__.im_func | ||
| 151 | except AttributeError: | ||
| 152 | for base in class_ob.__bases__: | ||
| 153 | rc = _find_constructor(base) | ||
| 154 | if rc is not None: return rc | ||
| 155 | return None | ||
| 156 | |||
| 157 | arg_offset = 1 | ||
| 158 | if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj) | ||
| 159 | elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func | ||
| 160 | else: arg_offset = 0 | ||
| 161 | |||
| 162 | arg_text='' | ||
| 163 | if type(func_obj) in [types.FunctionType, types.LambdaType]: | ||
| 164 | try: | ||
| 165 | cd = func_obj.func_code | ||
| 166 | real_args = cd.co_varnames[arg_offset:cd.co_argcount] | ||
| 167 | defaults = func_obj.func_defaults or '' | ||
| 168 | defaults = map(lambda name: "=%s" % name, defaults) | ||
| 169 | defaults = [""] * (len(real_args)-len(defaults)) + defaults | ||
| 170 | items = map(lambda a,d: a+d, real_args, defaults) | ||
| 171 | if func_obj.func_code.co_flags & 0x4: | ||
| 172 | items.append("...") | ||
| 173 | if func_obj.func_code.co_flags & 0x8: | ||
| 174 | items.append("***") | ||
| 175 | arg_text = (','.join(items)) + ')' | ||
| 176 | |||
| 177 | except: | ||
| 178 | dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1])) | ||
| 179 | pass | ||
| 180 | if len(arg_text) == 0: | ||
| 181 | # The doc string sometimes contains the function signature | ||
| 182 | # this works for alot of C modules that are part of the | ||
| 183 | # standard library | ||
| 184 | doc = func_obj.__doc__ | ||
| 185 | if doc: | ||
| 186 | doc = doc.lstrip() | ||
| 187 | pos = doc.find('\n') | ||
| 188 | if pos > 0: | ||
| 189 | sigline = doc[:pos] | ||
| 190 | lidx = sigline.find('(') | ||
| 191 | ridx = sigline.find(')') | ||
| 192 | if lidx > 0 and ridx > 0: | ||
| 193 | arg_text = sigline[lidx+1:ridx] + ')' | ||
| 194 | if len(arg_text) == 0: arg_text = ')' | ||
| 195 | return arg_text | ||
| 196 | |||
| 197 | def get_completions(self,context,match): | ||
| 198 | dbg("get_completions('%s','%s')" % (context,match)) | ||
| 199 | stmt = '' | ||
| 200 | if context: stmt += str(context) | ||
| 201 | if match: stmt += str(match) | ||
| 202 | try: | ||
| 203 | result = None | ||
| 204 | all = {} | ||
| 205 | ridx = stmt.rfind('.') | ||
| 206 | if len(stmt) > 0 and stmt[-1] == '(': | ||
| 207 | result = eval(_sanitize(stmt[:-1]), self.compldict) | ||
| 208 | doc = result.__doc__ | ||
| 209 | if doc == None: doc = '' | ||
| 210 | args = self.get_arguments(result) | ||
| 211 | return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}] | ||
| 212 | elif ridx == -1: | ||
| 213 | match = stmt | ||
| 214 | all = self.compldict | ||
| 215 | else: | ||
| 216 | match = stmt[ridx+1:] | ||
| 217 | stmt = _sanitize(stmt[:ridx]) | ||
| 218 | result = eval(stmt, self.compldict) | ||
| 219 | all = dir(result) | ||
| 220 | |||
| 221 | dbg("completing: stmt:%s" % stmt) | ||
| 222 | completions = [] | ||
| 223 | |||
| 224 | try: maindoc = result.__doc__ | ||
| 225 | except: maindoc = ' ' | ||
| 226 | if maindoc == None: maindoc = ' ' | ||
| 227 | for m in all: | ||
| 228 | if m == "_PyCmplNoType": continue #this is internal | ||
| 229 | try: | ||
| 230 | dbg('possible completion: %s' % m) | ||
| 231 | if m.find(match) == 0: | ||
| 232 | if result == None: inst = all[m] | ||
| 233 | else: inst = getattr(result,m) | ||
| 234 | try: doc = inst.__doc__ | ||
| 235 | except: doc = maindoc | ||
| 236 | typestr = str(inst) | ||
| 237 | if doc == None or doc == '': doc = maindoc | ||
| 238 | |||
| 239 | wrd = m[len(match):] | ||
| 240 | c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)} | ||
| 241 | if "function" in typestr: | ||
| 242 | c['word'] += '(' | ||
| 243 | c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) | ||
| 244 | elif "method" in typestr: | ||
| 245 | c['word'] += '(' | ||
| 246 | c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) | ||
| 247 | elif "module" in typestr: | ||
| 248 | c['word'] += '.' | ||
| 249 | elif "class" in typestr: | ||
| 250 | c['word'] += '(' | ||
| 251 | c['abbr'] += '(' | ||
| 252 | completions.append(c) | ||
| 253 | except: | ||
| 254 | i = sys.exc_info() | ||
| 255 | dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) | ||
| 256 | return completions | ||
| 257 | except: | ||
| 258 | i = sys.exc_info() | ||
| 259 | dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) | ||
| 260 | return [] | ||
| 261 | |||
| 262 | class Scope(object): | ||
| 263 | def __init__(self,name,indent): | ||
| 264 | self.subscopes = [] | ||
| 265 | self.docstr = '' | ||
| 266 | self.locals = [] | ||
| 267 | self.parent = None | ||
| 268 | self.name = name | ||
| 269 | self.indent = indent | ||
| 270 | |||
| 271 | def add(self,sub): | ||
| 272 | #print 'push scope: [%s@%s]' % (sub.name,sub.indent) | ||
| 273 | sub.parent = self | ||
| 274 | self.subscopes.append(sub) | ||
| 275 | return sub | ||
| 276 | |||
| 277 | def doc(self,str): | ||
| 278 | """ Clean up a docstring """ | ||
| 279 | d = str.replace('\n',' ') | ||
| 280 | d = d.replace('\t',' ') | ||
| 281 | while d.find(' ') > -1: d = d.replace(' ',' ') | ||
| 282 | while d[0] in '"\'\t ': d = d[1:] | ||
| 283 | while d[-1] in '"\'\t ': d = d[:-1] | ||
| 284 | self.docstr = d | ||
| 285 | |||
| 286 | def local(self,loc): | ||
| 287 | if not self._hasvaralready(loc): | ||
| 288 | self.locals.append(loc) | ||
| 289 | |||
| 290 | def copy_decl(self,indent=0): | ||
| 291 | """ Copy a scope's declaration only, at the specified indent level - not local variables """ | ||
| 292 | return Scope(self.name,indent) | ||
| 293 | |||
| 294 | def _hasvaralready(self,test): | ||
| 295 | "Convienance function... keep out duplicates" | ||
| 296 | if test.find('=') > -1: | ||
| 297 | var = test.split('=')[0].strip() | ||
| 298 | for l in self.locals: | ||
| 299 | if l.find('=') > -1 and var == l.split('=')[0].strip(): | ||
| 300 | return True | ||
| 301 | return False | ||
| 302 | |||
| 303 | def get_code(self): | ||
| 304 | # we need to start with this, to fix up broken completions | ||
| 305 | # hopefully this name is unique enough... | ||
| 306 | str = '"""'+self.docstr+'"""\n' | ||
| 307 | for l in self.locals: | ||
| 308 | if l.startswith('import'): str += l+'\n' | ||
| 309 | str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' | ||
| 310 | for sub in self.subscopes: | ||
| 311 | str += sub.get_code() | ||
| 312 | for l in self.locals: | ||
| 313 | if not l.startswith('import'): str += l+'\n' | ||
| 314 | |||
| 315 | return str | ||
| 316 | |||
| 317 | def pop(self,indent): | ||
| 318 | #print 'pop scope: [%s] to [%s]' % (self.indent,indent) | ||
| 319 | outer = self | ||
| 320 | while outer.parent != None and outer.indent >= indent: | ||
| 321 | outer = outer.parent | ||
| 322 | return outer | ||
| 323 | |||
| 324 | def currentindent(self): | ||
| 325 | #print 'parse current indent: %s' % self.indent | ||
| 326 | return ' '*self.indent | ||
| 327 | |||
| 328 | def childindent(self): | ||
| 329 | #print 'parse child indent: [%s]' % (self.indent+1) | ||
| 330 | return ' '*(self.indent+1) | ||
| 331 | |||
| 332 | class Class(Scope): | ||
| 333 | def __init__(self, name, supers, indent): | ||
| 334 | Scope.__init__(self,name,indent) | ||
| 335 | self.supers = supers | ||
| 336 | def copy_decl(self,indent=0): | ||
| 337 | c = Class(self.name,self.supers,indent) | ||
| 338 | for s in self.subscopes: | ||
| 339 | c.add(s.copy_decl(indent+1)) | ||
| 340 | return c | ||
| 341 | def get_code(self): | ||
| 342 | str = '%sclass %s' % (self.currentindent(),self.name) | ||
| 343 | if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers) | ||
| 344 | str += ':\n' | ||
| 345 | if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' | ||
| 346 | if len(self.subscopes) > 0: | ||
| 347 | for s in self.subscopes: str += s.get_code() | ||
| 348 | else: | ||
| 349 | str += '%spass\n' % self.childindent() | ||
| 350 | return str | ||
| 351 | |||
| 352 | |||
| 353 | class Function(Scope): | ||
| 354 | def __init__(self, name, params, indent): | ||
| 355 | Scope.__init__(self,name,indent) | ||
| 356 | self.params = params | ||
| 357 | def copy_decl(self,indent=0): | ||
| 358 | return Function(self.name,self.params,indent) | ||
| 359 | def get_code(self): | ||
| 360 | str = "%sdef %s(%s):\n" % \ | ||
| 361 | (self.currentindent(),self.name,','.join(self.params)) | ||
| 362 | if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' | ||
| 363 | str += "%spass\n" % self.childindent() | ||
| 364 | return str | ||
| 365 | |||
| 366 | class PyParser: | ||
| 367 | def __init__(self): | ||
| 368 | self.top = Scope('global',0) | ||
| 369 | self.scope = self.top | ||
| 370 | |||
| 371 | def _parsedotname(self,pre=None): | ||
| 372 | #returns (dottedname, nexttoken) | ||
| 373 | name = [] | ||
| 374 | if pre == None: | ||
| 375 | tokentype, token, indent = self.next() | ||
| 376 | if tokentype != NAME and token != '*': | ||
| 377 | return ('', token) | ||
| 378 | else: token = pre | ||
| 379 | name.append(token) | ||
| 380 | while True: | ||
| 381 | tokentype, token, indent = self.next() | ||
| 382 | if token != '.': break | ||
| 383 | tokentype, token, indent = self.next() | ||
| 384 | if tokentype != NAME: break | ||
| 385 | name.append(token) | ||
| 386 | return (".".join(name), token) | ||
| 387 | |||
| 388 | def _parseimportlist(self): | ||
| 389 | imports = [] | ||
| 390 | while True: | ||
| 391 | name, token = self._parsedotname() | ||
| 392 | if not name: break | ||
| 393 | name2 = '' | ||
| 394 | if token == 'as': name2, token = self._parsedotname() | ||
| 395 | imports.append((name, name2)) | ||
| 396 | while token != "," and "\n" not in token: | ||
| 397 | tokentype, token, indent = self.next() | ||
| 398 | if token != ",": break | ||
| 399 | return imports | ||
| 400 | |||
| 401 | def _parenparse(self): | ||
| 402 | name = '' | ||
| 403 | names = [] | ||
| 404 | level = 1 | ||
| 405 | while True: | ||
| 406 | tokentype, token, indent = self.next() | ||
| 407 | if token in (')', ',') and level == 1: | ||
| 408 | names.append(name) | ||
| 409 | name = '' | ||
| 410 | if token == '(': | ||
| 411 | level += 1 | ||
| 412 | elif token == ')': | ||
| 413 | level -= 1 | ||
| 414 | if level == 0: break | ||
| 415 | elif token == ',' and level == 1: | ||
| 416 | pass | ||
| 417 | else: | ||
| 418 | name += str(token) | ||
| 419 | return names | ||
| 420 | |||
| 421 | def _parsefunction(self,indent): | ||
| 422 | self.scope=self.scope.pop(indent) | ||
| 423 | tokentype, fname, ind = self.next() | ||
| 424 | if tokentype != NAME: return None | ||
| 425 | |||
| 426 | tokentype, open, ind = self.next() | ||
| 427 | if open != '(': return None | ||
| 428 | params=self._parenparse() | ||
| 429 | |||
| 430 | tokentype, colon, ind = self.next() | ||
| 431 | if colon != ':': return None | ||
| 432 | |||
| 433 | return Function(fname,params,indent) | ||
| 434 | |||
| 435 | def _parseclass(self,indent): | ||
| 436 | self.scope=self.scope.pop(indent) | ||
| 437 | tokentype, cname, ind = self.next() | ||
| 438 | if tokentype != NAME: return None | ||
| 439 | |||
| 440 | super = [] | ||
| 441 | tokentype, next, ind = self.next() | ||
| 442 | if next == '(': | ||
| 443 | super=self._parenparse() | ||
| 444 | elif next != ':': return None | ||
| 445 | |||
| 446 | return Class(cname,super,indent) | ||
| 447 | |||
| 448 | def _parseassignment(self): | ||
| 449 | assign='' | ||
| 450 | tokentype, token, indent = self.next() | ||
| 451 | if tokentype == tokenize.STRING or token == 'str': | ||
| 452 | return '""' | ||
| 453 | elif token == '(' or token == 'tuple': | ||
| 454 | return '()' | ||
| 455 | elif token == '[' or token == 'list': | ||
| 456 | return '[]' | ||
| 457 | elif token == '{' or token == 'dict': | ||
| 458 | return '{}' | ||
| 459 | elif tokentype == tokenize.NUMBER: | ||
| 460 | return '0' | ||
| 461 | elif token == 'open' or token == 'file': | ||
| 462 | return 'file' | ||
| 463 | elif token == 'None': | ||
| 464 | return '_PyCmplNoType()' | ||
| 465 | elif token == 'type': | ||
| 466 | return 'type(_PyCmplNoType)' #only for method resolution | ||
| 467 | else: | ||
| 468 | assign += token | ||
| 469 | level = 0 | ||
| 470 | while True: | ||
| 471 | tokentype, token, indent = self.next() | ||
| 472 | if token in ('(','{','['): | ||
| 473 | level += 1 | ||
| 474 | elif token in (']','}',')'): | ||
| 475 | level -= 1 | ||
| 476 | if level == 0: break | ||
| 477 | elif level == 0: | ||
| 478 | if token in (';','\n'): break | ||
| 479 | assign += token | ||
| 480 | return "%s" % assign | ||
| 481 | |||
| 482 | def next(self): | ||
| 483 | type, token, (lineno, indent), end, self.parserline = self.gen.next() | ||
| 484 | if lineno == self.curline: | ||
| 485 | #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name) | ||
| 486 | self.currentscope = self.scope | ||
| 487 | return (type, token, indent) | ||
| 488 | |||
| 489 | def _adjustvisibility(self): | ||
| 490 | newscope = Scope('result',0) | ||
| 491 | scp = self.currentscope | ||
| 492 | while scp != None: | ||
| 493 | if type(scp) == Function: | ||
| 494 | slice = 0 | ||
| 495 | #Handle 'self' params | ||
| 496 | if scp.parent != None and type(scp.parent) == Class: | ||
| 497 | 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)) | ||
| 502 | for p in scp.params[slice:]: | ||
| 503 | i = p.find('=') | ||
| 504 | if i == -1: | ||
| 505 | newscope.local('%s = _PyCmplNoType()' % p) | ||
| 506 | else: | ||
| 507 | newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1]))) | ||
| 508 | |||
| 509 | for s in scp.subscopes: | ||
| 510 | ns = s.copy_decl(0) | ||
| 511 | newscope.add(ns) | ||
| 512 | for l in scp.locals: newscope.local(l) | ||
| 513 | scp = scp.parent | ||
| 514 | |||
| 515 | self.currentscope = newscope | ||
| 516 | return self.currentscope | ||
| 517 | |||
| 518 | #p.parse(vim.current.buffer[:],vim.eval("line('.')")) | ||
| 519 | def parse(self,text,curline=0): | ||
| 520 | self.curline = int(curline) | ||
| 521 | buf = cStringIO.StringIO(''.join(text) + '\n') | ||
| 522 | self.gen = tokenize.generate_tokens(buf.readline) | ||
| 523 | self.currentscope = self.scope | ||
| 524 | |||
| 525 | try: | ||
| 526 | freshscope=True | ||
| 527 | while True: | ||
| 528 | tokentype, token, indent = self.next() | ||
| 529 | #dbg( 'main: token=[%s] indent=[%s]' % (token,indent)) | ||
| 530 | |||
| 531 | if tokentype == DEDENT or token == "pass": | ||
| 532 | self.scope = self.scope.pop(indent) | ||
| 533 | elif token == 'def': | ||
| 534 | func = self._parsefunction(indent) | ||
| 535 | if func == None: | ||
| 536 | print "function: syntax error..." | ||
| 537 | continue | ||
| 538 | freshscope = True | ||
| 539 | self.scope = self.scope.add(func) | ||
| 540 | elif token == 'class': | ||
| 541 | cls = self._parseclass(indent) | ||
| 542 | if cls == None: | ||
| 543 | print "class: syntax error..." | ||
| 544 | continue | ||
| 545 | freshscope = True | ||
| 546 | self.scope = self.scope.add(cls) | ||
| 547 | |||
| 548 | elif token == 'import': | ||
| 549 | imports = self._parseimportlist() | ||
| 550 | for mod, alias in imports: | ||
| 551 | loc = "import %s" % mod | ||
| 552 | if len(alias) > 0: loc += " as %s" % alias | ||
| 553 | self.scope.local(loc) | ||
| 554 | freshscope = False | ||
| 555 | elif token == 'from': | ||
| 556 | mod, token = self._parsedotname() | ||
| 557 | if not mod or token != "import": | ||
| 558 | print "from: syntax error..." | ||
| 559 | continue | ||
| 560 | names = self._parseimportlist() | ||
| 561 | for name, alias in names: | ||
| 562 | loc = "from %s import %s" % (mod,name) | ||
| 563 | if len(alias) > 0: loc += " as %s" % alias | ||
| 564 | self.scope.local(loc) | ||
| 565 | freshscope = False | ||
| 566 | elif tokentype == STRING: | ||
| 567 | if freshscope: self.scope.doc(token) | ||
| 568 | elif tokentype == NAME: | ||
| 569 | name,token = self._parsedotname(token) | ||
| 570 | if token == '=': | ||
| 571 | stmt = self._parseassignment() | ||
| 572 | if stmt != None: | ||
| 573 | self.scope.local("%s = %s" % (name,stmt)) | ||
| 574 | freshscope = False | ||
| 575 | except StopIteration: #thrown on EOF | ||
| 576 | pass | ||
| 577 | except: | ||
| 578 | dbg("parse error: %s, %s @ %s" % | ||
| 579 | (sys.exc_info()[0], sys.exc_info()[1], self.parserline)) | ||
| 580 | return self._adjustvisibility() | ||
| 581 | |||
| 582 | def _sanitize(str): | ||
| 583 | val = '' | ||
| 584 | level = 0 | ||
| 585 | for c in str: | ||
| 586 | if c in ('(','{','['): | ||
| 587 | level += 1 | ||
| 588 | elif c in (']','}',')'): | ||
| 589 | level -= 1 | ||
| 590 | elif level == 0: | ||
| 591 | val += c | ||
| 592 | return val | ||
| 593 | |||
| 594 | sys.path.extend(['.','..']) | ||
| 595 | PYTHONEOF | ||
| 596 | endfunction | ||
| 597 | |||
| 598 | call s:DefPython() | ||
| 599 | " vim: set et ts=4: | ||