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' % ( - 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()