|
1 # -*- coding: utf-8 -*- |
|
2 |
|
3 """ |
|
4 Word completion for the eric4 shell |
|
5 |
|
6 <h4>NOTE for eric4 variant</h4> |
|
7 |
|
8 This version is a re-implementation of FlexCompleter |
|
9 as found in the PyQwt package. It is modified to work with the eric4 debug |
|
10 clients. |
|
11 |
|
12 |
|
13 <h4>NOTE for the PyQwt variant</h4> |
|
14 |
|
15 This version is a re-implementation of FlexCompleter |
|
16 with readline support for PyQt&sip-3.6 and earlier. |
|
17 |
|
18 Full readline support is present in PyQt&sip-snapshot-20030531 and later. |
|
19 |
|
20 |
|
21 <h4>NOTE for FlexCompleter</h4> |
|
22 |
|
23 This version is a re-implementation of rlcompleter with |
|
24 selectable namespace. |
|
25 |
|
26 The problem with rlcompleter is that it's hardwired to work with |
|
27 __main__.__dict__, and in some cases one may have 'sandboxed' namespaces. So |
|
28 this class is a ripoff of rlcompleter, with the namespace to work in as an |
|
29 optional parameter. |
|
30 |
|
31 This class can be used just like rlcompleter, but the Completer class now has |
|
32 a constructor with the optional 'namespace' parameter. |
|
33 |
|
34 A patch has been submitted to Python@sourceforge for these changes to go in |
|
35 the standard Python distribution. |
|
36 |
|
37 |
|
38 <h4>Original rlcompleter documentation</h4> |
|
39 |
|
40 This requires the latest extension to the readline module (the |
|
41 completes keywords, built-ins and globals in __main__; when completing |
|
42 NAME.NAME..., it evaluates (!) the expression up to the last dot and |
|
43 completes its attributes. |
|
44 |
|
45 It's very cool to do "import string" type "string.", hit the |
|
46 completion key (twice), and see the list of names defined by the |
|
47 string module! |
|
48 |
|
49 Tip: to use the tab key as the completion key, call |
|
50 |
|
51 'readline.parse_and_bind("tab: complete")' |
|
52 |
|
53 <b>Notes</b>: |
|
54 <ul> |
|
55 <li> |
|
56 Exceptions raised by the completer function are *ignored* (and |
|
57 generally cause the completion to fail). This is a feature -- since |
|
58 readline sets the tty device in raw (or cbreak) mode, printing a |
|
59 traceback wouldn't work well without some complicated hoopla to save, |
|
60 reset and restore the tty state. |
|
61 </li> |
|
62 <li> |
|
63 The evaluation of the NAME.NAME... form may cause arbitrary |
|
64 application defined code to be executed if an object with a |
|
65 __getattr__ hook is found. Since it is the responsibility of the |
|
66 application (or the user) to enable this feature, I consider this an |
|
67 acceptable risk. More complicated expressions (e.g. function calls or |
|
68 indexing operations) are *not* evaluated. |
|
69 </li> |
|
70 <li> |
|
71 GNU readline is also used by the built-in functions input() and |
|
72 raw_input(), and thus these also benefit/suffer from the completer |
|
73 features. Clearly an interactive application can benefit by |
|
74 specifying its own completer function and using raw_input() for all |
|
75 its input. |
|
76 </li> |
|
77 <li> |
|
78 When the original stdin is not a tty device, GNU readline is never |
|
79 used, and this module (and the readline module) are silently inactive. |
|
80 </li> |
|
81 </ul> |
|
82 """ |
|
83 |
|
84 #***************************************************************************** |
|
85 # |
|
86 # Since this file is essentially a minimally modified copy of the rlcompleter |
|
87 # module which is part of the standard Python distribution, I assume that the |
|
88 # proper procedure is to maintain its copyright as belonging to the Python |
|
89 # Software Foundation: |
|
90 # |
|
91 # Copyright (C) 2001 Python Software Foundation, www.python.org |
|
92 # |
|
93 # Distributed under the terms of the Python Software Foundation license. |
|
94 # |
|
95 # Full text available at: |
|
96 # |
|
97 # http://www.python.org/2.1/license.html |
|
98 # |
|
99 #***************************************************************************** |
|
100 |
|
101 import __builtin__ |
|
102 import __main__ |
|
103 |
|
104 __all__ = ["Completer"] |
|
105 |
|
106 class Completer(object): |
|
107 """ |
|
108 Class implementing the command line completer object. |
|
109 """ |
|
110 def __init__(self, namespace = None): |
|
111 """ |
|
112 Create a new completer for the command line. |
|
113 |
|
114 Completer([namespace]) -> completer instance. |
|
115 |
|
116 If unspecified, the default namespace where completions are performed |
|
117 is __main__ (technically, __main__.__dict__). Namespaces should be |
|
118 given as dictionaries. |
|
119 |
|
120 Completer instances should be used as the completion mechanism of |
|
121 readline via the set_completer() call: |
|
122 |
|
123 readline.set_completer(Completer(my_namespace).complete) |
|
124 |
|
125 @param namespace The namespace for the completer. |
|
126 """ |
|
127 |
|
128 if namespace and type(namespace) != type({}): |
|
129 raise TypeError,'namespace must be a dictionary' |
|
130 |
|
131 # Don't bind to namespace quite yet, but flag whether the user wants a |
|
132 # specific namespace or to use __main__.__dict__. This will allow us |
|
133 # to bind to __main__.__dict__ at completion time, not now. |
|
134 if namespace is None: |
|
135 self.use_main_ns = 1 |
|
136 else: |
|
137 self.use_main_ns = 0 |
|
138 self.namespace = namespace |
|
139 |
|
140 def complete(self, text, state): |
|
141 """ |
|
142 Return the next possible completion for 'text'. |
|
143 |
|
144 This is called successively with state == 0, 1, 2, ... until it |
|
145 returns None. The completion should begin with 'text'. |
|
146 |
|
147 @param text The text to be completed. (string) |
|
148 @param state The state of the completion. (integer) |
|
149 @return The possible completions as a list of strings. |
|
150 """ |
|
151 if self.use_main_ns: |
|
152 self.namespace = __main__.__dict__ |
|
153 |
|
154 if state == 0: |
|
155 if "." in text: |
|
156 self.matches = self.attr_matches(text) |
|
157 else: |
|
158 self.matches = self.global_matches(text) |
|
159 try: |
|
160 return self.matches[state] |
|
161 except IndexError: |
|
162 return None |
|
163 |
|
164 def global_matches(self, text): |
|
165 """ |
|
166 Compute matches when text is a simple name. |
|
167 |
|
168 @param text The text to be completed. (string) |
|
169 @return A list of all keywords, built-in functions and names currently |
|
170 defined in self.namespace that match. |
|
171 """ |
|
172 import keyword |
|
173 matches = [] |
|
174 n = len(text) |
|
175 for list in [keyword.kwlist, |
|
176 __builtin__.__dict__.keys(), |
|
177 self.namespace.keys()]: |
|
178 for word in list: |
|
179 if word[:n] == text and word != "__builtins__" and not word in matches: |
|
180 matches.append(word) |
|
181 return matches |
|
182 |
|
183 def attr_matches(self, text): |
|
184 """ |
|
185 Compute matches when text contains a dot. |
|
186 |
|
187 Assuming the text is of the form NAME.NAME....[NAME], and is |
|
188 evaluatable in self.namespace, it will be evaluated and its attributes |
|
189 (as revealed by dir()) are used as possible completions. (For class |
|
190 instances, class members are are also considered.) |
|
191 |
|
192 <b>WARNING</b>: this can still invoke arbitrary C code, if an object |
|
193 with a __getattr__ hook is evaluated. |
|
194 |
|
195 @param text The text to be completed. (string) |
|
196 @return A list of all matches. |
|
197 """ |
|
198 import re |
|
199 |
|
200 # Testing. This is the original code: |
|
201 #m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) |
|
202 |
|
203 # Modified to catch [] in expressions: |
|
204 #m = re.match(r"([\w\[\]]+(\.[\w\[\]]+)*)\.(\w*)", text) |
|
205 |
|
206 # Another option, seems to work great. Catches things like ''.<tab> |
|
207 m = re.match(r"(\S+(\.\w+)*)\.(\w*)", text) |
|
208 |
|
209 if not m: |
|
210 return |
|
211 expr, attr = m.group(1, 3) |
|
212 object = eval(expr, self.namespace) |
|
213 words = dir(object) |
|
214 if hasattr(object,'__class__'): |
|
215 words.append('__class__') |
|
216 words = words + get_class_members(object.__class__) |
|
217 matches = [] |
|
218 n = len(attr) |
|
219 for word in words: |
|
220 try: |
|
221 if word[:n] == attr and word != "__builtins__": |
|
222 match = "%s.%s" % (expr, word) |
|
223 if not match in matches: |
|
224 matches.append(match) |
|
225 except: |
|
226 # some badly behaved objects pollute dir() with non-strings, |
|
227 # which cause the completion to fail. This way we skip the |
|
228 # bad entries and can still continue processing the others. |
|
229 pass |
|
230 return matches |
|
231 |
|
232 def get_class_members(klass): |
|
233 """ |
|
234 Module function to retrieve the class members. |
|
235 |
|
236 @param klass The class object to be analysed. |
|
237 @return A list of all names defined in the class. |
|
238 """ |
|
239 # PyQwt's hack for PyQt&sip-3.6 and earlier |
|
240 if hasattr(klass, 'getLazyNames'): |
|
241 return klass.getLazyNames() |
|
242 # vanilla Python stuff |
|
243 ret = dir(klass) |
|
244 if hasattr(klass,'__bases__'): |
|
245 for base in klass.__bases__: |
|
246 ret = ret + get_class_members(base) |
|
247 return ret |