Commits

Anonymous committed 59acbec

Auto-completion in nested functions
Better scope endpoint selection
Nested scopes

Comments (0)

Files changed (5)

+- Auto-complete local variable names : May 22, 2006
+
+
 > Public release 0.2pre : May 20, 2006
 
 
 * Proposing function parameters in the function @ 1
 
 
-* Auto-complete local variable names @ 3
-
-
 --- Remaining Stories ---
 ? Change program goals and description; principles.html
   ? Go toward refactoring and ... library rather than an IDE

docs/workingon.txt

-*** Auto-complete local variable names @ 3 ***
+--- Auto-complete local variable names @ 3 ---
 
+- Test not including class body variables
+- Test nested Functions
+- Better scope endpoints selection
+- Test imports inside functions
+- Test nested Classes
 
+? Not proposing local_variables that are defined after current position
 ? Remote pair programming support
 ? Completions are context dependant
 ? Separating ui modules and packages

rope/codeassist.py

     def visitFunction(self, node):
         if node.name.startswith(self.starting):
             self.scope.var_dict[node.name] = CompletionProposal(node.name, 'function')
-        new_visitor = _FunctionScopeVisitor(self.starting, node)
-        compiler.walk(node, new_visitor)
+        new_visitor = _FunctionScopeVisitor.walk_function(self.starting, node)
         self.scope.children.append(new_visitor.scope)
 
     def visitClass(self, node):
         if node.name.startswith(self.starting):
             self.result[node.name] = CompletionProposal(node.name, 'class')
-        new_visitor = _ClassScopeVisitor(self.starting, node)
-        compiler.walk(node, new_visitor)
+        new_visitor = _ClassScopeVisitor.walk_class(self.starting, node)
         self.scope.children.append(new_visitor.scope)
 
     @staticmethod
 
 
 class CodeAssist(ICodeAssist):
-    def __init__(self):
+    def __init__(self, indentation_length=4):
+        self.indentation_length = indentation_length
         self.builtins = [str(name) for name in dir(__builtin__)
                          if not name.startswith('_')]
         import keyword
                 result[kw] = CompletionProposal(kw, 'keyword')
         return result
 
-    def _get_all_completions(self, global_scope, lineno):
+    def _get_all_completions(self, global_scope, lineno, indents):
         result = {}
         current_scope = global_scope
-        while current_scope is not None:
+        nested_scope_count = 0
+        while current_scope is not None and nested_scope_count <= indents:
             result.update(current_scope.var_dict)
             new_scope = None
             for scope in current_scope.children:
                 else:
                     break
             current_scope = new_scope
+            nested_scope_count += 1
         return result
     
     def _get_line_number(self, source_code, offset):
         return source_code[:offset].count('\n') + 1
 
+    def _count_line_indents(self, source_code, offset):
+        last_non_space = offset - 1
+        current_pos = offset - 1
+        while current_pos >= 0 and source_code[current_pos] != '\n':
+            if source_code[current_pos] != ' ':
+                last_non_space = current_pos
+            current_pos -= 1
+        return (last_non_space - current_pos - 1) / self.indentation_length
+
     def complete_code(self, source_code, offset):
         if offset > len(source_code):
             return []
             raise RopeSyntaxError(e)
         visitor = _GlobalScopeVisitor(starting)
         compiler.walk(code_ast, visitor)
-#        result.update(visitor.scope.var_dict)
         result = self._get_all_completions(visitor.scope,
-                                           self._get_line_number(source_code, offset))
+                                           self._get_line_number(source_code, offset),
+                                           self._count_line_indents(source_code, offset))
         if len(starting) > 0:
             result.update(self._get_matching_builtins(starting))
             result.update(self._get_matching_keywords(starting))

ropetest/codeassisttest.py

         result = self.assist.complete_code(code, len(code))
         self.assert_proposal_in_result('my_var', 'local_variable', result)
 
+    def test_not_including_class_body_variables(self):
+        code = 'class C(object):\n    my_var = 20\n    def f(self):\n        a = 20\n        my_'
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_not_in_result('my_var', 'local_variable', result)
+
+    def test_nested_functions(self):
+        code = "def my_func():\n    func_var = 20\n    def inner_func():\n        a = 20\n        func"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_in_result('func_var', 'local_variable', result)
+
+    def test_scope_endpoint_selection(self):
+        code = "def my_func():\n    func_var = 20\n"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_not_in_result('func_var', 'local_variable', result)
+
+    def test_imports_inside_function(self):
+        code = "def f():\n    import sys\n    sy"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_in_result('sys', 'module', result)
+
+    def test_imports_inside_function_dont_mix_with_globals(self):
+        code = "def f():\n    import sys\nsy"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_not_in_result('sys', 'module', result)
+
+    def test_nested_classes_local_names(self):
+        code = "global_var = 10\ndef my_func():\n    func_var = 20\n    class C(object):\n" + \
+               "        def another_func(self):\n            local_var = 10\n            func"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_in_result('func_var', 'local_variable', result)
+
+    def test_nested_classes_global(self):
+        code = "global_var = 10\ndef my_func():\n    func_var = 20\n    class C(object):\n" + \
+               "        def another_func(self):\n            local_var = 10\n            globa"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_in_result('global_var', 'global_variable', result)
+
+    def test_nested_classes_global_function(self):
+        code = "global_var = 10\ndef my_func():\n    func_var = 20\n    class C(object):\n" + \
+               "        def another_func(self):\n            local_var = 10\n            my_f"
+        result = self.assist.complete_code(code, len(code))
+        self.assert_proposal_in_result('my_func', 'function', result)
+
 
 if __name__ == '__main__':
     unittest.main()