118144c84SBram Moolenaar"pythoncomplete.vim - Omni Completion for python 2*fc1421ebSBram Moolenaar" Maintainer: Aaron Griffin <[email protected]> 3*fc1421ebSBram Moolenaar" Version: 0.5 4*fc1421ebSBram Moolenaar" Last Updated: 19 April 2006 518144c84SBram Moolenaar" 6*fc1421ebSBram Moolenaar" Yeah, I skipped a version number - 0.4 was never public. 7*fc1421ebSBram Moolenaar" It was a bugfix version on top of 0.3. This is a complete 8*fc1421ebSBram Moolenaar" rewrite. 918144c84SBram Moolenaar" 10*fc1421ebSBram Moolenaar" TODO: 11*fc1421ebSBram Moolenaar" User defined docstrings aren't handled right... 12*fc1421ebSBram Moolenaar" 'info' item output can use some formatting work 13*fc1421ebSBram Moolenaar" Add an "unsafe eval" mode, to allow for return type evaluation 1418144c84SBram Moolenaar 1518144c84SBram Moolenaarif !has('python') 1618144c84SBram Moolenaar echo "Error: Required vim compiled with +python" 1718144c84SBram Moolenaar finish 1818144c84SBram Moolenaarendif 1918144c84SBram Moolenaar 2018144c84SBram Moolenaarfunction! pythoncomplete#Complete(findstart, base) 2118144c84SBram Moolenaar "findstart = 1 when we need to get the text length 22*fc1421ebSBram Moolenaar if a:findstart == 1 2318144c84SBram Moolenaar let line = getline('.') 2418144c84SBram Moolenaar let idx = col('.') 2518144c84SBram Moolenaar while idx > 0 2618144c84SBram Moolenaar let idx -= 1 27*fc1421ebSBram Moolenaar let c = line[idx] 2818144c84SBram Moolenaar if c =~ '\w' 2918144c84SBram Moolenaar continue 3018144c84SBram Moolenaar elseif ! c =~ '\.' 3118144c84SBram Moolenaar idx = -1 3218144c84SBram Moolenaar break 3318144c84SBram Moolenaar else 3418144c84SBram Moolenaar break 3518144c84SBram Moolenaar endif 3618144c84SBram Moolenaar endwhile 3718144c84SBram Moolenaar 3818144c84SBram Moolenaar return idx 3918144c84SBram Moolenaar "findstart = 0 when we need to return the list of completions 4018144c84SBram Moolenaar else 41*fc1421ebSBram Moolenaar "vim no longer moves the cursor upon completion... fix that 42*fc1421ebSBram Moolenaar let line = getline('.') 43*fc1421ebSBram Moolenaar let idx = col('.') 44*fc1421ebSBram Moolenaar let cword = '' 45*fc1421ebSBram Moolenaar while idx > 0 46*fc1421ebSBram Moolenaar let idx -= 1 47*fc1421ebSBram Moolenaar let c = line[idx] 48*fc1421ebSBram Moolenaar if c =~ '\w' || c =~ '\.' 49*fc1421ebSBram Moolenaar let cword = c . cword 50*fc1421ebSBram Moolenaar continue 51*fc1421ebSBram Moolenaar elseif strlen(cword) > 0 || idx == 0 52*fc1421ebSBram Moolenaar break 53*fc1421ebSBram Moolenaar endif 54*fc1421ebSBram Moolenaar endwhile 55*fc1421ebSBram Moolenaar execute "python vimcomplete('" . cword . "', '" . a:base . "')" 5618144c84SBram Moolenaar return g:pythoncomplete_completions 5718144c84SBram Moolenaar endif 5818144c84SBram Moolenaarendfunction 5918144c84SBram Moolenaar 6018144c84SBram Moolenaarfunction! s:DefPython() 6118144c84SBram Moolenaarpython << PYTHONEOF 62*fc1421ebSBram Moolenaarimport sys, tokenize, cStringIO, types 63*fc1421ebSBram Moolenaarfrom token import NAME, DEDENT, NEWLINE, STRING 6418144c84SBram Moolenaar 65*fc1421ebSBram Moolenaardebugstmts=[] 66*fc1421ebSBram Moolenaardef dbg(s): debugstmts.append(s) 67*fc1421ebSBram Moolenaardef showdbg(): 68*fc1421ebSBram Moolenaar for d in debugstmts: print "DBG: %s " % d 6918144c84SBram Moolenaar 70*fc1421ebSBram Moolenaardef vimcomplete(context,match): 71*fc1421ebSBram Moolenaar global debugstmts 72*fc1421ebSBram Moolenaar debugstmts = [] 7318144c84SBram Moolenaar try: 74*fc1421ebSBram Moolenaar import vim 75*fc1421ebSBram Moolenaar def complsort(x,y): 76*fc1421ebSBram Moolenaar return x['abbr'] > y['abbr'] 77*fc1421ebSBram Moolenaar cmpl = Completer() 78*fc1421ebSBram Moolenaar cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')")) 79*fc1421ebSBram Moolenaar all = cmpl.get_completions(context,match) 80*fc1421ebSBram Moolenaar all.sort(complsort) 81*fc1421ebSBram Moolenaar dictstr = '[' 82*fc1421ebSBram Moolenaar # have to do this for double quoting 83*fc1421ebSBram Moolenaar for cmpl in all: 84*fc1421ebSBram Moolenaar dictstr += '{' 85*fc1421ebSBram Moolenaar for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x]) 86*fc1421ebSBram Moolenaar dictstr += '"icase":0},' 87*fc1421ebSBram Moolenaar if dictstr[-1] == ',': dictstr = dictstr[:-1] 88*fc1421ebSBram Moolenaar dictstr += ']' 89*fc1421ebSBram Moolenaar dbg("dict: %s" % dictstr) 90*fc1421ebSBram Moolenaar vim.command("silent let g:pythoncomplete_completions = %s" % dictstr) 91*fc1421ebSBram Moolenaar #dbg("Completion dict:\n%s" % all) 92*fc1421ebSBram Moolenaar except vim.error: 93*fc1421ebSBram Moolenaar dbg("VIM Error: %s" % vim.error) 9418144c84SBram Moolenaar 95*fc1421ebSBram Moolenaarclass Completer(object): 96*fc1421ebSBram Moolenaar def __init__(self): 97*fc1421ebSBram Moolenaar self.compldict = {} 98*fc1421ebSBram Moolenaar self.parser = PyParser() 9918144c84SBram Moolenaar 100*fc1421ebSBram Moolenaar def evalsource(self,text,line=0): 101*fc1421ebSBram Moolenaar sc = self.parser.parse(text,line) 102*fc1421ebSBram Moolenaar src = sc.get_code() 103*fc1421ebSBram Moolenaar dbg("source: %s" % src) 104*fc1421ebSBram Moolenaar try: exec(src) in self.compldict 105*fc1421ebSBram Moolenaar except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) 106*fc1421ebSBram Moolenaar for l in sc.locals: 107*fc1421ebSBram Moolenaar try: exec(l) in self.compldict 108*fc1421ebSBram Moolenaar except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) 10918144c84SBram Moolenaar 110*fc1421ebSBram Moolenaar def _cleanstr(self,doc): 111*fc1421ebSBram Moolenaar return doc.replace('"',' ')\ 112*fc1421ebSBram Moolenaar .replace("'",' ')\ 113*fc1421ebSBram Moolenaar .replace('\n',' ')\ 114*fc1421ebSBram Moolenaar .replace('\r',' ')\ 115*fc1421ebSBram Moolenaar .replace(' 11618144c84SBram Moolenaar',' ') 117*fc1421ebSBram Moolenaar 11818144c84SBram Moolenaar def get_arguments(self,func_obj): 119*fc1421ebSBram Moolenaar def _ctor(obj): 12018144c84SBram Moolenaar try: return class_ob.__init__.im_func 12118144c84SBram Moolenaar except AttributeError: 12218144c84SBram Moolenaar for base in class_ob.__bases__: 12318144c84SBram Moolenaar rc = _find_constructor(base) 12418144c84SBram Moolenaar if rc is not None: return rc 12518144c84SBram Moolenaar return None 12618144c84SBram Moolenaar 12718144c84SBram Moolenaar arg_offset = 1 12818144c84SBram Moolenaar if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj) 12918144c84SBram Moolenaar elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func 13018144c84SBram Moolenaar else: arg_offset = 0 131*fc1421ebSBram Moolenaar 13218144c84SBram Moolenaar arg_text = ')' 13318144c84SBram Moolenaar if type(func_obj) in [types.FunctionType, types.LambdaType]: 13418144c84SBram Moolenaar try: 13518144c84SBram Moolenaar cd = func_obj.func_code 13618144c84SBram Moolenaar real_args = cd.co_varnames[arg_offset:cd.co_argcount] 137*fc1421ebSBram Moolenaar defaults = func_obj.func_defaults or [] 13818144c84SBram Moolenaar defaults = [map(lambda name: "=%s" % name, defaults)] 13918144c84SBram Moolenaar defaults = [""] * (len(real_args)-len(defaults)) + defaults 14018144c84SBram Moolenaar items = map(lambda a,d: a+d, real_args, defaults) 14118144c84SBram Moolenaar if func_obj.func_code.co_flags & 0x4: 14218144c84SBram Moolenaar items.append("...") 14318144c84SBram Moolenaar if func_obj.func_code.co_flags & 0x8: 14418144c84SBram Moolenaar items.append("***") 14518144c84SBram Moolenaar arg_text = ", ".join(items) + ')' 14618144c84SBram Moolenaar 147*fc1421ebSBram Moolenaar except: 14818144c84SBram Moolenaar dbg("completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1])) 14918144c84SBram Moolenaar pass 15018144c84SBram Moolenaar if len(arg_text) == 0: 15118144c84SBram Moolenaar # The doc string sometimes contains the function signature 15218144c84SBram Moolenaar # this works for alot of C modules that are part of the 153*fc1421ebSBram Moolenaar # standard library 15418144c84SBram Moolenaar doc = func_obj.__doc__ 15518144c84SBram Moolenaar if doc: 15618144c84SBram Moolenaar doc = doc.lstrip() 15718144c84SBram Moolenaar pos = doc.find('\n') 15818144c84SBram Moolenaar if pos > 0: 15918144c84SBram Moolenaar sigline = doc[:pos] 16018144c84SBram Moolenaar lidx = sigline.find('(') 16118144c84SBram Moolenaar ridx = sigline.find(')') 16218144c84SBram Moolenaar if lidx > 0 and ridx > 0: 16318144c84SBram Moolenaar arg_text = sigline[lidx+1:ridx] + ')' 16418144c84SBram Moolenaar return arg_text 165*fc1421ebSBram Moolenaar 166*fc1421ebSBram Moolenaar def get_completions(self,context,match): 16718144c84SBram Moolenaar dbg("get_completions('%s','%s')" % (context,match)) 168*fc1421ebSBram Moolenaar stmt = '' 169*fc1421ebSBram Moolenaar if context: stmt += str(context) 170*fc1421ebSBram Moolenaar if match: stmt += str(match) 171*fc1421ebSBram Moolenaar try: 172*fc1421ebSBram Moolenaar result = None 173*fc1421ebSBram Moolenaar all = {} 174*fc1421ebSBram Moolenaar ridx = stmt.rfind('.') 175*fc1421ebSBram Moolenaar if len(stmt) > 0 and stmt[-1] == '(': 176*fc1421ebSBram Moolenaar #TODO 177*fc1421ebSBram Moolenaar result = eval(_sanitize(stmt[:-1]), self.compldict) 178*fc1421ebSBram Moolenaar doc = result.__doc__ 179*fc1421ebSBram Moolenaar if doc == None: doc = '' 180*fc1421ebSBram Moolenaar args = self.get_arguments(res) 181*fc1421ebSBram Moolenaar return [{'word':self._cleanstr(args),'info':self._cleanstr(doc),'kind':'p'}] 182*fc1421ebSBram Moolenaar elif ridx == -1: 183*fc1421ebSBram Moolenaar match = stmt 184*fc1421ebSBram Moolenaar all = self.compldict 185*fc1421ebSBram Moolenaar else: 186*fc1421ebSBram Moolenaar match = stmt[ridx+1:] 187*fc1421ebSBram Moolenaar stmt = _sanitize(stmt[:ridx]) 188*fc1421ebSBram Moolenaar result = eval(stmt, self.compldict) 189*fc1421ebSBram Moolenaar all = dir(result) 190*fc1421ebSBram Moolenaar 191*fc1421ebSBram Moolenaar dbg("completing: stmt:%s" % stmt) 192*fc1421ebSBram Moolenaar completions = [] 193*fc1421ebSBram Moolenaar 194*fc1421ebSBram Moolenaar try: maindoc = result.__doc__ 195*fc1421ebSBram Moolenaar except: maindoc = ' ' 196*fc1421ebSBram Moolenaar if maindoc == None: maindoc = ' ' 197*fc1421ebSBram Moolenaar for m in all: 198*fc1421ebSBram Moolenaar if m == "_PyCmplNoType": continue #this is internal 199*fc1421ebSBram Moolenaar try: 200*fc1421ebSBram Moolenaar dbg('possible completion: %s' % m) 201*fc1421ebSBram Moolenaar if m.find(match) == 0: 202*fc1421ebSBram Moolenaar if result == None: inst = all[m] 203*fc1421ebSBram Moolenaar else: inst = getattr(result,m) 204*fc1421ebSBram Moolenaar try: doc = inst.__doc__ 205*fc1421ebSBram Moolenaar except: doc = maindoc 206*fc1421ebSBram Moolenaar typestr = str(inst) 207*fc1421ebSBram Moolenaar if doc == None or doc == '': doc = maindoc 208*fc1421ebSBram Moolenaar 209*fc1421ebSBram Moolenaar wrd = m[len(match):] 210*fc1421ebSBram Moolenaar c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc),'kind':'m'} 211*fc1421ebSBram Moolenaar if "function" in typestr: 212*fc1421ebSBram Moolenaar c['word'] += '(' 213*fc1421ebSBram Moolenaar c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) 214*fc1421ebSBram Moolenaar c['kind'] = 'f' 215*fc1421ebSBram Moolenaar elif "method" in typestr: 216*fc1421ebSBram Moolenaar c['word'] += '(' 217*fc1421ebSBram Moolenaar c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) 218*fc1421ebSBram Moolenaar c['kind'] = 'f' 219*fc1421ebSBram Moolenaar elif "module" in typestr: 220*fc1421ebSBram Moolenaar c['word'] += '.' 221*fc1421ebSBram Moolenaar c['kind'] = 'm' 222*fc1421ebSBram Moolenaar elif "class" in typestr: 223*fc1421ebSBram Moolenaar c['word'] += '(' 224*fc1421ebSBram Moolenaar c['abbr'] += '(' 225*fc1421ebSBram Moolenaar c['kind']='c' 226*fc1421ebSBram Moolenaar completions.append(c) 227*fc1421ebSBram Moolenaar except: 228*fc1421ebSBram Moolenaar i = sys.exc_info() 229*fc1421ebSBram Moolenaar dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) 230*fc1421ebSBram Moolenaar return completions 231*fc1421ebSBram Moolenaar except: 232*fc1421ebSBram Moolenaar i = sys.exc_info() 233*fc1421ebSBram Moolenaar dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) 234*fc1421ebSBram Moolenaar return [] 235*fc1421ebSBram Moolenaar 236*fc1421ebSBram Moolenaarclass Scope(object): 237*fc1421ebSBram Moolenaar def __init__(self,name,indent): 238*fc1421ebSBram Moolenaar self.subscopes = [] 239*fc1421ebSBram Moolenaar self.docstr = '' 240*fc1421ebSBram Moolenaar self.locals = [] 241*fc1421ebSBram Moolenaar self.parent = None 242*fc1421ebSBram Moolenaar self.name = name 243*fc1421ebSBram Moolenaar self.indent = indent 244*fc1421ebSBram Moolenaar 245*fc1421ebSBram Moolenaar def add(self,sub): 246*fc1421ebSBram Moolenaar #print 'push scope: [%s@%s]' % (sub.name,sub.indent) 247*fc1421ebSBram Moolenaar sub.parent = self 248*fc1421ebSBram Moolenaar self.subscopes.append(sub) 249*fc1421ebSBram Moolenaar return sub 250*fc1421ebSBram Moolenaar 251*fc1421ebSBram Moolenaar def doc(self,str): 252*fc1421ebSBram Moolenaar """ Clean up a docstring """ 253*fc1421ebSBram Moolenaar d = str.replace('\n',' ') 254*fc1421ebSBram Moolenaar d = d.replace('\t',' ') 255*fc1421ebSBram Moolenaar while d.find(' ') > -1: d = d.replace(' ',' ') 256*fc1421ebSBram Moolenaar while d[0] in '"\'\t ': d = d[1:] 257*fc1421ebSBram Moolenaar while d[-1] in '"\'\t ': d = d[:-1] 258*fc1421ebSBram Moolenaar self.docstr = d 259*fc1421ebSBram Moolenaar 260*fc1421ebSBram Moolenaar def local(self,loc): 261*fc1421ebSBram Moolenaar if not self._hasvaralready(loc): 262*fc1421ebSBram Moolenaar self.locals.append(loc) 263*fc1421ebSBram Moolenaar 264*fc1421ebSBram Moolenaar def copy_decl(self,indent=0): 265*fc1421ebSBram Moolenaar """ Copy a scope's declaration only, at the specified indent level - not local variables """ 266*fc1421ebSBram Moolenaar return Scope(self.name,indent) 267*fc1421ebSBram Moolenaar 268*fc1421ebSBram Moolenaar def _hasvaralready(self,test): 269*fc1421ebSBram Moolenaar "Convienance function... keep out duplicates" 270*fc1421ebSBram Moolenaar if test.find('=') > -1: 271*fc1421ebSBram Moolenaar var = test.split('=')[0].strip() 272*fc1421ebSBram Moolenaar for l in self.locals: 273*fc1421ebSBram Moolenaar if l.find('=') > -1 and var == l.split('=')[0].strip(): 274*fc1421ebSBram Moolenaar return True 275*fc1421ebSBram Moolenaar return False 276*fc1421ebSBram Moolenaar 277*fc1421ebSBram Moolenaar def get_code(self): 278*fc1421ebSBram Moolenaar # we need to start with this, to fix up broken completions 279*fc1421ebSBram Moolenaar # hopefully this name is unique enough... 280*fc1421ebSBram Moolenaar str = '"""'+self.docstr+'"""\n' 281*fc1421ebSBram Moolenaar str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' 282*fc1421ebSBram Moolenaar for sub in self.subscopes: 283*fc1421ebSBram Moolenaar str += sub.get_code() 284*fc1421ebSBram Moolenaar #str += '\n'.join(self.locals)+'\n' 285*fc1421ebSBram Moolenaar 286*fc1421ebSBram Moolenaar return str 287*fc1421ebSBram Moolenaar 288*fc1421ebSBram Moolenaar def pop(self,indent): 289*fc1421ebSBram Moolenaar #print 'pop scope: [%s] to [%s]' % (self.indent,indent) 290*fc1421ebSBram Moolenaar outer = self 291*fc1421ebSBram Moolenaar while outer.parent != None and outer.indent >= indent: 292*fc1421ebSBram Moolenaar outer = outer.parent 293*fc1421ebSBram Moolenaar return outer 294*fc1421ebSBram Moolenaar 295*fc1421ebSBram Moolenaar def currentindent(self): 296*fc1421ebSBram Moolenaar #print 'parse current indent: %s' % self.indent 297*fc1421ebSBram Moolenaar return ' '*self.indent 298*fc1421ebSBram Moolenaar 299*fc1421ebSBram Moolenaar def childindent(self): 300*fc1421ebSBram Moolenaar #print 'parse child indent: [%s]' % (self.indent+1) 301*fc1421ebSBram Moolenaar return ' '*(self.indent+1) 302*fc1421ebSBram Moolenaar 303*fc1421ebSBram Moolenaarclass Class(Scope): 304*fc1421ebSBram Moolenaar def __init__(self, name, supers, indent): 305*fc1421ebSBram Moolenaar Scope.__init__(self,name,indent) 306*fc1421ebSBram Moolenaar self.supers = supers 307*fc1421ebSBram Moolenaar def copy_decl(self,indent=0): 308*fc1421ebSBram Moolenaar c = Class(self.name,self.supers,indent) 309*fc1421ebSBram Moolenaar for s in self.subscopes: 310*fc1421ebSBram Moolenaar c.add(s.copy_decl(indent+1)) 311*fc1421ebSBram Moolenaar return c 312*fc1421ebSBram Moolenaar def get_code(self): 313*fc1421ebSBram Moolenaar str = '%sclass %s' % (self.currentindent(),self.name) 314*fc1421ebSBram Moolenaar if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers) 315*fc1421ebSBram Moolenaar str += ':\n' 316*fc1421ebSBram Moolenaar if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' 317*fc1421ebSBram Moolenaar if len(self.subscopes) > 0: 318*fc1421ebSBram Moolenaar for s in self.subscopes: str += s.get_code() 319*fc1421ebSBram Moolenaar else: 320*fc1421ebSBram Moolenaar str += '%spass\n' % self.childindent() 321*fc1421ebSBram Moolenaar return str 322*fc1421ebSBram Moolenaar 323*fc1421ebSBram Moolenaar 324*fc1421ebSBram Moolenaarclass Function(Scope): 325*fc1421ebSBram Moolenaar def __init__(self, name, params, indent): 326*fc1421ebSBram Moolenaar Scope.__init__(self,name,indent) 327*fc1421ebSBram Moolenaar self.params = params 328*fc1421ebSBram Moolenaar def copy_decl(self,indent=0): 329*fc1421ebSBram Moolenaar return Function(self.name,self.params,indent) 330*fc1421ebSBram Moolenaar def get_code(self): 331*fc1421ebSBram Moolenaar str = "%sdef %s(%s):\n" % \ 332*fc1421ebSBram Moolenaar (self.currentindent(),self.name,','.join(self.params)) 333*fc1421ebSBram Moolenaar if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' 334*fc1421ebSBram Moolenaar str += "%spass\n" % self.childindent() 335*fc1421ebSBram Moolenaar return str 336*fc1421ebSBram Moolenaar 337*fc1421ebSBram Moolenaarclass PyParser: 338*fc1421ebSBram Moolenaar def __init__(self): 339*fc1421ebSBram Moolenaar self.top = Scope('global',0) 340*fc1421ebSBram Moolenaar self.scope = self.top 341*fc1421ebSBram Moolenaar 342*fc1421ebSBram Moolenaar def _parsedotname(self,pre=None): 343*fc1421ebSBram Moolenaar #returns (dottedname, nexttoken) 344*fc1421ebSBram Moolenaar name = [] 345*fc1421ebSBram Moolenaar if pre == None: 346*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 347*fc1421ebSBram Moolenaar if tokentype != NAME and token != '*': 348*fc1421ebSBram Moolenaar return ('', token) 349*fc1421ebSBram Moolenaar else: token = pre 350*fc1421ebSBram Moolenaar name.append(token) 351*fc1421ebSBram Moolenaar while True: 352*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 353*fc1421ebSBram Moolenaar if token != '.': break 354*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 355*fc1421ebSBram Moolenaar if tokentype != NAME: break 356*fc1421ebSBram Moolenaar name.append(token) 357*fc1421ebSBram Moolenaar return (".".join(name), token) 358*fc1421ebSBram Moolenaar 359*fc1421ebSBram Moolenaar def _parseimportlist(self): 360*fc1421ebSBram Moolenaar imports = [] 361*fc1421ebSBram Moolenaar while True: 362*fc1421ebSBram Moolenaar name, token = self._parsedotname() 363*fc1421ebSBram Moolenaar if not name: break 364*fc1421ebSBram Moolenaar name2 = '' 365*fc1421ebSBram Moolenaar if token == 'as': name2, token = self._parsedotname() 366*fc1421ebSBram Moolenaar imports.append((name, name2)) 367*fc1421ebSBram Moolenaar while token != "," and "\n" not in token: 368*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 369*fc1421ebSBram Moolenaar if token != ",": break 370*fc1421ebSBram Moolenaar return imports 371*fc1421ebSBram Moolenaar 372*fc1421ebSBram Moolenaar def _parenparse(self): 373*fc1421ebSBram Moolenaar name = '' 374*fc1421ebSBram Moolenaar names = [] 375*fc1421ebSBram Moolenaar level = 1 376*fc1421ebSBram Moolenaar while True: 377*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 378*fc1421ebSBram Moolenaar if token in (')', ',') and level == 1: 379*fc1421ebSBram Moolenaar names.append(name) 380*fc1421ebSBram Moolenaar name = '' 38118144c84SBram Moolenaar if token == '(': 382*fc1421ebSBram Moolenaar level += 1 383*fc1421ebSBram Moolenaar elif token == ')': 384*fc1421ebSBram Moolenaar level -= 1 385*fc1421ebSBram Moolenaar if level == 0: break 386*fc1421ebSBram Moolenaar elif token == ',' and level == 1: 387*fc1421ebSBram Moolenaar pass 388*fc1421ebSBram Moolenaar else: 389*fc1421ebSBram Moolenaar name += str(token) 390*fc1421ebSBram Moolenaar return names 391*fc1421ebSBram Moolenaar 392*fc1421ebSBram Moolenaar def _parsefunction(self,indent): 393*fc1421ebSBram Moolenaar self.scope=self.scope.pop(indent) 394*fc1421ebSBram Moolenaar tokentype, fname, ind = self.next() 395*fc1421ebSBram Moolenaar if tokentype != NAME: return None 396*fc1421ebSBram Moolenaar 397*fc1421ebSBram Moolenaar tokentype, open, ind = self.next() 398*fc1421ebSBram Moolenaar if open != '(': return None 399*fc1421ebSBram Moolenaar params=self._parenparse() 400*fc1421ebSBram Moolenaar 401*fc1421ebSBram Moolenaar tokentype, colon, ind = self.next() 402*fc1421ebSBram Moolenaar if colon != ':': return None 403*fc1421ebSBram Moolenaar 404*fc1421ebSBram Moolenaar return Function(fname,params,indent) 405*fc1421ebSBram Moolenaar 406*fc1421ebSBram Moolenaar def _parseclass(self,indent): 407*fc1421ebSBram Moolenaar self.scope=self.scope.pop(indent) 408*fc1421ebSBram Moolenaar tokentype, cname, ind = self.next() 409*fc1421ebSBram Moolenaar if tokentype != NAME: return None 410*fc1421ebSBram Moolenaar 411*fc1421ebSBram Moolenaar super = [] 412*fc1421ebSBram Moolenaar tokentype, next, ind = self.next() 413*fc1421ebSBram Moolenaar if next == '(': 414*fc1421ebSBram Moolenaar super=self._parenparse() 415*fc1421ebSBram Moolenaar elif next != ':': return None 416*fc1421ebSBram Moolenaar 417*fc1421ebSBram Moolenaar return Class(cname,super,indent) 418*fc1421ebSBram Moolenaar 419*fc1421ebSBram Moolenaar def _parseassignment(self): 420*fc1421ebSBram Moolenaar assign='' 421*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 422*fc1421ebSBram Moolenaar if tokentype == tokenize.STRING or token == 'str': 423*fc1421ebSBram Moolenaar return '""' 424*fc1421ebSBram Moolenaar elif token == '[' or token == 'list': 425*fc1421ebSBram Moolenaar return '[]' 426*fc1421ebSBram Moolenaar elif token == '{' or token == 'dict': 427*fc1421ebSBram Moolenaar return '{}' 428*fc1421ebSBram Moolenaar elif tokentype == tokenize.NUMBER: 429*fc1421ebSBram Moolenaar return '0' 430*fc1421ebSBram Moolenaar elif token == 'open' or token == 'file': 431*fc1421ebSBram Moolenaar return 'file' 432*fc1421ebSBram Moolenaar elif token == 'None': 433*fc1421ebSBram Moolenaar return '_PyCmplNoType()' 434*fc1421ebSBram Moolenaar elif token == 'type': 435*fc1421ebSBram Moolenaar return 'type(_PyCmplNoType)' #only for method resolution 436*fc1421ebSBram Moolenaar else: 437*fc1421ebSBram Moolenaar assign += token 438*fc1421ebSBram Moolenaar level = 0 439*fc1421ebSBram Moolenaar while True: 440*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 441*fc1421ebSBram Moolenaar if token in ('(','{','['): 442*fc1421ebSBram Moolenaar level += 1 443*fc1421ebSBram Moolenaar elif token in (']','}',')'): 444*fc1421ebSBram Moolenaar level -= 1 445*fc1421ebSBram Moolenaar if level == 0: break 446*fc1421ebSBram Moolenaar elif level == 0: 447*fc1421ebSBram Moolenaar if token in (';','\n'): break 448*fc1421ebSBram Moolenaar assign += token 449*fc1421ebSBram Moolenaar return "%s" % assign 450*fc1421ebSBram Moolenaar 451*fc1421ebSBram Moolenaar def next(self): 452*fc1421ebSBram Moolenaar type, token, (lineno, indent), end, self.parserline = self.gen.next() 453*fc1421ebSBram Moolenaar if lineno == self.curline: 454*fc1421ebSBram Moolenaar #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name) 455*fc1421ebSBram Moolenaar self.currentscope = self.scope 456*fc1421ebSBram Moolenaar return (type, token, indent) 457*fc1421ebSBram Moolenaar 458*fc1421ebSBram Moolenaar def _adjustvisibility(self): 459*fc1421ebSBram Moolenaar newscope = Scope('result',0) 460*fc1421ebSBram Moolenaar scp = self.currentscope 461*fc1421ebSBram Moolenaar while scp != None: 462*fc1421ebSBram Moolenaar if type(scp) == Function: 463*fc1421ebSBram Moolenaar slice = 0 464*fc1421ebSBram Moolenaar #Handle 'self' params 465*fc1421ebSBram Moolenaar if scp.parent != None and type(scp.parent) == Class: 466*fc1421ebSBram Moolenaar slice = 1 467*fc1421ebSBram Moolenaar p = scp.params[0] 468*fc1421ebSBram Moolenaar i = p.find('=') 469*fc1421ebSBram Moolenaar if i != -1: p = p[:i] 470*fc1421ebSBram Moolenaar newscope.local('%s = %s' % (scp.params[0],scp.parent.name)) 471*fc1421ebSBram Moolenaar for p in scp.params[slice:]: 472*fc1421ebSBram Moolenaar i = p.find('=') 473*fc1421ebSBram Moolenaar if i == -1: 474*fc1421ebSBram Moolenaar newscope.local('%s = _PyCmplNoType()' % p) 475*fc1421ebSBram Moolenaar else: 476*fc1421ebSBram Moolenaar newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1]))) 477*fc1421ebSBram Moolenaar 478*fc1421ebSBram Moolenaar for s in scp.subscopes: 479*fc1421ebSBram Moolenaar ns = s.copy_decl(0) 480*fc1421ebSBram Moolenaar newscope.add(ns) 481*fc1421ebSBram Moolenaar for l in scp.locals: newscope.local(l) 482*fc1421ebSBram Moolenaar scp = scp.parent 483*fc1421ebSBram Moolenaar 484*fc1421ebSBram Moolenaar self.currentscope = newscope 485*fc1421ebSBram Moolenaar return self.currentscope 486*fc1421ebSBram Moolenaar 487*fc1421ebSBram Moolenaar #p.parse(vim.current.buffer[:],vim.eval("line('.')")) 488*fc1421ebSBram Moolenaar def parse(self,text,curline=0): 489*fc1421ebSBram Moolenaar self.curline = int(curline) 490*fc1421ebSBram Moolenaar buf = cStringIO.StringIO(''.join(text) + '\n') 491*fc1421ebSBram Moolenaar self.gen = tokenize.generate_tokens(buf.readline) 492*fc1421ebSBram Moolenaar self.currentscope = self.scope 493*fc1421ebSBram Moolenaar 494*fc1421ebSBram Moolenaar try: 495*fc1421ebSBram Moolenaar freshscope=True 496*fc1421ebSBram Moolenaar while True: 497*fc1421ebSBram Moolenaar tokentype, token, indent = self.next() 498*fc1421ebSBram Moolenaar #print 'main: token=[%s] indent=[%s]' % (token,indent) 499*fc1421ebSBram Moolenaar 500*fc1421ebSBram Moolenaar if tokentype == DEDENT: 501*fc1421ebSBram Moolenaar self.scope = self.scope.pop(indent) 502*fc1421ebSBram Moolenaar elif token == 'def': 503*fc1421ebSBram Moolenaar func = self._parsefunction(indent) 504*fc1421ebSBram Moolenaar if func == None: 505*fc1421ebSBram Moolenaar print "function: syntax error..." 506*fc1421ebSBram Moolenaar continue 507*fc1421ebSBram Moolenaar freshscope = True 508*fc1421ebSBram Moolenaar self.scope = self.scope.add(func) 509*fc1421ebSBram Moolenaar elif token == 'class': 510*fc1421ebSBram Moolenaar cls = self._parseclass(indent) 511*fc1421ebSBram Moolenaar if cls == None: 512*fc1421ebSBram Moolenaar print "class: syntax error..." 513*fc1421ebSBram Moolenaar continue 514*fc1421ebSBram Moolenaar freshscope = True 515*fc1421ebSBram Moolenaar self.scope = self.scope.add(cls) 516*fc1421ebSBram Moolenaar 517*fc1421ebSBram Moolenaar elif token == 'import': 518*fc1421ebSBram Moolenaar imports = self._parseimportlist() 519*fc1421ebSBram Moolenaar for mod, alias in imports: 520*fc1421ebSBram Moolenaar loc = "import %s" % mod 521*fc1421ebSBram Moolenaar if len(alias) > 0: loc += " as %s" % alias 522*fc1421ebSBram Moolenaar self.scope.local(loc) 523*fc1421ebSBram Moolenaar freshscope = False 524*fc1421ebSBram Moolenaar elif token == 'from': 525*fc1421ebSBram Moolenaar mod, token = self._parsedotname() 526*fc1421ebSBram Moolenaar if not mod or token != "import": 527*fc1421ebSBram Moolenaar print "from: syntax error..." 528*fc1421ebSBram Moolenaar continue 529*fc1421ebSBram Moolenaar names = self._parseimportlist() 530*fc1421ebSBram Moolenaar for name, alias in names: 531*fc1421ebSBram Moolenaar loc = "from %s import %s" % (mod,name) 532*fc1421ebSBram Moolenaar if len(alias) > 0: loc += " as %s" % alias 533*fc1421ebSBram Moolenaar self.scope.local(loc) 534*fc1421ebSBram Moolenaar freshscope = False 535*fc1421ebSBram Moolenaar elif tokentype == STRING: 536*fc1421ebSBram Moolenaar if freshscope: self.scope.doc(token) 537*fc1421ebSBram Moolenaar elif tokentype == NAME: 538*fc1421ebSBram Moolenaar name,token = self._parsedotname(token) 539*fc1421ebSBram Moolenaar if token == '=': 540*fc1421ebSBram Moolenaar stmt = self._parseassignment() 541*fc1421ebSBram Moolenaar if stmt != None: 542*fc1421ebSBram Moolenaar self.scope.local("%s = %s" % (name,stmt)) 543*fc1421ebSBram Moolenaar freshscope = False 544*fc1421ebSBram Moolenaar except StopIteration: #thrown on EOF 545*fc1421ebSBram Moolenaar pass 546*fc1421ebSBram Moolenaar except: 547*fc1421ebSBram Moolenaar dbg("parse error: %s, %s @ %s" % 548*fc1421ebSBram Moolenaar (sys.exc_info()[0], sys.exc_info()[1], self.parserline)) 549*fc1421ebSBram Moolenaar return self._adjustvisibility() 550*fc1421ebSBram Moolenaar 551*fc1421ebSBram Moolenaardef _sanitize(str): 552*fc1421ebSBram Moolenaar val = '' 553*fc1421ebSBram Moolenaar level = 0 554*fc1421ebSBram Moolenaar for c in str: 555*fc1421ebSBram Moolenaar if c in ('(','{','['): 556*fc1421ebSBram Moolenaar level += 1 55718144c84SBram Moolenaar elif c in (']','}',')'): 55818144c84SBram Moolenaar level -= 1 559*fc1421ebSBram Moolenaar elif level == 0: 560*fc1421ebSBram Moolenaar val += c 56118144c84SBram Moolenaar return val 56218144c84SBram Moolenaar 56318144c84SBram Moolenaarsys.path.extend(['.','..']) 56418144c84SBram MoolenaarPYTHONEOF 56518144c84SBram Moolenaarendfunction 56618144c84SBram Moolenaar 56718144c84SBram Moolenaarcall s:DefPython() 568" vim: set et ts=4: 569