src/eric7/DebugClients/Python/FlexCompleter.py

branch
eric7-maintenance
changeset 9264
18a7312cfdb3
parent 9221
bf71ee032bb4
child 9473
3f23dbf37dbe
equal deleted inserted replaced
9241:d23e9854aea4 9264:18a7312cfdb3
1 # -*- coding: utf-8 -*-
2
3 """
4 Word completion for the eric shell.
5
6 <h4>NOTE for eric variant</h4>
7
8 This version is a re-implementation of rlcompleter
9 as found in the Python3 library. It is modified to work with the eric
10 debug clients.
11
12 <h4>Original rlcompleter documentation</h4>
13
14 This requires the latest extension to the readline module. The completer
15 completes keywords, built-ins and globals in a selectable namespace (which
16 defaults to __main__); when completing NAME.NAME..., it evaluates (!) the
17 expression up to the last dot and completes its attributes.
18
19 It's very cool to do "import sys" type "sys.", hit the
20 completion key (twice), and see the list of names defined by the
21 sys module!
22
23 Tip: to use the tab key as the completion key, call
24
25 readline.parse_and_bind("tab: complete")
26
27 <b>Notes</b>:
28 <ul>
29 <li>
30 Exceptions raised by the completer function are *ignored* (and
31 generally cause the completion to fail). This is a feature -- since
32 readline sets the tty device in raw (or cbreak) mode, printing a
33 traceback wouldn't work well without some complicated hoopla to save,
34 reset and restore the tty state.
35 </li>
36 <li>
37 The evaluation of the NAME.NAME... form may cause arbitrary
38 application defined code to be executed if an object with a
39 __getattr__ hook is found. Since it is the responsibility of the
40 application (or the user) to enable this feature, I consider this an
41 acceptable risk. More complicated expressions (e.g. function calls or
42 indexing operations) are *not* evaluated.
43 </li>
44 <li>
45 When the original stdin is not a tty device, GNU readline is never
46 used, and this module (and the readline module) are silently inactive.
47 </li>
48 </ul>
49 """
50
51 import builtins
52 import __main__
53
54 __all__ = ["Completer"]
55
56
57 class Completer:
58 """
59 Class implementing the command line completer object.
60 """
61
62 def __init__(self, namespace=None):
63 """
64 Constructor
65
66 Completer([namespace]) -> completer instance.
67
68 If unspecified, the default namespace where completions are performed
69 is __main__ (technically, __main__.__dict__). Namespaces should be
70 given as dictionaries.
71
72 Completer instances should be used as the completion mechanism of
73 readline via the set_completer() call:
74
75 readline.set_completer(Completer(my_namespace).complete)
76
77 @param namespace The namespace for the completer.
78 @exception TypeError raised to indicate a wrong data structure of
79 the namespace object
80 """
81 if namespace and not isinstance(namespace, dict):
82 raise TypeError("namespace must be a dictionary")
83
84 # Don't bind to namespace quite yet, but flag whether the user wants a
85 # specific namespace or to use __main__.__dict__. This will allow us
86 # to bind to __main__.__dict__ at completion time, not now.
87 if namespace is None:
88 self.use_main_ns = True
89 else:
90 self.use_main_ns = False
91 self.namespace = namespace
92
93 def complete(self, text, state):
94 """
95 Public method to return the next possible completion for 'text'.
96
97 This is called successively with state == 0, 1, 2, ... until it
98 returns None. The completion should begin with 'text'.
99
100 @param text The text to be completed. (string)
101 @param state The state of the completion. (integer)
102 @return The possible completions as a list of strings.
103 """
104 if self.use_main_ns:
105 self.namespace = __main__.__dict__
106
107 if state == 0:
108 if "." in text:
109 self.matches = self.attr_matches(text)
110 else:
111 self.matches = self.global_matches(text)
112 try:
113 return self.matches[state]
114 except IndexError:
115 return None
116
117 def _callable_postfix(self, val, word):
118 """
119 Protected method to check for a callable.
120
121 @param val value to check (object)
122 @param word word to ammend (string)
123 @return ammended word (string)
124 """
125 if callable(val):
126 word += "("
127 return word
128
129 def global_matches(self, text):
130 """
131 Public method to compute matches when text is a simple name.
132
133 @param text The text to be completed. (string)
134 @return A list of all keywords, built-in functions and names currently
135 defined in self.namespace that match.
136 """
137 import keyword
138
139 matches = []
140 seen = {"__builtins__"}
141 n = len(text)
142 for word in keyword.kwlist:
143 if word[:n] == text:
144 seen.add(word)
145 if word in {"finally", "try"}:
146 word += ":"
147 elif word not in {
148 "False",
149 "None",
150 "True",
151 "break",
152 "continue",
153 "pass",
154 "else",
155 }:
156 word += " "
157 matches.append(word)
158 for nspace in [self.namespace, builtins.__dict__]:
159 for word, val in nspace.items():
160 if word[:n] == text and word not in seen:
161 seen.add(word)
162 matches.append(self._callable_postfix(val, word))
163 return matches
164
165 def attr_matches(self, text):
166 """
167 Public method to compute matches when text contains a dot.
168
169 Assuming the text is of the form NAME.NAME....[NAME], and is
170 evaluatable in self.namespace, it will be evaluated and its attributes
171 (as revealed by dir()) are used as possible completions. (For class
172 instances, class members are are also considered.)
173
174 <b>WARNING</b>: this can still invoke arbitrary C code, if an object
175 with a __getattr__ hook is evaluated.
176
177 @param text The text to be completed. (string)
178 @return A list of all matches.
179 """
180 import re
181
182 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text)
183 if not m:
184 return []
185 expr, attr = m.group(1, 3)
186 try:
187 thisobject = eval(expr, self.namespace) # secok
188 except Exception:
189 return []
190
191 # get the content of the object, except __builtins__
192 words = set(dir(thisobject))
193 words.discard("__builtins__")
194
195 if hasattr(object, "__class__"):
196 words.add("__class__")
197 words.update(get_class_members(thisobject.__class__))
198 matches = []
199 n = len(attr)
200 if attr == "":
201 noprefix = "_"
202 elif attr == "_":
203 noprefix = "__"
204 else:
205 noprefix = None
206 while True:
207 for word in words:
208 if word[:n] == attr and not (noprefix and word[: n + 1] == noprefix):
209 match = "{0}.{1}".format(expr, word)
210 try:
211 val = getattr(thisobject, word)
212 except Exception: # secok
213 pass # Include even if attribute not set
214 else:
215 match = self._callable_postfix(val, match)
216 matches.append(match)
217 if matches or not noprefix:
218 break
219 noprefix = "__" if noprefix == "_" else None
220 matches.sort()
221 return matches
222
223
224 def get_class_members(klass):
225 """
226 Module function to retrieve the class members.
227
228 @param klass The class object to be analysed.
229 @return A list of all names defined in the class.
230 """
231 ret = dir(klass)
232 if hasattr(klass, "__bases__"):
233 for base in klass.__bases__:
234 ret += get_class_members(base)
235 return ret
236
237
238 #
239 # eflag: noqa = M111

eric ide

mercurial