--- a/DebugClients/Python/FlexCompleter.py Mon Mar 12 19:37:23 2018 +0100 +++ b/DebugClients/Python/FlexCompleter.py Mon Mar 12 19:42:07 2018 +0100 @@ -125,7 +125,7 @@ @param word word to ammend (string) @return ammended word (string) """ - if hasattr(val, '__call__'): + if callable(val): word = word + "(" return word @@ -139,13 +139,22 @@ """ import keyword matches = [] + seen = {"__builtins__"} n = len(text) for word in keyword.kwlist: if word[:n] == text: + seen.add(word) + if word in {'finally', 'try'}: + word = word + ':' + elif word not in {'False', 'None', 'True', + 'break', 'continue', 'pass', + 'else'}: + word = word + ' ' matches.append(word) for nspace in [builtins.__dict__, self.namespace]: for word, val in nspace.items(): - if word[:n] == text and word != "__builtins__": + if word[:n] == text and word not in seen: + seen.add(word) matches.append(self._callable_postfix(val, word)) return matches @@ -166,9 +175,7 @@ """ import re - # Another option, seems to work great. Catches things like ''.<tab> - m = re.match(r"(\S+(\.\w+)*)\.(\w*)", text) - + m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) if not m: return expr, attr = m.group(1, 3) @@ -178,27 +185,39 @@ return [] # get the content of the object, except __builtins__ - words = dir(thisobject) - if "__builtins__" in words: - words.remove("__builtins__") + words = set(dir(thisobject)) + words.discard("__builtins__") if hasattr(object, '__class__'): - words.append('__class__') - words = words + get_class_members(object.__class__) + words.add('__class__') + words.update(get_class_members(thisobject.__class__)) matches = [] n = len(attr) - for word in words: - try: - if word[:n] == attr and hasattr(thisobject, word): - val = getattr(thisobject, word) - word = self._callable_postfix( - val, "{0}.{1}".format(expr, word)) - matches.append(word) - except Exception: - # some badly behaved objects pollute dir() with non-strings, - # which cause the completion to fail. This way we skip the - # bad entries and can still continue processing the others. - pass + if attr == '': + noprefix = '_' + elif attr == '_': + noprefix = '__' + else: + noprefix = None + while True: + for word in words: + if word[:n] == attr and \ + not (noprefix and word[:n + 1] == noprefix): + match = "{0}.{1}".format(expr, word) + try: + val = getattr(thisobject, word) + except Exception: + pass # Include even if attribute not set + else: + match = self._callable_postfix(val, match) + matches.append(match) + if matches or not noprefix: + break + if noprefix == '_': + noprefix = '__' + else: + noprefix = None + matches.sort() return matches