# HG changeset patch # User Marcin Kuzminski # Date 1274053907 -7200 # Node ID f905f45c457ece88ca0ab527478c46377cbef9db # Parent a72fb7d330bdde3ef9876f95d08ed5ce80865124 moved diff libs to vcs. updated htmls and css for diff and source diff -r a72fb7d330bd -r f905f45c457e pylons_app/controllers/files.py --- a/pylons_app/controllers/files.py Sun May 16 19:00:21 2010 +0200 +++ b/pylons_app/controllers/files.py Mon May 17 01:51:47 2010 +0200 @@ -6,8 +6,7 @@ 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 @@ 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 -r a72fb7d330bd -r f905f45c457e pylons_app/lib/differ.py --- a/pylons_app/lib/differ.py Sun May 16 19:00:21 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -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' % ( - 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 -r a72fb7d330bd -r f905f45c457e pylons_app/public/css/diff.css --- a/pylons_app/public/css/diff.css Sun May 16 19:00:21 2010 +0200 +++ b/pylons_app/public/css/diff.css Mon May 17 01:51:47 2010 +0200 @@ -24,6 +24,14 @@ .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 -r a72fb7d330bd -r f905f45c457e pylons_app/public/css/pygments.css --- a/pylons_app/public/css/pygments.css Sun May 16 19:00:21 2010 +0200 +++ b/pylons_app/public/css/pygments.css Mon May 17 01:51:47 2010 +0200 @@ -14,10 +14,14 @@ 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 -r a72fb7d330bd -r f905f45c457e pylons_app/templates/files/file_diff.html --- a/pylons_app/templates/files/file_diff.html Sun May 16 19:00:21 2010 +0200 +++ b/pylons_app/templates/files/file_diff.html Mon May 17 01:51:47 2010 +0200 @@ -34,25 +34,7 @@ %if c.no_changes: ${_('No changes')} %else: - - %for diff in c.diff_files: - %for x in diff['chunks']: - %for y in x: - - - - - - %endfor$ - %endfor - %endfor -
-
${y['old_lineno']}
-
-
${y['new_lineno']}
-
-
${y['line']|n}
-
+ ${c.differ.as_HTML()|n} %endif diff -r a72fb7d330bd -r f905f45c457e pylons_app/templates/files/files_source.html --- a/pylons_app/templates/files/files_source.html Sun May 16 19:00:21 2010 +0200 +++ b/pylons_app/templates/files/files_source.html Mon May 17 01:51:47 2010 +0200 @@ -17,8 +17,8 @@
- ${c.files_list.name}@r${c.files_list.last_changeset.revision}:${c.files_list.last_changeset._short} - "${c.file_msg}" +
${c.files_list.name}@r${c.files_list.last_changeset.revision}:${c.files_list.last_changeset._short}
+
"${c.file_msg}"
${h.pygmentize(c.files_list.content,linenos=True,anchorlinenos=True,cssclass="code-highlight")}