Browse files

diff: Support .gitattribute encodings when showing diffs

Teach the diff viewer to display diffs using the encoding
specified in .gitattributes.

This is the first half of the work needed to properly support
.gitattributes for file encodings as described in issue #96.

Set `cola.fileattributes` to true to enable this feature.
The diffs are now displayed correctly for non-utf8 files.

Diffs cannot yet be applied, but this is the first step.

Signed-off-by: David Aguilar <davvid@gmail.com>
  • Loading branch information...
1 parent fecf2d6 commit e06e134407823884d0475fb1d96c1edc98016ef8 @davvid committed May 28, 2012
Showing with 60 additions and 5 deletions.
  1. +9 −2 cola/core.py
  2. +43 −2 cola/gitcfg.py
  3. +3 −1 cola/gitcmds.py
  4. +5 −0 share/doc/git-cola/git-cola.txt
View
11 cola/core.py
@@ -4,6 +4,8 @@
e.g. when python raises an IOError or OSError with errno == EINTR.
"""
+import itertools
+
from cola.decorators import interruptable
# Some files are not in UTF-8; some other aren't in any codification.
@@ -16,10 +18,15 @@
# <-- add encodings here
]
-def decode(enc):
+def decode(enc, encoding=None):
"""decode(encoded_string) returns an unencoded unicode string
"""
- for encoding in _encoding_tests:
+ if encoding is None:
+ encoding_tests = _encoding_tests
+ else:
+ encoding_tests = itertools.chain([encoding], _encoding_tests)
+
+ for encoding in encoding_tests:
try:
return unicode(enc.decode(encoding))
except:
View
45 cola/gitcfg.py
@@ -61,6 +61,8 @@ def __init__(self):
self._cache_key = None
self._configs = []
self._config_files = {}
+ self._value_cache = {}
+ self._attr_cache = {}
self._find_config_files()
def reset(self):
@@ -72,6 +74,8 @@ def reset(self):
self._cache_key = None
self._configs = []
self._config_files.clear()
+ self._value_cache = {}
+ self._attr_cache = {}
self._find_config_files()
def user(self):
@@ -225,8 +229,45 @@ def find(self, pat):
result[key] = val
return result
- def get_encoding(self, default='utf-8'):
- return self.get('gui.encoding', default=default)
+ def get_cached(self, key, default=None):
+ cache = self._value_cache
+ try:
+ value = cache[key]
+ except KeyError:
+ value = cache[key] = self.get(key, default=default)
+ return value
+
+ def gui_encoding(self):
+ return self.get_cached('gui.encoding', default='utf-8')
+
+ def is_per_file_attrs_enabled(self):
+ return self.get_cached('cola.fileattributes', default=False)
+
+ def file_encoding(self, path):
+ if not self.is_per_file_attrs_enabled():
+ return None
+ cache = self._attr_cache
+ try:
+ value = cache[path]
+ except KeyError:
+ value = cache[path] = self._file_encoding(path)
+ return value
+
+ def _file_encoding(self, path):
+ """Return the file encoding for a path"""
+ status, out = self.git.check_attr('encoding', '--', path,
+ with_status=True)
+ if status != 0:
+ return None
+ out = core.decode(out)
+ header = '%s: encoding: ' % path
+ if out.startswith(header):
+ encoding = out[len(header):].strip()
+ if (encoding != 'unspecified' and
+ encoding != 'unset' and
+ encoding != 'set'):
+ return encoding
+ return None
guitool_opts = ('cmd', 'needsfile', 'noconsole', 'norescan', 'confirm',
'argprompt', 'revprompt', 'revunmerged', 'title', 'prompt')
View
4 cola/gitcmds.py
@@ -247,12 +247,14 @@ def diff_helper(commit=None,
elif head and amending and cached:
argv.append(head)
+ encoding = None
if filename:
argv.append('--')
if type(filename) is list:
argv.extend(filename)
else:
argv.append(filename)
+ encoding = config.file_encoding(filename)
start = False
del_tag = 'deleted file mode '
@@ -281,7 +283,7 @@ def diff_helper(commit=None,
output = StringIO()
- diff = core.decode(diffoutput).split('\n')
+ diff = core.decode(diffoutput, encoding=encoding).split('\n')
for line in diff:
if not start and '@@' == line[:2] and '@@' in line[2:]:
start = True
View
5 share/doc/git-cola/git-cola.txt
@@ -67,6 +67,11 @@ CONFIG VARIABLES
cola.savewindowsettings::
Whether 'git-cola' should remember its window settings.
+cola.fileattributes::
+ Enables per-file linkgit:gitattributes[5] encoding support
+ when set to `true`. This tells 'git-cola' to honor the
+ configured encoding when displaying and applying diffs.
+
cola.fontdiff::
Specifies the font to use for 'git-cola''s diff display.

0 comments on commit e06e134

Please sign in to comment.