diff --git a/pylons_app/controllers/files.py b/pylons_app/controllers/files.py
--- a/pylons_app/controllers/files.py
+++ b/pylons_app/controllers/files.py
@@ -6,8 +6,7 @@ from pylons.controllers.util import abor
from pylons_app.lib.base import BaseController, render
from pylons_app.lib.utils import get_repo_slug
from pylons_app.model.hg_model import HgModel
-from difflib import unified_diff
-from pylons_app.lib.differ import render_udiff
+from vcs.utils import diffs as differ
from vcs.exceptions import RepositoryError, ChangesetError
log = logging.getLogger(__name__)
@@ -83,21 +82,14 @@ class FilesController(BaseController):
c.repo = hg_model.get_repo(c.repo_name)
c.changeset_1 = c.repo.get_changeset(diff1)
c.changeset_2 = c.repo.get_changeset(diff2)
- f1 = c.changeset_1.get_node(f_path)
- f2 = c.changeset_2.get_node(f_path)
c.diff1 = 'r%s:%s' % (c.changeset_1.revision, c.changeset_1._short)
c.diff2 = 'r%s:%s' % (c.changeset_2.revision, c.changeset_2._short)
-
- f_udiff = unified_diff(f1.content.splitlines(True),
- f2.content.splitlines(True),
- f1.name,
- f2.name)
+
- c.diff_files = render_udiff(udiff=f_udiff, differ='difflib')
- print c.diff_files
- if len(c.diff_files) < 1:
- c.no_changes = True
+ f_udiff = differ.get_udiff(c.changeset_1.get_node(f_path),
+ c.changeset_2.get_node(f_path))
+ c.differ = differ.DiffProcessor(f_udiff)
return render('files/file_diff.html')
def _get_history(self, repo, node, f_path):
diff --git a/pylons_app/lib/differ.py b/pylons_app/lib/differ.py
deleted file mode 100644
--- a/pylons_app/lib/differ.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# -*- coding: utf-8 -*-
-# original copyright: 2007-2008 by Armin Ronacher
-# licensed under the BSD license.
-
-import re, difflib
-
-def render_udiff(udiff, differ='udiff'):
- """Renders the udiff into multiple chunks of nice looking tables.
- The return value is a list of those tables.
- """
- return DiffProcessor(udiff, differ).prepare()
-
-class DiffProcessor(object):
- """Give it a unified diff and it returns a list of the files that were
- mentioned in the diff together with a dict of meta information that
- can be used to render it in a HTML template.
- """
- _chunk_re = re.compile(r'@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)')
-
- def __init__(self, udiff, differ):
- """
- :param udiff: a text in udiff format
- """
- if isinstance(udiff, basestring):
- udiff = udiff.splitlines(1)
-
- self.lines = map(self.escaper, udiff)
-
- # Select a differ.
- if differ == 'difflib':
- self.differ = self._highlight_line_difflib
- else:
- self.differ = self._highlight_line_udiff
-
-
- def escaper(self, string):
- return string.replace('<', '<').replace('>', '>')
-
- def _extract_rev(self, line1, line2):
- """Extract the filename and revision hint from a line."""
- try:
- if line1.startswith('--- ') and line2.startswith('+++ '):
- l1 = line1[4:].split(None, 1)
- old_filename = l1[0] if len(l1) >= 1 else None
- old_rev = l1[1] if len(l1) == 2 else 'old'
-
- l2 = line1[4:].split(None, 1)
- new_filename = l2[0] if len(l2) >= 1 else None
- new_rev = l2[1] if len(l2) == 2 else 'new'
-
- return old_filename, new_rev, old_rev
- except (ValueError, IndexError):
- pass
-
- return None, None, None
-
- def _highlight_line_difflib(self, line, next):
- """Highlight inline changes in both lines."""
-
- if line['action'] == 'del':
- old, new = line, next
- else:
- old, new = next, line
-
- oldwords = re.split(r'(\W)', old['line'])
- newwords = re.split(r'(\W)', new['line'])
-
- sequence = difflib.SequenceMatcher(None, oldwords, newwords)
-
- oldfragments, newfragments = [], []
- for tag, i1, i2, j1, j2 in sequence.get_opcodes():
- oldfrag = ''.join(oldwords[i1:i2])
- newfrag = ''.join(newwords[j1:j2])
- if tag != 'equal':
- if oldfrag:
- oldfrag = '%s' % oldfrag
- if newfrag:
- newfrag = '%s' % newfrag
- oldfragments.append(oldfrag)
- newfragments.append(newfrag)
-
- old['line'] = "".join(oldfragments)
- new['line'] = "".join(newfragments)
-
- def _highlight_line_udiff(self, line, next):
- """Highlight inline changes in both lines."""
- start = 0
- limit = min(len(line['line']), len(next['line']))
- while start < limit and line['line'][start] == next['line'][start]:
- start += 1
- end = -1
- limit -= start
- while - end <= limit and line['line'][end] == next['line'][end]:
- end -= 1
- end += 1
- if start or end:
- def do(l):
- last = end + len(l['line'])
- if l['action'] == 'add':
- tag = 'ins'
- else:
- tag = 'del'
- l['line'] = '%s<%s>%s%s>%s' % (
- l['line'][:start],
- tag,
- l['line'][start:last],
- tag,
- l['line'][last:]
- )
- do(line)
- do(next)
-
- def _parse_udiff(self):
- """Parse the diff an return data for the template."""
- lineiter = iter(self.lines)
- files = []
- try:
- line = lineiter.next()
- while 1:
- # continue until we found the old file
- if not line.startswith('--- '):
- line = lineiter.next()
- continue
-
- chunks = []
- filename, old_rev, new_rev = \
- self._extract_rev(line, lineiter.next())
- files.append({
- 'filename': filename,
- 'old_revision': old_rev,
- 'new_revision': new_rev,
- 'chunks': chunks
- })
-
- line = lineiter.next()
- while line:
- match = self._chunk_re.match(line)
- if not match:
- break
-
- lines = []
- chunks.append(lines)
-
- old_line, old_end, new_line, new_end = \
- [int(x or 1) for x in match.groups()[:-1]]
- old_line -= 1
- new_line -= 1
- context = match.groups()[-1]
- old_end += old_line
- new_end += new_line
-
- if context:
- lines.append({
- 'old_lineno': None,
- 'new_lineno': None,
- 'action': 'context',
- 'line': line,
- })
-
- line = lineiter.next()
-
- while old_line < old_end or new_line < new_end:
- if line:
- command, line = line[0], line[1:]
- else:
- command = ' '
- affects_old = affects_new = False
-
- # ignore those if we don't expect them
- if command in '#@':
- continue
- elif command == '+':
- affects_new = True
- action = 'add'
- elif command == '-':
- affects_old = True
- action = 'del'
- else:
- affects_old = affects_new = True
- action = 'unmod'
-
- old_line += affects_old
- new_line += affects_new
- lines.append({
- 'old_lineno': affects_old and old_line or '',
- 'new_lineno': affects_new and new_line or '',
- 'action': action,
- 'line': line
- })
- line = lineiter.next()
-
- except StopIteration:
- pass
-
- # highlight inline changes
- for file in files:
- for chunk in chunks:
- lineiter = iter(chunk)
- first = True
- try:
- while 1:
- line = lineiter.next()
- if line['action'] != 'unmod':
- nextline = lineiter.next()
- if nextline['action'] == 'unmod' or \
- nextline['action'] == line['action']:
- continue
- self.differ(line, nextline)
- except StopIteration:
- pass
-
- return files
-
- def prepare(self):
- """Prepare the passed udiff for HTML rendering."""
- return self._parse_udiff()
diff --git a/pylons_app/public/css/diff.css b/pylons_app/public/css/diff.css
--- a/pylons_app/public/css/diff.css
+++ b/pylons_app/public/css/diff.css
@@ -24,6 +24,14 @@ div.diffblock .code-body{
.code-difftable{
border-collapse: collapse;
+ width: 99%;
+}
+.code-difftable td:target *{
+ background: repeat scroll 0 0 #FFFFBE !important;
+ text-decoration: underline;
+}
+.code-difftable .context{
+ background:none repeat scroll 0 0 #DDE7EF;
}
.code-difftable .add{
background:none repeat scroll 0 0 #DDFFDD;
diff --git a/pylons_app/public/css/pygments.css b/pylons_app/public/css/pygments.css
--- a/pylons_app/public/css/pygments.css
+++ b/pylons_app/public/css/pygments.css
@@ -14,10 +14,14 @@ div.codeblock .code-header{
color:blue;
padding:10px 0 10px 0;
}
-div.codeblock .code-header span{
+div.codeblock .code-header .revision{
margin-left:25px;
font-weight: bold;
}
+div.codeblock .code-header .commit{
+ margin-left:25px;
+ font-weight: normal;
+}
.code-highlight {
padding: 0px;
diff --git a/pylons_app/templates/files/file_diff.html b/pylons_app/templates/files/file_diff.html
--- a/pylons_app/templates/files/file_diff.html
+++ b/pylons_app/templates/files/file_diff.html
@@ -34,25 +34,7 @@
%if c.no_changes:
${_('No changes')}
%else:
-
- ${y['old_lineno']}- |
-
- ${y['new_lineno']}- |
-
- ${y['line']|n}- |
-