All pastes #446932 Raw Edit

omni

public python v1 · immutable
·published 2007-04-18 19:06 UTC
rendered paste body
"pythoncomplete.vim"" dodac do .vimrc" autocmd FileType python set omnifunc=pythoncomplete#Complete" set completeopt=menu,longest,preview" autocmd FileType python set et sts=4 sw=4if !has('python')    echo "Error: Required vim compiled with +python"    finishendiffunction! pythoncomplete#Complete(findstart, base)    "findstart = 1 when we need to get the text length    if a:findstart == 1        let line = getline('.')        let idx = col('.')        while idx > 0            let idx -= 1            let c = line[idx]            if c =~ '\w'                continue            elseif ! c =~ '\.'                idx = -1                break            else                break            endif        endwhile        return idx    "findstart = 0 when we need to return the list of completions    else        "vim no longer moves the cursor upon completion... fix that        let line = getline('.')        let idx = col('.')        let cword = ''        while idx > 0            let idx -= 1            let c = line[idx]            if c =~ '\w' || c =~ '\.'                let cword = c . cword                continue            elseif strlen(cword) > 0 || idx == 0                break            endif        endwhile        execute "python vimcomplete('" . cword . "', '" . a:base . "')"        return g:pythoncomplete_completions    endifendfunctionfunction! s:DefPython()python << PYTHONEOFimport sys, tokenize, cStringIO, typesfrom token import NAME, DEDENT, NEWLINE, STRINGdebugstmts=[]def dbg(s): debugstmts.append(s)def showdbg():    for d in debugstmts: print "DBG: %s " % ddef vimcomplete(context,match):    global debugstmts    debugstmts = []    try:        import vim        def complsort(x,y):            return x['abbr'] > y['abbr']        #ocmpl = CompleterORIG()	cmpl = Completer()	#dbg("context: %s" % context)	#import time	#dbg("match: %s" % match)	#time.sleep(4)        cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')"))        #all = ocmpl.get_completions(context,match)	all = cmpl.all_completions(str(context)+str(match))        all.sort(complsort)	#all = []        dictstr = '['        # have to do this for double quoting        for cmpl in all:            dictstr += '{'            for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x])            dictstr += '"icase":0},'        if dictstr[-1] == ',': dictstr = dictstr[:-1]        dictstr += ']'        dbg("dict: %s" % dictstr)        vim.command("silent let g:pythoncomplete_completions = %s" % dictstr)        #dbg("Completion dict:\n%s" % all)    except vim.error:        dbg("VIM Error: %s" % vim.error)#############################################################################import __builtin__import __main__import globimport keywordimport osimport reimport shleximport sysimport itertoolsimport types# Python 2.4 offers sets as a builtintry:    set([1,2])except NameError:    from sets import Set as set__all__ = ['Completer']def get_class_members(cls):    ret = dir(cls)    if hasattr(cls,'__bases__'):        for base in cls.__bases__:            ret.extend(get_class_members(base))    return retclass Completer:    def __init__(self,namespace=None,global_namespace=None):        """Create a new completer for the command line.        Completer([namespace,global_namespace]) -> completer instance.        If unspecified, the default namespace where completions are performed        is __main__ (technically, __main__.__dict__). Namespaces should be        given as dictionaries.        An optional second namespace can be given.  This allows the completer        to handle cases where both the local and global scopes need to be        distinguished.        Completer instances should be used as the completion mechanism of        readline via the set_completer() call:        readline.set_completer(Completer(my_namespace).complete)        """        # some minimal strict typechecks.  For some core data structures, I        # want actual basic python types, not just anything that looks like        # one.  This is especially true for namespaces.        for ns in (namespace,global_namespace):            if ns is not None and type(ns) != types.DictType:                raise TypeError,'namespace must be a dictionary'        # Don't bind to namespace quite yet, but flag whether the user wants a        # specific namespace or to use __main__.__dict__. This will allow us        # to bind to __main__.__dict__ at completion time, not now.	self.namespace = __builtin__.__dict__	self.global_namespace = __builtin__.__dict__        if namespace is None:            self.use_main_ns = 1        else:            self.use_main_ns = 0            self.namespace = namespace        # The global namespace, if given, can be bound directly        if global_namespace is None:            self.global_namespace = {}        else:            self.global_namespace = global_namespace        self.compldict = {}        self.parser = PyParser()    def evalsource(self,text,line=0):        sc = self.parser.parse(text,line)        src = sc.get_code()        dbg("source: %s" % src)        try: exec(src) in self.namespace        except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1]))        for l in sc.locals:            try: exec(l) in self.global_namespace            except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l))	        def complete(self, text, state):        """Return the next possible completion for 'text'.        This is called successively with state == 0, 1, 2, ... until it        returns None.  The completion should begin with 'text'.        """        #if self.use_main_ns:    	#    self.namespace = __main__.__dict__                    if state == 0:            if "." in text:                self.matches = self.attr_matches(text)            else:                self.matches = self.global_matches(text)        try:            return self.matches[state]        except IndexError:            return None    def all_completions(self, text):        """Return all possible completions for the benefit of emacs."""        completions = []        comp_append = completions.append        try:            for i in xrange(sys.maxint):                res = self.complete(text, i)                if not res: break				##############		aaa = res[len(text):]		attr = None		doc = ''		try:        	    attr = eval(res, self.namespace)    		except:        	    try:            		attr = eval(res, self.global_namespace)        	    except:			if not self.is_keyword(res):			    continue			    		c = {'word':str(aaa), 'abbr':res,  'info':'','kind':''}		if self.is_keyword(res):            	    c['word'] = aaa                    c['kind'] = 'keyword'		elif self.is_type(attr):		    c['info'] = self.get_doc(attr)		    c['kind'] = 'type'                elif self.is_function(attr):                    c['word'] = aaa + '()'                    c['abbr'] = res + '()'                    c['kind'] = 'function'		elif self.is_method(attr):		    c['word'] = aaa + '()'		    c['abbr'] = res + '()'		    c['info'] = self.get_doc(attr)                    c['kind'] = 'method'		elif self.is_class(attr):		    c['info'] = self.get_doc(attr)                    c['kind'] = 'class'                elif self.is_module(attr):		    c['info'] = self.get_doc(attr)                    c['kind'] = 'module'                elif self.is_list(attr):                    #c['word'] += aaa                    #c['abbr'] += res		    c['info'] = self.get_doc(attr)                    c['kind']='list'		elif self.is_builtin_method(attr):		    c['word'] = aaa + '()'		    c['abbr'] = res + '()'		    c['info'] = self.get_doc(attr)                    c['kind']='builtinmethod'		elif self.is_builtin_function(attr):		    c['word'] = aaa + '()'		    c['abbr'] = res + '()'		    c['info'] = self.get_doc(attr)                    c['kind']='builtinfunction'		elif self.is_file(attr):		    c['info'] = self.get_doc(attr)                    c['kind'] = 'file'		elif self.is_string(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='string'		elif self.is_dict(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='dict'		elif self.is_int(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='int'		elif self.is_boolean(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='bool'		elif self.is_tuple(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='tuple'		elif self.is_instance(attr):		    c['info'] = self.get_doc(attr)                    c['kind']='instance'		elif self.is_none(attr):                    c['kind']='None'		###############                comp_append(c)        except NameError:            pass        return completions    def get_attr(self, x):	ret_attr = None	at = x.split('.')	at = ''.join(at[len(at)-1])	y = x[:-len(at)-1]	ml = [x, y, __main__, __builtin__]	for i in ml:	    #print "x:%s  y:%s  i:%s" % (x,y,i)	    try:		ret_attr = getattr(i, at)			    except:		continue	    break	return ret_attr	    def get_doc(self, x):	try:	    doc = x.__doc__        except:	    return ''	if doc == None:	    return ''	return doc.replace('"',' ')\                  .replace("'",' ')\                  .replace('\n',' ')\                  .replace('\r',' ')\                  .replace('',' ')	    def is_keyword(self, x):	return keyword.iskeyword(x)    def cmp_type(self, x, typ):	try:	    if type(x) is typ:		return True	    else:		return False	except:	    pass    def is_boolean(self, x):	return self.cmp_type(x, types.BooleanType)    def is_buffer(self, x):	return self.cmp_type(x, types.BufferType)    def is_builtin_function(self, x):	return self.cmp_type(x, types.BuiltinFunctionType)    def is_builtin_method(self, x):	return self.cmp_type(x, types.BuiltinMethodType)    def is_class(self, x):	return self.cmp_type(x, types.ClassType)    def is_dict(self, x):	return self.cmp_type(x, types.DictType)    def is_file(self, x):	return self.cmp_type(x, types.FileType)    def is_int(self, x):	return self.cmp_type(x, types.IntType)    def is_instance(self, x):	return self.cmp_type(x, types.InstanceType)    def is_none(self, x):	return self.cmp_type(x, types.NoneType)    def is_string(self, x):	return self.cmp_type(x, types.StringType)    def is_type(self, x):	return self.cmp_type(x, types.TypeType)    def is_tuple(self, x):	return self.cmp_type(x, types.TupleType)    def is_function(self, x):	return self.cmp_type(x, types.FunctionType)    def is_method(self, x):	return self.cmp_type(x, types.MethodType)    def is_module(self, x):	return self.cmp_type(x, types.ModuleType)    def is_list(self, x):	return self.cmp_type(x, types.ListType)	    def global_matches(self, text):        """Compute matches when text is a simple name.        Return a list of all keywords, built-in functions and names currently        defined in self.namespace or self.global_namespace that match.        """        matches = []        match_append = matches.append        n = len(text)        for lst in [keyword.kwlist,                    __builtin__.__dict__.keys(),                    self.namespace.keys(),                    self.global_namespace.keys()]:            for word in lst:                if word[:n] == text and word != "__builtins__":                    match_append(word)        return matches    def attr_matches(self, text):        """Compute matches when text contains a dot.        Assuming the text is of the form NAME.NAME....[NAME], and is        evaluatable in self.namespace or self.global_namespace, it will be        evaluated and its attributes (as revealed by dir()) are used as        possible completions.  (For class instances, class members are are        also considered.)        WARNING: this can still invoke arbitrary C code, if an object        with a __getattr__ hook is evaluated.        """        import re        # Another option, seems to work great. Catches things like ''.<tab>        m = re.match(r"(\S+(\.\w+)*)\.(\w*)$", text)        if not m:            return []                expr, attr = m.group(1, 3)        try:            object = eval(expr, self.namespace)        except:            try:                object = eval(expr, self.global_namespace)            except:                return []                        # Start building the attribute list via dir(), and then complete it        # with a few extra special-purpose calls.        words = dir(object)        if hasattr(object,'__class__'):            words.append('__class__')            words.extend(get_class_members(object.__class__))        # this is the 'dir' function for objects with Enthought's traits        if hasattr(object, 'trait_names'):            try:                words.extend(object.trait_names())                # eliminate possible duplicates, as some traits may also                # appear as normal attributes in the dir() call.                words = set(words)            except TypeError:                # This will happen if `object` is a class and not an instance.                pass        # Support for PyCrust-style _getAttributeNames magic method.        if hasattr(object, '_getAttributeNames'):            try:                words.extend(object._getAttributeNames())                # Eliminate duplicates.                words = set(words)            except TypeError:                # `object` is a class and not an instance.  Ignore                # this error.                pass        # filter out non-string attributes which may be stuffed by dir() calls        # and poor coding in third-party modules        words = [w for w in words                 if isinstance(w, basestring) and w != "__builtins__"]        # Build match list to return        n = len(attr)        return ["%s.%s" % (expr, w) for w in words if w[:n] == attr ]class Scope(object):    def __init__(self,name,indent):        self.subscopes = []        self.docstr = ''        self.locals = []        self.parent = None        self.name = name        self.indent = indent    def add(self,sub):        #print 'push scope: [%s@%s]' % (sub.name,sub.indent)        sub.parent = self        self.subscopes.append(sub)        return sub    def doc(self,str):        """ Clean up a docstring """        d = str.replace('\n',' ')        d = d.replace('\t',' ')        while d.find('  ') > -1: d = d.replace('  ',' ')        while d[0] in '"\'\t ': d = d[1:]        while d[-1] in '"\'\t ': d = d[:-1]        self.docstr = d    def local(self,loc):        if not self._hasvaralready(loc):            self.locals.append(loc)    def copy_decl(self,indent=0):        """ Copy a scope's declaration only, at the specified indent level - not local variables """        return Scope(self.name,indent)    def _hasvaralready(self,test):        "Convienance function... keep out duplicates"        if test.find('=') > -1:            var = test.split('=')[0].strip()            for l in self.locals:                if l.find('=') > -1 and var == l.split('=')[0].strip():                    return True        return False    def get_code(self):        # we need to start with this, to fix up broken completions        # hopefully this name is unique enough...        str = '"""'+self.docstr+'"""\n'        str += 'class _PyCmplNoType:\n    def __getattr__(self,name):\n        return None\n'        for sub in self.subscopes:            str += sub.get_code()        #str += '\n'.join(self.locals)+'\n'        return str    def pop(self,indent):        #print 'pop scope: [%s] to [%s]' % (self.indent,indent)        outer = self        while outer.parent != None and outer.indent >= indent:            outer = outer.parent        return outer    def currentindent(self):        #print 'parse current indent: %s' % self.indent        return '    '*self.indent    def childindent(self):        #print 'parse child indent: [%s]' % (self.indent+1)        return '    '*(self.indent+1)class Class(Scope):    def __init__(self, name, supers, indent):        Scope.__init__(self,name,indent)        self.supers = supers    def copy_decl(self,indent=0):        c = Class(self.name,self.supers,indent)        for s in self.subscopes:            c.add(s.copy_decl(indent+1))        return c    def get_code(self):        str = '%sclass %s' % (self.currentindent(),self.name)        if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers)        str += ':\n'        if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'        if len(self.subscopes) > 0:            for s in self.subscopes: str += s.get_code()        else:            str += '%spass\n' % self.childindent()        return strclass Function(Scope):    def __init__(self, name, params, indent):        Scope.__init__(self,name,indent)        self.params = params    def copy_decl(self,indent=0):        return Function(self.name,self.params,indent)    def get_code(self):        str = "%sdef %s(%s):\n" % \            (self.currentindent(),self.name,','.join(self.params))        if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n'        str += "%spass\n" % self.childindent()        return strclass PyParser:    def __init__(self):        self.top = Scope('global',0)        self.scope = self.top    def _parsedotname(self,pre=None):        #returns (dottedname, nexttoken)        name = []        if pre == None:            tokentype, token, indent = self.next()            if tokentype != NAME and token != '*':                return ('', token)        else: token = pre        name.append(token)        while True:            tokentype, token, indent = self.next()            if token != '.': break            tokentype, token, indent = self.next()            if tokentype != NAME: break            name.append(token)        return (".".join(name), token)    def _parseimportlist(self):        imports = []        while True:            name, token = self._parsedotname()            if not name: break            name2 = ''            if token == 'as': name2, token = self._parsedotname()            imports.append((name, name2))            while token != "," and "\n" not in token:                tokentype, token, indent = self.next()            if token != ",": break        return imports    def _parenparse(self):        name = ''        names = []        level = 1        while True:            tokentype, token, indent = self.next()            if token in (')', ',') and level == 1:                names.append(name)                name = ''            if token == '(':                level += 1            elif token == ')':                level -= 1                if level == 0: break            elif token == ',' and level == 1:                pass            else:                name += str(token)        return names    def _parsefunction(self,indent):        self.scope=self.scope.pop(indent)        tokentype, fname, ind = self.next()        if tokentype != NAME: return None        tokentype, open, ind = self.next()        if open != '(': return None        params=self._parenparse()        tokentype, colon, ind = self.next()        if colon != ':': return None        return Function(fname,params,indent)    def _parseclass(self,indent):        self.scope=self.scope.pop(indent)        tokentype, cname, ind = self.next()        if tokentype != NAME: return None        super = []        tokentype, next, ind = self.next()        if next == '(':            super=self._parenparse()        elif next != ':': return None        return Class(cname,super,indent)    def _parseassignment(self):        assign=''        tokentype, token, indent = self.next()        if tokentype == tokenize.STRING or token == 'str':              return '""'        elif token == '[' or token == 'list':            return '[]'        elif token == '{' or token == 'dict':            return '{}'        elif tokentype == tokenize.NUMBER:            return '0'        elif token == 'open' or token == 'file':            return 'file'        elif token == 'None':            return '_PyCmplNoType()'        elif token == 'type':            return 'type(_PyCmplNoType)' #only for method resolution        else:            assign += token            level = 0            while True:                tokentype, token, indent = self.next()                if token in ('(','{','['):                    level += 1                elif token in (']','}',')'):                    level -= 1                    if level == 0: break                elif level == 0:                    if token in (';','\n'): break                    assign += token        return "%s" % assign    def next(self):        type, token, (lineno, indent), end, self.parserline = self.gen.next()        if lineno == self.curline:            #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name)            self.currentscope = self.scope        return (type, token, indent)    def _adjustvisibility(self):        newscope = Scope('result',0)        scp = self.currentscope        while scp != None:            if type(scp) == Function:                slice = 0                #Handle 'self' params                if scp.parent != None and type(scp.parent) == Class:                    slice = 1                    p = scp.params[0]                    i = p.find('=')                    if i != -1: p = p[:i]                    newscope.local('%s = %s' % (scp.params[0],scp.parent.name))                for p in scp.params[slice:]:                    i = p.find('=')                    if i == -1:                        newscope.local('%s = _PyCmplNoType()' % p)                    else:                        newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1])))            for s in scp.subscopes:                ns = s.copy_decl(0)                newscope.add(ns)            for l in scp.locals: newscope.local(l)            scp = scp.parent        self.currentscope = newscope        return self.currentscope    #p.parse(vim.current.buffer[:],vim.eval("line('.')"))    def parse(self,text,curline=0):        self.curline = int(curline)        buf = cStringIO.StringIO(''.join(text) + '\n')        self.gen = tokenize.generate_tokens(buf.readline)        self.currentscope = self.scope        try:            freshscope=True            while True:                tokentype, token, indent = self.next()                #print 'main: token=[%s] indent=[%s]' % (token,indent)                if tokentype == DEDENT:                    self.scope = self.scope.pop(indent)                elif token == 'def':                    func = self._parsefunction(indent)                    if func == None:                        print "function: syntax error..."                        continue                    freshscope = True                    self.scope = self.scope.add(func)                elif token == 'class':                    cls = self._parseclass(indent)                    if cls == None:                        print "class: syntax error..."                        continue                    freshscope = True                    self.scope = self.scope.add(cls)                                    elif token == 'import':                    imports = self._parseimportlist()                    for mod, alias in imports:                        loc = "import %s" % mod                        if len(alias) > 0: loc += " as %s" % alias                        self.scope.local(loc)                    freshscope = False                elif token == 'from':                    mod, token = self._parsedotname()                    if not mod or token != "import":                        print "from: syntax error..."                        continue                    names = self._parseimportlist()                    for name, alias in names:                        loc = "from %s import %s" % (mod,name)                        if len(alias) > 0: loc += " as %s" % alias                        self.scope.local(loc)                    freshscope = False                elif tokentype == STRING:                    if freshscope: self.scope.doc(token)                elif tokentype == NAME:                    name,token = self._parsedotname(token)                     if token == '=':                        stmt = self._parseassignment()                        if stmt != None:                            self.scope.local("%s = %s" % (name,stmt))                    freshscope = False        except StopIteration: #thrown on EOF            pass        except:            dbg("parse error: %s, %s @ %s" %                (sys.exc_info()[0], sys.exc_info()[1], self.parserline))        return self._adjustvisibility()def _sanitize(str):    val = ''    level = 0    for c in str:        if c in ('(','{','['):            level += 1        elif c in (']','}',')'):            level -= 1        elif level == 0:            val += c    return valsys.path.extend(['.','..'])PYTHONEOFendfunctioncall s:DefPython()" vim: set et ts=4: