DebugClients/Python/FlexCompleter.py

changeset 0
de9c2efb9d02
child 15
f6ccc31d6e72
equal deleted inserted replaced
-1:000000000000 0:de9c2efb9d02
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

eric ide

mercurial