| """Word completion for GNU readline 2.0. |
| |
| This requires the latest extension to the readline module (the |
| completes keywords, built-ins and globals in __main__; when completing |
| NAME.NAME..., it evaluates (!) the expression up to the last dot and |
| completes its attributes. |
| |
| It's very cool to do "import string" type "string.", hit the |
| completion key (twice), and see the list of names defined by the |
| string module! |
| |
| Tip: to use the tab key as the completion key, call |
| |
| readline.parse_and_bind("tab: complete") |
| |
| Notes: |
| |
| - Exceptions raised by the completer function are *ignored* (and |
| generally cause the completion to fail). This is a feature -- since |
| readline sets the tty device in raw (or cbreak) mode, printing a |
| traceback wouldn't work well without some complicated hoopla to save, |
| reset and restore the tty state. |
| |
| - The evaluation of the NAME.NAME... form may cause arbitrary |
| application defined code to be executed if an object with a |
| __getattr__ hook is found. Since it is the responsibility of the |
| application (or the user) to enable this feature, I consider this an |
| acceptable risk. More complicated expressions (e.g. function calls or |
| indexing operations) are *not* evaluated. |
| |
| - GNU readline is also used by the built-in functions input() and |
| raw_input(), and thus these also benefit/suffer from the completer |
| features. Clearly an interactive application can benefit by |
| specifying its own completer function and using raw_input() for all |
| its input. |
| |
| - When the original stdin is not a tty device, GNU readline is never |
| used, and this module (and the readline module) are silently inactive. |
| |
| """ |
| |
| import readline |
| import __builtin__ |
| import __main__ |
| |
| class Completer: |
| |
| def complete(self, text, state): |
| """Return the next possible completion for 'text'. |
| |
| This is called successively with state == 0, 1, 2, ... until it |
| returns None. The completion should begin with 'text'. |
| |
| """ |
| if state == 0: |
| if "." in text: |
| self.matches = self.attr_matches(text) |
| else: |
| self.matches = self.global_matches(text) |
| try: |
| return self.matches[state] |
| except IndexError: |
| return None |
| |
| def global_matches(self, text): |
| """Compute matches when text is a simple name. |
| |
| Return a list of all keywords, built-in functions and names |
| currently defines in __main__ that match. |
| |
| """ |
| import keyword |
| matches = [] |
| n = len(text) |
| for list in [keyword.kwlist, |
| __builtin__.__dict__.keys(), |
| __main__.__dict__.keys()]: |
| for word in list: |
| if word[:n] == text and word != "__builtins__": |
| matches.append(word) |
| return matches |
| |
| def attr_matches(self, text): |
| """Compute matches when text contains a dot. |
| |
| Assuming the text is of the form NAME.NAME....[NAME], and is |
| evaluabable in the globals of __main__, it will be evaluated |
| and its attributes (as revealed by dir()) are used as possible |
| completions. (For class instances, class members are are also |
| considered.) |
| |
| WARNING: this can still invoke arbitrary C code, if an object |
| with a __getattr__ hook is evaluated. |
| |
| """ |
| import re |
| m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) |
| if not m: |
| return |
| expr, attr = m.group(1, 3) |
| object = eval(expr, __main__.__dict__) |
| words = dir(object) |
| if hasattr(object,'__class__'): |
| words.append('__class__') |
| words = words + get_class_members(object.__class__) |
| matches = [] |
| n = len(attr) |
| for word in words: |
| if word[:n] == attr and word != "__builtins__": |
| matches.append("%s.%s" % (expr, word)) |
| return matches |
| |
| def get_class_members(klass): |
| ret = dir(klass) |
| if hasattr(klass,'__bases__'): |
| for base in klass.__bases__: |
| ret = ret + get_class_members(base) |
| return ret |
| |
| readline.set_completer(Completer().complete) |