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