1. shillo
  2. rope

Commits

Ali Gholami Rudi  committed 8e75353

Changed codeassist to use LogicalLineFinder

  • Participants
  • Parent commits e79b44b
  • Branches trunk

Comments (0)

Files changed (4)

File docs/dev/issues.txt

View file
 * ObjectInfo: for storing object information
 * History: for storing changes
 
-We should measure the amount of memory each of them uses to make
+We should measure the amount of memory each of them use to make
 decisions.
 
 
 This has been moved to a separate branch.
 
 
-What Rope Assumes...
-====================
-
-In order to simplify problems a bit, rope makes some assumptions about
-the source code.  In future some of this restrictions might be
-removed.
-
-* All files that end with ``.py`` are considered to be python files
-  and all others not.
-* Either all files that are not ignored should be under version
-  control or none.
-* All ``*.txt`` files are considered to be ReST.
-* XXX
-
-
 Unresolved Issues
 =================
 
-* Splitting history for being faster?
+* Commenting based on the line of syntax error in codeassist?
+* objectinfer:183; should we give up when the first attempt
+  returned None or unknown, user config?
 * Searching all files when extracting a global method?
 * Better tests in `patchedasttest`
-* Callbacks in keybinder hold their parent frame
 * Import actions with more that one phase and filtering problems
 * Handle long imports should work on filtered imports unconditionally?
-
-* A mode for removing trailing whitespaces
-* Renaming ``rope.py`` to ``ropeide.py`` and ``~/.rope`` to
-  ``~/.ropeide.py``?
-* Changing the default font on linux to courier?
-* Commenting based on the line of syntax error in codeassist?
 * Adding restructuring scope; local scope, module, all files?
-* Better search triggering in find type dialog
 * Changing `codeanalyze.WordFinder` to use ASTs?
 * Refactoring codeanalyze; lots of estimations
 * Assignment to parameters in inline method
-* Assignment to parameter warning
-
 * Extracting subexpressions; look at `extracttest` for more info
 * Remove ``change occurreces`` refactoring?
 * Using similarfinder in introduce_parameter?
-* Moving `PyCore.create_module()` and `PyCore.create_package()`?
 * Using GPLv3 from 0.7?
+* Removed unused refactorings
+* Unignored files that are not under version control
 
 
 Small Stories

File rope/base/codeanalyze.py

View file
 
     def _calculate_logical(self, readline, line_number):
         last_line_start = 1
-        for current in tokenize.generate_tokens(readline):
-            current_lineno = current[2][0]
-            if current[0] == token.NEWLINE:
-                if current_lineno >= line_number:
-                    return (last_line_start, current_lineno)
-                last_line_start = current_lineno + 1
+        try:
+            for current in tokenize.generate_tokens(readline):
+                current_lineno = current[2][0]
+                if current[0] == token.NEWLINE:
+                    if current_lineno >= line_number:
+                        return (last_line_start, current_lineno)
+                    last_line_start = current_lineno + 1
+        except tokenize.TokenError:
+            return (last_line_start, None)
         return (last_line_start, None)
 
     def _get_first_non_blank(self, line_number):
         return current
 
 
-class StatementRangeFinder(object):
-    """A method object for finding the range of a statement"""
-
-    def __init__(self, lines, lineno):
-        self.lines = lines
-        self.lineno = lineno
-        self.in_string = ''
-        self.open_count = 0
-        self.explicit_continuation = False
-        self.open_parens = []
-        self._analyze()
-
-    def _analyze_line(self, current_line_number):
-        current_line = self.lines.get_line(current_line_number)
-        for i, char in enumerate(current_line):
-            if char in '\'"':
-                if self.in_string == '':
-                    self.in_string = char
-                    if char * 3 == current_line[i:i + 3]:
-                        self.in_string = char * 3
-                elif self.in_string == current_line[i:i + len(self.in_string)] and \
-                     not (i > 0 and current_line[i - 1] == '\\' and
-                          not (i > 1 and current_line[i - 2:i] == '\\\\')):
-                    self.in_string = ''
-            if self.in_string != '':
-                continue
-            if char == '#':
-                break
-            if char in '([{':
-                self.open_count += 1
-                self.open_parens.append((current_line_number, i))
-            if char in ')]}':
-                self.open_count -= 1
-                if self.open_parens:
-                    self.open_parens.pop()
-        if current_line and char != '#' and current_line.endswith('\\'):
-            self.explicit_continuation = True
-        else:
-            self.explicit_continuation = False
-
-    def _analyze(self):
-        last_statement = 1
-        for current_line_number in range(get_block_start(self.lines,
-                                                         self.lineno),
-                                         self.lineno + 1):
-            if not self.explicit_continuation and \
-               self.open_count == 0 and self.in_string == '':
-                last_statement = current_line_number
-            self._analyze_line(current_line_number)
-        last_indents = self.get_line_indents(last_statement)
-        end_line = self.lineno
-        for i in range(self.lineno + 1, self.lines.length() + 1):
-            if self.get_line_indents(i) >= last_indents:
-                end_line = i
-            else:
-                break
-        self.block_end = end_line
-        self.statement_start = last_statement
-
-    def get_statement_start(self):
-        return self.statement_start
-
-    def get_block_end(self):
-        return self.block_end
-
-    def last_open_parens(self):
-        if not self.open_parens:
-            return None
-        return self.open_parens[-1]
-
-    def is_line_continued(self):
-        return self.open_count != 0 or self.explicit_continuation
-
-    def get_line_indents(self, line_number):
-        return count_line_indents(self.lines.get_line(line_number))
-
-    _block_start_pattern = None
-
-
 def get_block_start(lines, lineno, maximum_indents=80):
     """Aproximate block start"""
     pattern = get_block_start_patterns()
             return i
     return 1
 
