137 @return A list of all keywords, built-in functions and names currently |
137 @return A list of all keywords, built-in functions and names currently |
138 defined in self.namespace that match. |
138 defined in self.namespace that match. |
139 """ |
139 """ |
140 import keyword |
140 import keyword |
141 matches = [] |
141 matches = [] |
|
142 seen = {"__builtins__"} |
142 n = len(text) |
143 n = len(text) |
143 for word in keyword.kwlist: |
144 for word in keyword.kwlist: |
144 if word[:n] == text: |
145 if word[:n] == text: |
|
146 seen.add(word) |
|
147 if word in {'finally', 'try'}: |
|
148 word = word + ':' |
|
149 elif word not in {'False', 'None', 'True', |
|
150 'break', 'continue', 'pass', |
|
151 'else'}: |
|
152 word = word + ' ' |
145 matches.append(word) |
153 matches.append(word) |
146 for nspace in [builtins.__dict__, self.namespace]: |
154 for nspace in [builtins.__dict__, self.namespace]: |
147 for word, val in nspace.items(): |
155 for word, val in nspace.items(): |
148 if word[:n] == text and word != "__builtins__": |
156 if word[:n] == text and word not in seen: |
|
157 seen.add(word) |
149 matches.append(self._callable_postfix(val, word)) |
158 matches.append(self._callable_postfix(val, word)) |
150 return matches |
159 return matches |
151 |
160 |
152 def attr_matches(self, text): |
161 def attr_matches(self, text): |
153 """ |
162 """ |
164 @param text The text to be completed. (string) |
173 @param text The text to be completed. (string) |
165 @return A list of all matches. |
174 @return A list of all matches. |
166 """ |
175 """ |
167 import re |
176 import re |
168 |
177 |
169 # Another option, seems to work great. Catches things like ''.<tab> |
178 m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) |
170 m = re.match(r"(\S+(\.\w+)*)\.(\w*)", text) |
|
171 |
|
172 if not m: |
179 if not m: |
173 return |
180 return |
174 expr, attr = m.group(1, 3) |
181 expr, attr = m.group(1, 3) |
175 try: |
182 try: |
176 thisobject = eval(expr, self.namespace) |
183 thisobject = eval(expr, self.namespace) |
177 except Exception: |
184 except Exception: |
178 return [] |
185 return [] |
179 |
186 |
180 # get the content of the object, except __builtins__ |
187 # get the content of the object, except __builtins__ |
181 words = dir(thisobject) |
188 words = set(dir(thisobject)) |
182 if "__builtins__" in words: |
189 words.discard("__builtins__") |
183 words.remove("__builtins__") |
|
184 |
190 |
185 if hasattr(object, '__class__'): |
191 if hasattr(object, '__class__'): |
186 words.append('__class__') |
192 words.add('__class__') |
187 words = words + get_class_members(object.__class__) |
193 words.update(get_class_members(thisobject.__class__)) |
188 matches = [] |
194 matches = [] |
189 n = len(attr) |
195 n = len(attr) |
190 for word in words: |
196 if attr == '': |
191 try: |
197 noprefix = '_' |
192 if word[:n] == attr and hasattr(thisobject, word): |
198 elif attr == '_': |
193 val = getattr(thisobject, word) |
199 noprefix = '__' |
194 word = self._callable_postfix( |
200 else: |
195 val, "{0}.{1}".format(expr, word)) |
201 noprefix = None |
196 matches.append(word) |
202 while True: |
197 except Exception: |
203 for word in words: |
198 # some badly behaved objects pollute dir() with non-strings, |
204 if word[:n] == attr and \ |
199 # which cause the completion to fail. This way we skip the |
205 not (noprefix and word[:n + 1] == noprefix): |
200 # bad entries and can still continue processing the others. |
206 match = "{0}.{1}".format(expr, word) |
201 pass |
207 try: |
|
208 val = getattr(thisobject, word) |
|
209 except Exception: |
|
210 pass # Include even if attribute not set |
|
211 else: |
|
212 match = self._callable_postfix(val, match) |
|
213 matches.append(match) |
|
214 if matches or not noprefix: |
|
215 break |
|
216 if noprefix == '_': |
|
217 noprefix = '__' |
|
218 else: |
|
219 noprefix = None |
|
220 matches.sort() |
202 return matches |
221 return matches |
203 |
222 |
204 |
223 |
205 def get_class_members(klass): |
224 def get_class_members(klass): |
206 """ |
225 """ |