Commits

Ali Gholami Rudi  committed 42cef02

Supporting file encodings using emacs encoding headers

  • Participants
  • Parent commits ab662f9

Comments (0)

Files changed (9)

File docs/issues.txt

 
 But I think the same problem existed in smalltalk, too.  Look what
 they did to overcome this problem.  You can also use a strategy
-for testing this approach for renaming.  Maybe in future when
-CPUs get even faster time inefficiency might not be an issue.
+for testing this approach for finding occurances.  Maybe in future
+when CPUs get even faster time inefficiency might not be an issue.
 
 Think of other ways of collecting type information.
 

File docs/workingon.txt

-Restructuring Packages
-======================
-
-::
-  rope
-    base
-      oi
-    refactor
-    ide
-    ui
-
-* Adding `rope.oi` package
-* Not accessing `refactor` in `base`
-* Does supporting implicit interfaces require lots of changes
-  across packages
-
-
 Before 0.3 Release
 ==================
 
+- If the first line contains coding comment do not read the second
+
+* File encodings for notepad style
+* File encodings for normal files
+
+* Changing `Editor.get_region_offset` to work with normal selections
+* Eliminating `Editor.refactoring`; Use editing contexts
+
+  * Should `editingtools` contain `refactoring`, `codeassist`, `outline`
+  * Saving variables for contexts; `Core.save_context_data`
+
 * ``overview.txt``
-* File encodings
-* Eliminating `Editor.refactoring`; Use editing contexts
+* ``contributing.txt``
+* Better pydoc wrapping
+* Better `ropetest` package structure
 
 
 Remaining Stories
 =================
 
+* Changing `uihelpers` tree and list to support mouse clicks
 * Spaces in module path for running modules
-* Changing `uihelpers` tree and list to support mouse clicks
 * Handling `AssList` for inline variable and encapsulate field
 * Changing refactor modules to use `sourcetools.add_methods`
 * Adding ``add_statements(method, statements)``

File rope/__init__.py

 """rope, a python refactoring IDE"""
 
-VERSION = '0.3rc1'
+VERSION = '0.3'

File rope/base/oi/__init__.py

+"""rope object inference package"""

File rope/base/project.py

 import os
+import re
 
 import rope.base.pycore
 import rope.base.fscommands
         super(_File, self).__init__(project, name)
     
     def read(self):
-        return open(self.project._get_resource_path(self.name)).read()
+        source_bytes = open(self.project._get_resource_path(self.name)).read()
+        encoding = self._conclude_file_encoding(source_bytes)
+        if encoding is not None:
+            return unicode(source_bytes, encoding)
+        return unicode(source_bytes)
+    
+    def _find_line_end(self, source_bytes, start):
+        try:
+            return source_bytes.index('\n', start)
+        except ValueError:
+            return len(source_bytes)
+    
+    def _get_the_first_two_lines(self, source_bytes):
+        line1_end = self._find_line_end(source_bytes, 0)
+        yield source_bytes[:line1_end]
+        if line1_end != len(source_bytes):
+            line2_end = self._find_line_end(source_bytes, line1_end)
+            line2 = source_bytes[line1_end + 1:line2_end]
+            yield line2
+        else:
+            yield ''
+    
+    encoding_pattern = re.compile(r'coding[=:]\s*([-\w.]+)')
+    
+    def _conclude_file_encoding(self, source_bytes):
+        for line in self._get_the_first_two_lines(source_bytes):
+            for match in _File.encoding_pattern.finditer(line):
+                return match.group(1)
 
     def write(self, contents):
         file_ = open(self.project._get_resource_path(self.name), 'w')
+        encoding = self._conclude_file_encoding(contents)
+        if encoding is not None and isinstance(contents, unicode):
+            contents = contents.encode(encoding)
         file_.write(contents)
         file_.close()
         for observer in list(self.observers):
         self.get_parent()._child_changed(self)
         for observer in list(self.observers):
             observer(self)
-
+    
 
 class File(_File):
     """Represents a file in a project"""

File rope/ui/testview.py

         self.ok_button.grid(row=4)
         self.toplevel.bind('<Control-g>', self._ok)
         self.toplevel.bind('<Escape>', self._ok)
+        self.toplevel.protocol('WM_DELETE_WINDOW', self._ok)
     
     def add_failure(self, test_name, error):
         self.failures[test_name] = error

File ropetest/codeanalyzetest.py

 
 from ropetest import testutils
 from rope.base.codeanalyze import (StatementRangeFinder, ArrayLinesAdapter,
-                              SourceLinesAdapter, WordRangeFinder,
-                              ScopeNameFinder, LogicalLineFinder)
+                                   SourceLinesAdapter, WordRangeFinder,
+                                   ScopeNameFinder, LogicalLineFinder)
 from rope.base.project import Project
 
 

File ropetest/projecttest.py

         self.assertEquals(1, sample_observer.change_count)
         self.assertEquals(sample_file, sample_observer.last_changed)
 
+    def test_file_encoding_reading(self):
+        sample_file = self.project.get_root_folder().create_file('my_file.txt')
+        contents = u'# -*- coding: utf-8 -*-\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n'
+        file = open(sample_file._get_real_path(), 'w')
+        file.write(contents.encode('utf-8'))
+        file.close()
+        self.assertEquals(contents, sample_file.read())
+
+    def test_file_encoding_writing(self):
+        sample_file = self.project.get_root_folder().create_file('my_file.txt')
+        contents = u'# -*- coding: utf-8 -*-\n\N{LATIN SMALL LETTER I WITH DIAERESIS}\n'
+        sample_file.write(contents)
+        self.assertEquals(contents, sample_file.read())
+
 
 class SampleObserver(object):
     def __init__(self):
         self.assertTrue(sample_folder.has_child('sample.txt'))
         self.assertFalse(sample_folder.has_child('doesnothave.txt'))
         self.assertEquals(sample_resource, sample_folder.get_child('sample.txt'))
-
+    
 
 def suite():
     result = unittest.TestSuite()

File ropetest/testutils.py

 
 def run_only_for_25(func):
     """Should be used as a decorator for a unittest.TestCase test method"""
-    if sys.version.startswith('2.5'):
+    major = sys.version_info[0]
+    minor = sys.version_info[1]
+    if major > 2 or minor > 4:
         return func
     else:
         def do_nothing(self):