0
|
1 """ |
|
2 rlcompleter_ng |
|
3 ============== |
|
4 |
|
5 This module represents an alternative to rlcompleter and rlcompleter2, |
|
6 for those who don't like their default behaviour. |
|
7 |
|
8 There are two main differences between stdlib's rlcompleter and |
|
9 rlcompleter_ng: |
|
10 |
|
11 - when doing something like a.b.c.<TAB>, rlcompleter prepends a.b.c |
|
12 to all the completions it finds; rlcompleter_ng displays only the |
|
13 attributes, making the screen less cluttered; |
|
14 |
|
15 - you can use the <TAB> key both to indent (when the current line is |
|
16 blank) or to complete (when it's not blank); |
|
17 |
|
18 - more important, rlcompleter_ng prints the various attributes found |
|
19 in different colors depending on their type. |
|
20 |
|
21 Unfortunately, the default version of libreadline don't support |
|
22 colored completions, so you need to patch it to fully exploid |
|
23 rlcompleter_ng capabilities. |
|
24 |
|
25 You can find the patch here: |
|
26 http://codespeak.net/svn/user/antocuni/hack/readline-escape.patch |
|
27 |
|
28 Alternatively, you can download the Ubuntu Hardy i386 package from here (thanks |
|
29 to Alexander Schremmer): |
|
30 http://antosreadlineforhardy.alexanderweb.de/libreadline5_5.2-3build1pypy_i386.deb |
|
31 |
|
32 Installation |
|
33 ------------ |
|
34 |
|
35 Simply put the file rlcompleter_ng.py in a directory which is in your |
|
36 PYTHONPATH. |
|
37 |
|
38 Configuration |
|
39 ------------- |
|
40 |
|
41 Since it requires a patched version of libreadline, coloured |
|
42 completions are disabled by default. |
|
43 |
|
44 To customize the configuration of rlcompleter_ng, you need to put a |
|
45 file named .rlcompleter_ngrc.py in your home directory. The file must |
|
46 contain a class named ``Config`` inheriting from ``DefaultConfig`` and |
|
47 overridding the desired values. |
|
48 |
|
49 You can find a sample configuration file, which enables colors, here: |
|
50 http://codespeak.net/svn/user/antocuni/hack/rlcompleter_ngrc.py |
|
51 |
|
52 Usage |
|
53 ----- |
|
54 |
|
55 From the interactive prompt, import rlcompleter_ng and call setup(): |
|
56 |
|
57 >>> import rlcompleter_ng |
|
58 >>> rlcompleter_ng.setup() |
|
59 |
|
60 Alternatively, you can put these lines in some file that it's |
|
61 referenced by the PYTHONSTARTUP environment variable, so that |
|
62 completions is always enabled. |
|
63 """ |
|
64 |
|
65 __version__='0.1' |
|
66 __author__ ='Antonio Cuni <anto.cuni@gmail.com>' |
|
67 __url__='http://codespeak.net/svn/user/antocuni/hack/rlcompleter_ng.py' |
|
68 |
|
69 |
|
70 import readline |
|
71 import rlcompleter |
|
72 import types |
|
73 import os.path |
|
74 from itertools import izip, count |
|
75 |
|
76 class colors: |
|
77 black = '30' |
|
78 darkred = '31' |
|
79 darkgreen = '32' |
|
80 brown = '33' |
|
81 darkblue = '34' |
|
82 purple = '35' |
|
83 teal = '36' |
|
84 lightgray = '37' |
|
85 darkgray = '30;01' |
|
86 red = '31;01' |
|
87 green = '32;01' |
|
88 yellow = '33;01' |
|
89 blue = '34;01' |
|
90 fuchsia = '35;01' |
|
91 turquoise = '36;01' |
|
92 white = '37;01' |
|
93 |
|
94 |
|
95 class DefaultConfig: |
|
96 |
|
97 # WARNING: for this option to work properly, you need to patch readline with this: |
|
98 # http://codespeak.net/svn/user/antocuni/hack/readline-escape.patch |
|
99 use_colors = False |
|
100 |
|
101 color_by_type = { |
|
102 types.BuiltinMethodType: colors.turquoise, |
|
103 types.BuiltinMethodType: colors.turquoise, |
|
104 types.MethodType: colors.turquoise, |
|
105 type((42).__add__): colors.turquoise, |
|
106 type(int.__add__): colors.turquoise, |
|
107 type(str.replace): colors.turquoise, |
|
108 |
|
109 types.FunctionType: colors.blue, |
|
110 types.BuiltinFunctionType: colors.blue, |
|
111 |
|
112 types.ClassType: colors.fuchsia, |
|
113 type: colors.fuchsia, |
|
114 |
|
115 types.ModuleType: colors.teal, |
|
116 types.NoneType: colors.lightgray, |
|
117 str: colors.green, |
|
118 unicode: colors.green, |
|
119 int: colors.yellow, |
|
120 float: colors.yellow, |
|
121 complex: colors.yellow, |
|
122 bool: colors.yellow, |
|
123 } |
|
124 |
|
125 |
|
126 def setcolor(s, color): |
|
127 return '\x1b[%sm%s\x1b[00m' % (color, s) |
|
128 |
|
129 |
|
130 class ConfigurableClass: |
|
131 DefaultConfig = None |
|
132 config_filename = None |
|
133 |
|
134 def get_config(self, Config): |
|
135 if Config is not None: |
|
136 return Config() |
|
137 # try to load config from the ~/filename file |
|
138 filename = '~/' + self.config_filename |
|
139 rcfile = os.path.expanduser(filename) |
|
140 if os.path.exists(rcfile): |
|
141 mydict = {} |
|
142 try: |
|
143 execfile(rcfile, mydict) |
|
144 return mydict['Config']() |
|
145 except Exception, e: |
|
146 print '** error when importing %s: %s **' % (s, e) |
|
147 return self.DefaultConfig() |
|
148 |
|
149 |
|
150 class Completer(rlcompleter.Completer, ConfigurableClass): |
|
151 """ |
|
152 When doing someting like a.b.<TAB>, display only the attributes of |
|
153 b instead of the full a.b.attr string. |
|
154 |
|
155 Optionally, display the various completions in different colors |
|
156 depending on the type. |
|
157 """ |
|
158 |
|
159 DefaultConfig = DefaultConfig |
|
160 config_filename = '.rlcompleter_ngrc.py' |
|
161 |
|
162 def __init__(self, namespace = None, Config=None): |
|
163 rlcompleter.Completer.__init__(self, namespace) |
|
164 self.config = self.get_config(Config) |
|
165 if self.config.use_colors: |
|
166 readline.parse_and_bind('set dont-escape-ctrl-chars on') |
|
167 |
|
168 def complete(self, text, state): |
|
169 """ |
|
170 stolen from: |
|
171 http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/496812 |
|
172 """ |
|
173 if text == "": |
|
174 return ['\t',None][state] |
|
175 else: |
|
176 return rlcompleter.Completer.complete(self,text,state) |
|
177 |
|
178 def global_matches(self, text): |
|
179 import keyword |
|
180 names = rlcompleter.Completer.global_matches(self, text) |
|
181 prefix = commonprefix(names) |
|
182 if prefix and prefix != text: |
|
183 return [prefix] |
|
184 |
|
185 names.sort() |
|
186 values = [] |
|
187 for name in names: |
|
188 if name in keyword.kwlist: |
|
189 values.append(None) |
|
190 else: |
|
191 values.append(eval(name, self.namespace)) |
|
192 matches = [self.color_for_obj(i, name, obj) |
|
193 for i, name, obj |
|
194 in izip(count(), names, values)] |
|
195 return matches + [' '] |
|
196 |
|
197 def attr_matches(self, text): |
|
198 import re |
|
199 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) |
|
200 if not m: |
|
201 return |
|
202 expr, attr = m.group(1, 3) |
|
203 object = eval(expr, self.namespace) |
|
204 names = [] |
|
205 values = [] |
|
206 n = len(attr) |
|
207 for word in dir(object): |
|
208 if word[:n] == attr and word != "__builtins__": |
|
209 names.append(word) |
|
210 values.append(getattr(object, word)) |
|
211 |
|
212 prefix = commonprefix(names) |
|
213 if prefix and prefix != attr: |
|
214 return ['%s.%s' % (expr, prefix)] # autocomplete prefix |
|
215 |
|
216 matches = [self.color_for_obj(i, name, value) |
|
217 for i, name, value |
|
218 in izip(count(), names, values)] |
|
219 return matches + [' '] |
|
220 |
|
221 def color_for_obj(self, i, name, value): |
|
222 if not self.config.use_colors: |
|
223 return name |
|
224 t = type(value) |
|
225 color = self.config.color_by_type.get(t, '00') |
|
226 # hack hack hack |
|
227 # prepend a fake escape sequence, so that readline can sort the matches correctly |
|
228 return '\x1b[%03d;00m' % i + setcolor(name, color) |
|
229 |
|
230 |
|
231 # stolen from rlcompleter2 |
|
232 def commonprefix(names, base = ''): |
|
233 """ return the common prefix of all 'names' starting with 'base' |
|
234 """ |
|
235 def commonfunc(s1,s2): |
|
236 while not s2.startswith(s1): |
|
237 s1=s1[:-1] |
|
238 return s1 |
|
239 |
|
240 if base: |
|
241 names = filter(lambda x, base=base: x.startswith(base), names) |
|
242 if not names: |
|
243 return '' |
|
244 return reduce(commonfunc,names) |
|
245 |
|
246 |
|
247 def setup(): |
|
248 completer = Completer() |
|
249 readline.parse_and_bind('tab: complete') |
|
250 readline.set_completer(completer.complete) |