diff --git a/evaluate.py b/evaluate.py index df36f7e6..2867bad4 100644 --- a/evaluate.py +++ b/evaluate.py @@ -169,6 +169,9 @@ class Instance(Executable): names.append(var) return names + def parent(self): + return self.base.parent + def __repr__(self): return "<%s of %s (params: %s)>" % \ (self.__class__.__name__, self.base, len(self.params or [])) @@ -310,17 +313,18 @@ def get_names_for_scope(scope, position=None, star_search=True): # class variables/functions are only availabe if (not isinstance(scope, parsing.Class) or scope == start_scope) \ and not isinstance(scope, parsing.Flow): - yield get_defined_names_for_position(scope, position) + yield scope, get_defined_names_for_position(scope, position) scope = scope.parent # add star imports if star_search: for s in remove_star_imports(start_scope.get_parent_until()): - for name_list in get_names_for_scope(s, star_search=False): - yield name_list + for g in get_names_for_scope(s, star_search=False): + yield g # add builtins to the global scope - yield builtin.Builtin.scope.get_defined_names() + builtin_scope = builtin.Builtin.scope + yield builtin_scope, builtin_scope.get_defined_names() def get_scopes_for_name(scope, name_str, position=None, search_global=False): """ @@ -355,8 +359,6 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): return res_new def filter_name(scope_generator): - # the name is already given in the parent function - def handle_non_arrays(name): result = [] par = name.parent @@ -389,14 +391,20 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): return result result = [] - for name_list in scope_generator: - for name in name_list: + for scope, name_list in scope_generator: + for name in sorted(name_list, key=lambda name: name.line_nr, + reverse=True): if name_str == name.get_code(): if isinstance(name, ArrayElement): - print 'dini mueter, wieso?', name + # TODO why? don't know why this exists, was if/else + raise Exception('dini mueter, wieso?' + str(name)) result.append(name) - else: - result += handle_non_arrays(name) + result += handle_non_arrays(name) + # this means that a definition was found and is not e.g. + # in if/else. + #print name, name.parent.parent, scope + if name.parent.parent == scope: + break # if there are results, ignore the other scopes if result: break @@ -404,16 +412,16 @@ def get_scopes_for_name(scope, name_str, position=None, search_global=False): return result if search_global: - names = get_names_for_scope(scope, position=position) + scope_generator = get_names_for_scope(scope, position=position) else: if position: names = get_defined_names_for_position(scope, position) else: names = scope.get_defined_names() - names = [names].__iter__() + scope_generator = [(scope, names)].__iter__() #print ' ln', position - return remove_statements(filter_name(names)) + return remove_statements(filter_name(scope_generator)) def strip_imports(scopes): diff --git a/functions.py b/functions.py index c2d0e9d0..cd8da39d 100644 --- a/functions.py +++ b/functions.py @@ -189,7 +189,7 @@ def complete(source, row, column, source_path): except IndexError: scope_generator = evaluate.get_names_for_scope(scope) completions = [] - for name_list in scope_generator: + for dummy, name_list in scope_generator: completions += name_list #for c in completions: # if isinstance(, parsing.Function): diff --git a/parsetest.py b/parsetest.py index 1d1a21c2..21448793 100644 --- a/parsetest.py +++ b/parsetest.py @@ -155,7 +155,7 @@ def globalfunc(): global globalvar, globalvar2 globalvar = 3 a8 = 3 -a8 = set +a8 = tuple # completion: a8. a8=list diff --git a/parsing.py b/parsing.py index c93568a8..0dfb761e 100644 --- a/parsing.py +++ b/parsing.py @@ -1210,7 +1210,7 @@ class PyFuzzyParser(object): def next(self): """ Generate the next tokenize pattern. """ - type, tok, position, dummy, self.parserline = self.gen.next() + type, tok, position, dummy, self.parserline = next(self.gen) (self._tokenize_line_nr, indent) = position if self.line_nr == self.user_line: debug.dbg('user scope found [%s] =%s' % \ diff --git a/test/completion/ordering.py b/test/completion/ordering.py new file mode 100644 index 00000000..d6381d37 --- /dev/null +++ b/test/completion/ordering.py @@ -0,0 +1,71 @@ +# normal +a = "" +a = 1 + +#? ['real'] +a.real +#? [] +a.upper +#? [] +a.append + + +a = list + +# function stuff +def a(a=3): + #? ['real'] + a.real + #? [] + a.upper + #? [] + a.func + return a + +#? ['real'] +a(2).real +#? [] +a(2).upper +#? [] +a(2).func + +# class stuff +class A(object): + a = "" + a = 3 + #? ['real'] + a.real + #? [] + a.upper + #? [] + a.append + a = list + def __init__(self): + self.b = "" + self.b = 3 + #? ['real'] + self.b.real + #? [] + self.b.upper + #? [] + self.b.append + + self.b = list + + def before(self): + self.a = 1 + #? ['real'] + self.a.real + #? ['upper'] + self.a.upper + + def after(self): + self.a = '' + +##? ['real'] +A.a.real +##? [] +A.a.upper +##? [] +A.a.append + diff --git a/test/run.py b/test/run.py index 79ffa867..fb6bd023 100755 --- a/test/run.py +++ b/test/run.py @@ -54,6 +54,10 @@ def completion_test(source): correct = re.search(r'(?:^|\s)#\?\s*([^\n]+)', line).group(1) except: correct = None + else: + # reset the test, if only one specific test is wanted + if len(sys.argv) > 2 and line_nr != int(sys.argv[2]): + correct = None return tests, fails # completion tests: