diff unixSoft/lib/python/rlcompleter_ng.py @ 0:c30d68fbd368

Initial import from svn.
author Augie Fackler <durin42@gmail.com>
date Wed, 26 Nov 2008 10:56:09 -0600
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/unixSoft/lib/python/rlcompleter_ng.py
@@ -0,0 +1,250 @@
+"""
+rlcompleter_ng
+==============
+
+This module represents an alternative to rlcompleter and rlcompleter2,
+for those who don't like their default behaviour.
+
+There are two main differences between stdlib's rlcompleter and
+rlcompleter_ng:
+
+  - when doing something like a.b.c.<TAB>, rlcompleter prepends a.b.c
+    to all the completions it finds; rlcompleter_ng displays only the
+    attributes, making the screen less cluttered;
+
+  - you can use the <TAB> key both to indent (when the current line is
+    blank) or to complete (when it's not blank);
+
+  - more important, rlcompleter_ng prints the various attributes found
+    in different colors depending on their type.
+
+Unfortunately, the default version of libreadline don't support
+colored completions, so you need to patch it to fully exploid
+rlcompleter_ng capabilities.
+
+You can find the patch here:
+http://codespeak.net/svn/user/antocuni/hack/readline-escape.patch
+
+Alternatively, you can download the Ubuntu Hardy i386 package from here (thanks
+to Alexander Schremmer):
+http://antosreadlineforhardy.alexanderweb.de/libreadline5_5.2-3build1pypy_i386.deb
+
+Installation
+------------
+
+Simply put the file rlcompleter_ng.py in a directory which is in your
+PYTHONPATH.
+
+Configuration
+-------------
+
+Since it requires a patched version of libreadline, coloured
+completions are disabled by default.
+
+To customize the configuration of rlcompleter_ng, you need to put a
+file named .rlcompleter_ngrc.py in your home directory.  The file must
+contain a class named ``Config`` inheriting from ``DefaultConfig`` and
+overridding the desired values.
+
+You can find a sample configuration file, which enables colors, here:
+http://codespeak.net/svn/user/antocuni/hack/rlcompleter_ngrc.py
+
+Usage
+-----
+
+From the interactive prompt, import rlcompleter_ng and call setup():
+
+>>> import rlcompleter_ng
+>>> rlcompleter_ng.setup()
+
+Alternatively, you can put these lines in some file that it's
+referenced by the PYTHONSTARTUP environment variable, so that
+completions is always enabled.
+"""
+
+__version__='0.1'
+__author__ ='Antonio Cuni <anto.cuni@gmail.com>'
+__url__='http://codespeak.net/svn/user/antocuni/hack/rlcompleter_ng.py'
+
+
+import readline
+import rlcompleter
+import types
+import os.path
+from itertools import izip, count
+
+class colors:
+    black = '30'
+    darkred = '31'
+    darkgreen = '32'    
+    brown = '33'
+    darkblue = '34'
+    purple = '35'
+    teal = '36'
+    lightgray = '37'
+    darkgray = '30;01'
+    red = '31;01'
+    green = '32;01'
+    yellow = '33;01'
+    blue = '34;01'
+    fuchsia = '35;01'
+    turquoise = '36;01'
+    white = '37;01'
+
+
+class DefaultConfig:
+
+    # WARNING: for this option to work properly, you need to patch readline with this:
+    # http://codespeak.net/svn/user/antocuni/hack/readline-escape.patch
+    use_colors = False
+    
+    color_by_type = {
+        types.BuiltinMethodType: colors.turquoise,
+        types.BuiltinMethodType: colors.turquoise,
+        types.MethodType: colors.turquoise,
+        type((42).__add__): colors.turquoise,
+        type(int.__add__): colors.turquoise,
+        type(str.replace): colors.turquoise,
+
+        types.FunctionType: colors.blue,
+        types.BuiltinFunctionType: colors.blue,
+        
+        types.ClassType: colors.fuchsia,
+        type: colors.fuchsia,
+        
+        types.ModuleType: colors.teal,
+        types.NoneType: colors.lightgray,
+        str: colors.green,
+        unicode: colors.green,
+        int: colors.yellow,
+        float: colors.yellow,
+        complex: colors.yellow,
+        bool: colors.yellow,
+        }
+
+
+def setcolor(s, color):
+    return '\x1b[%sm%s\x1b[00m' % (color, s)
+
+
+class ConfigurableClass:
+    DefaultConfig = None
+    config_filename = None
+
+    def get_config(self, Config):
+        if Config is not None:
+            return Config()
+        # try to load config from the ~/filename file
+        filename = '~/' + self.config_filename
+        rcfile = os.path.expanduser(filename)
+        if os.path.exists(rcfile):
+            mydict = {}
+            try:
+                execfile(rcfile, mydict)
+                return mydict['Config']()
+            except Exception, e:
+                print '** error when importing %s: %s **' % (s, e)
+        return self.DefaultConfig()
+
+
+class Completer(rlcompleter.Completer, ConfigurableClass):
+    """
+    When doing someting like a.b.<TAB>, display only the attributes of
+    b instead of the full a.b.attr string.
+    
+    Optionally, display the various completions in different colors
+    depending on the type.
+    """
+
+    DefaultConfig = DefaultConfig
+    config_filename = '.rlcompleter_ngrc.py'
+
+    def __init__(self, namespace = None, Config=None):
+        rlcompleter.Completer.__init__(self, namespace)
+        self.config = self.get_config(Config)
+        if self.config.use_colors:
+            readline.parse_and_bind('set dont-escape-ctrl-chars on')
+
+    def complete(self, text, state):
+        """
+        stolen from:
+        http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812
+        """
+        if text == "":
+            return ['\t',None][state]
+        else:
+            return rlcompleter.Completer.complete(self,text,state)
+
+    def global_matches(self, text):
+        import keyword
+        names = rlcompleter.Completer.global_matches(self, text)
+        prefix = commonprefix(names)
+        if prefix and prefix != text:
+            return [prefix]
+
+        names.sort()
+        values = []
+        for name in names:
+            if name in keyword.kwlist:
+                values.append(None)
+            else:
+                values.append(eval(name, self.namespace))
+        matches = [self.color_for_obj(i, name, obj)
+                   for i, name, obj
+                   in izip(count(), names, values)]
+        return matches + [' ']
+
+    def attr_matches(self, text):
+        import re
+        m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
+        if not m:
+            return
+        expr, attr = m.group(1, 3)
+        object = eval(expr, self.namespace)
+        names = []
+        values = []
+        n = len(attr)
+        for word in dir(object):
+            if word[:n] == attr and word != "__builtins__":
+                names.append(word)
+                values.append(getattr(object, word))
+                
+        prefix = commonprefix(names)
+        if prefix and prefix != attr:
+            return ['%s.%s' % (expr, prefix)] # autocomplete prefix
+
+        matches = [self.color_for_obj(i, name, value)
+                   for i, name, value
+                   in izip(count(), names, values)]
+        return matches + [' ']
+
+    def color_for_obj(self, i, name, value):
+        if not self.config.use_colors:
+            return name
+        t = type(value)
+        color = self.config.color_by_type.get(t, '00')
+        # hack hack hack
+        # prepend a fake escape sequence, so that readline can sort the matches correctly
+        return '\x1b[%03d;00m' % i + setcolor(name, color)
+
+
+# stolen from rlcompleter2
+def commonprefix(names, base = ''):
+    """ return the common prefix of all 'names' starting with 'base'
+    """
+    def commonfunc(s1,s2):
+        while not s2.startswith(s1): 
+            s1=s1[:-1]
+        return s1
+
+    if base:
+        names = filter(lambda x, base=base: x.startswith(base), names)
+        if not names:
+            return ''
+    return reduce(commonfunc,names)
+
+
+def setup():
+    completer = Completer()
+    readline.parse_and_bind('tab: complete')
+    readline.set_completer(completer.complete)