+
+_block_start_pattern = None
+
 def get_block_start_patterns():
-    if not StatementRangeFinder._block_start_pattern:
+    global _block_start_pattern
+    if not _block_start_pattern:
         pattern = '^\\s*(((def|class|if|elif|except|for|while|with)\\s)|'\
                   '((try|else|finally|except)\\s*:))'
-        StatementRangeFinder._block_start_pattern = re.compile(pattern, re.M)
-    return StatementRangeFinder._block_start_pattern
+        _block_start_pattern = re.compile(pattern, re.M)
+    return _block_start_pattern
 
 
 def count_line_indents(line):

File rope/contrib/codeassist.py

View file
 import sys
 
 import rope.base.codeanalyze
-from rope.base import pyobjects, pynames, taskhandle, builtins
-from rope.base.codeanalyze import (StatementRangeFinder, ArrayLinesAdapter,
-                                   WordRangeFinder, ScopeNameFinder,
-                                   SourceLinesAdapter, BadIdentifierError)
+from rope.base import pyobjects, pynames, taskhandle, builtins, codeanalyze
+from rope.base.codeanalyze import (ArrayLinesAdapter, BadIdentifierError,
+                                   LogicalLineFinder, ScopeNameFinder,
+                                   SourceLinesAdapter, WordRangeFinder)
 from rope.refactor import occurrences, functionutils
 
 
         return rope.base.codeanalyze.count_line_indents(line)
 
     def _comment_current_statement(self):
-        range_finder = StatementRangeFinder(ArrayLinesAdapter(self.lines),
-                                            self.lineno)
-        start = range_finder.get_statement_start() - 1
-        end = range_finder.get_block_end() - 1
+        logical_finder = LogicalLineFinder(ArrayLinesAdapter(self.lines))
+        start = logical_finder.get_logical_line_in(self.lineno)[0] - 1
+        end = self._get_block_end(start)
         last_indents = self._get_line_indents(self.lines[start])
         self.lines[start] = ' ' * last_indents + 'pass'
         for line in range(start + 1, end + 1):
         self.lines.append('\n')
         self._fix_incomplete_try_blocks()
 
+    def _get_block_end(self, lineno):
+        end_line = lineno
+        base_indents = self._get_line_indents(self.lines[lineno])
+        for i in range(lineno + 1, len(self.lines)):
+            if self._get_line_indents(self.lines[i]) >= base_indents:
+                end_line = i
+            else:
+                break
+        return end_line
+
     def _fix_incomplete_try_blocks(self):
         block_start = self.lineno
         last_indents = self.current_indents
         word_finder = WordRangeFinder(self.unchanged_source)
         lines = SourceLinesAdapter(self.unchanged_source)
         lineno = lines.get_line_number(offset)
-        stop_line = StatementRangeFinder(lines, lineno).get_statement_start()
+        stop_line = LogicalLineFinder(lines).get_logical_line_in(lineno)[0]
         stop = lines.get_line_start(stop_line)
         if word_finder.is_on_function_call_keyword(offset - 1, stop):
             name_finder = ScopeNameFinder(pymodule)

File ropetest/codeanalyzetest.py

View file
 import unittest
 
 from rope.base import exceptions
-from rope.base.codeanalyze import (StatementRangeFinder, ArrayLinesAdapter,
+from rope.base.codeanalyze import (ArrayLinesAdapter,
                                    SourceLinesAdapter, WordRangeFinder,
                                    ScopeNameFinder, LogicalLineFinder, get_block_start)
 from ropetest import testutils
     def tearDown(self):
         super(StatementRangeFinderTest, self).tearDown()
 
-    def get_range_finder(self, code, line):
-        result = StatementRangeFinder(ArrayLinesAdapter(code.split('\n')), line)
-        return result
-
-    def test_simple_statement_finding(self):
-        finder = self.get_range_finder('a = 10', 1)
-        self.assertEquals(1,  finder.get_statement_start())
-
-    def test_get_start(self):
-        finder = self.get_range_finder('a = 10\nb = 12\nc = 14', 1)
-        self.assertEquals(1,  finder.get_statement_start())
-
-    def test_get_block_end(self):
-        finder = self.get_range_finder('a = 10\nb = 12\nc = 14', 1)
-        self.assertEquals(3,  finder.get_block_end())
-
-    def test_get_last_open_parens(self):
-        finder = self.get_range_finder('a = 10', 1)
-        self.assertTrue(finder.last_open_parens() is None)
-
-    def test_get_last_open_parens2(self):
-        finder = self.get_range_finder('a = (10 +', 1)
-        self.assertEquals((1, 4), finder.last_open_parens())
-
-    def test_is_line_continued(self):
-        finder = self.get_range_finder('a = 10', 1)
-        self.assertFalse(finder.is_line_continued())
-
-    def test_is_line_continued2(self):
-        finder = self.get_range_finder('a = (10 +', 1)
-        self.assertTrue(finder.is_line_continued())
-
     def test_source_lines_simple(self):
         to_lines = SourceLinesAdapter('line1\nline2\n')
         self.assertEquals('line1', to_lines.get_line(1))