diff --git a/kallithea/controllers/changeset.py b/kallithea/controllers/changeset.py
--- a/kallithea/controllers/changeset.py
+++ b/kallithea/controllers/changeset.py
@@ -286,9 +286,8 @@ class ChangesetController(BaseRepoContro
filename = f['filename']
fid = h.FID(changeset.raw_id, filename)
url_fid = h.FID('', filename)
- diff = diff_processor.as_html(enable_comments=enable_comments,
- parsed_lines=[f])
- file_diff_data.append((fid, url_fid, f['operation'], f['old_filename'], filename, diff, st))
+ html_diff = diffs.as_html(enable_comments=enable_comments, parsed_lines=[f])
+ file_diff_data.append((fid, url_fid, f['operation'], f['old_filename'], filename, html_diff, st))
else:
# downloads/raw we only need RAW diff nothing else
file_diff_data.append(('', None, None, None, raw_diff, None))
diff --git a/kallithea/controllers/compare.py b/kallithea/controllers/compare.py
--- a/kallithea/controllers/compare.py
+++ b/kallithea/controllers/compare.py
@@ -281,8 +281,7 @@ class CompareController(BaseRepoControll
c.lines_deleted += st['deleted']
filename = f['filename']
fid = h.FID('', filename)
- diff = diff_processor.as_html(enable_comments=False,
- parsed_lines=[f])
- c.file_diff_data.append((fid, None, f['operation'], f['old_filename'], filename, diff, st))
+ html_diff = diffs.as_html(enable_comments=False, parsed_lines=[f])
+ c.file_diff_data.append((fid, None, f['operation'], f['old_filename'], filename, html_diff, st))
return render('compare/compare_diff.html')
diff --git a/kallithea/controllers/pullrequests.py b/kallithea/controllers/pullrequests.py
--- a/kallithea/controllers/pullrequests.py
+++ b/kallithea/controllers/pullrequests.py
@@ -608,9 +608,8 @@ class PullrequestsController(BaseRepoCon
c.lines_deleted += st['deleted']
filename = f['filename']
fid = h.FID('', filename)
- diff = diff_processor.as_html(enable_comments=True,
- parsed_lines=[f])
- c.file_diff_data.append((fid, None, f['operation'], f['old_filename'], filename, diff, st))
+ html_diff = diffs.as_html(enable_comments=True, parsed_lines=[f])
+ c.file_diff_data.append((fid, None, f['operation'], f['old_filename'], filename, html_diff, st))
# inline comments
c.inline_cnt = 0
diff --git a/kallithea/lib/diffs.py b/kallithea/lib/diffs.py
--- a/kallithea/lib/diffs.py
+++ b/kallithea/lib/diffs.py
@@ -40,6 +40,131 @@ from kallithea.lib.utils2 import safe_un
log = logging.getLogger(__name__)
+def _safe_id(idstring):
+ """Make a string safe for including in an id attribute.
+
+ The HTML spec says that id attributes 'must begin with
+ a letter ([A-Za-z]) and may be followed by any number
+ of letters, digits ([0-9]), hyphens ("-"), underscores
+ ("_"), colons (":"), and periods (".")'. These regexps
+ are slightly over-zealous, in that they remove colons
+ and periods unnecessarily.
+
+ Whitespace is transformed into underscores, and then
+ anything which is not a hyphen or a character that
+ matches \w (alphanumerics and underscore) is removed.
+
+ """
+ # Transform all whitespace to underscore
+ idstring = re.sub(r'\s', "_", idstring)
+ # Remove everything that is not a hyphen or a member of \w
+ idstring = re.sub(r'(?!-)\W', "", idstring).lower()
+ return idstring
+
+
+def as_html(table_class='code-difftable', line_class='line',
+ old_lineno_class='lineno old', new_lineno_class='lineno new',
+ no_lineno_class='lineno',
+ code_class='code', enable_comments=False, parsed_lines=None):
+ """
+ Return given diff as html table with customized css classes
+ """
+ def _link_to_if(condition, label, url):
+ """
+ Generates a link if condition is meet or just the label if not.
+ """
+
+ if condition:
+ return '''%(label)s''' % {
+ 'url': url,
+ 'label': label
+ }
+ else:
+ return label
+
+ _html_empty = True
+ _html = []
+ _html.append('''
\n''' % {
+ 'table_class': table_class
+ })
+
+ for diff in parsed_lines:
+ for line in diff['chunks']:
+ _html_empty = False
+ for change in line:
+ _html.append('''\n''' % {
+ 'lc': line_class,
+ 'action': change['action']
+ })
+ anchor_old_id = ''
+ anchor_new_id = ''
+ anchor_old = "%(filename)s_o%(oldline_no)s" % {
+ 'filename': _safe_id(diff['filename']),
+ 'oldline_no': change['old_lineno']
+ }
+ anchor_new = "%(filename)s_n%(oldline_no)s" % {
+ 'filename': _safe_id(diff['filename']),
+ 'oldline_no': change['new_lineno']
+ }
+ cond_old = (change['old_lineno'] != '...' and
+ change['old_lineno'])
+ cond_new = (change['new_lineno'] != '...' and
+ change['new_lineno'])
+ no_lineno = (change['old_lineno'] == '...' and
+ change['new_lineno'] == '...')
+ if cond_old:
+ anchor_old_id = 'id="%s"' % anchor_old
+ if cond_new:
+ anchor_new_id = 'id="%s"' % anchor_new
+ ###########################################################
+ # OLD LINE NUMBER
+ ###########################################################
+ _html.append('''\t| ''' % {
+ 'a_id': anchor_old_id,
+ 'olc': no_lineno_class if no_lineno else old_lineno_class,
+ 'colspan': 'colspan="2"' if no_lineno else ''
+ })
+
+ _html.append('''%(link)s''' % {
+ 'link': _link_to_if(not no_lineno, change['old_lineno'],
+ '#%s' % anchor_old)
+ })
+ _html.append(''' | \n''')
+ ###########################################################
+ # NEW LINE NUMBER
+ ###########################################################
+
+ if not no_lineno:
+ _html.append('''\t''' % {
+ 'a_id': anchor_new_id,
+ 'nlc': new_lineno_class
+ })
+
+ _html.append('''%(link)s''' % {
+ 'link': _link_to_if(True, change['new_lineno'],
+ '#%s' % anchor_new)
+ })
+ _html.append(''' | \n''')
+ ###########################################################
+ # CODE
+ ###########################################################
+ comments = '' if enable_comments else 'no-comment'
+ _html.append('''\t''' % {
+ 'cc': code_class,
+ 'inc': comments
+ })
+ _html.append('''\n\t\t%(code)s \n''' % {
+ 'code': change['line']
+ })
+
+ _html.append('''\t | ''')
+ _html.append('''\n
\n''')
+ _html.append('''
''')
+ if _html_empty:
+ return None
+ return ''.join(_html)
+
+
def wrap_to_table(html):
"""Given a string with html, return it wrapped in a table, similar to what
DiffProcessor returns."""
@@ -65,7 +190,7 @@ def wrapped_diff(filenode_old, filenode_
op = None
a_path = filenode_old.path # default, might be overriden by actual rename in diff
if filenode_old.is_binary or filenode_new.is_binary:
- diff = wrap_to_table(_('Binary file'))
+ html_diff = wrap_to_table(_('Binary file'))
stats = (0, 0)
elif diff_limit != -1 and (
@@ -81,26 +206,26 @@ def wrapped_diff(filenode_old, filenode_
op = f['operation']
a_path = f['old_filename']
- diff = diff_processor.as_html(enable_comments=enable_comments)
+ html_diff = as_html(parsed_lines=diff_processor.parsed, enable_comments=enable_comments)
stats = diff_processor.stat()
else:
- diff = wrap_to_table(_('Changeset was too big and was cut off, use '
+ html_diff = wrap_to_table(_('Changeset was too big and was cut off, use '
'diff menu to display this diff'))
stats = (0, 0)
- if not diff:
+ if not html_diff:
submodules = filter(lambda o: isinstance(o, SubModuleNode),
[filenode_new, filenode_old])
if submodules:
- diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
+ html_diff = wrap_to_table(escape('Submodule %r' % submodules[0]))
else:
- diff = wrap_to_table(_('No changes detected'))
+ html_diff = wrap_to_table(_('No changes detected'))
cs1 = filenode_old.changeset.raw_id
cs2 = filenode_new.changeset.raw_id
- return cs1, cs2, a_path, diff, stats, op
+ return cs1, cs2, a_path, html_diff, stats, op
def get_gitdiff(filenode_old, filenode_new, ignore_whitespace=True, context=3):
@@ -127,7 +252,6 @@ def get_gitdiff(filenode_old, filenode_n
ignore_whitespace, context)
return vcs_gitdiff
-
NEW_FILENODE = 1
DEL_FILENODE = 2
MOD_FILENODE = 3
@@ -523,133 +647,6 @@ class DiffProcessor(object):
return chunks, added, deleted
- def _safe_id(self, idstring):
- """Make a string safe for including in an id attribute.
-
- The HTML spec says that id attributes 'must begin with
- a letter ([A-Za-z]) and may be followed by any number
- of letters, digits ([0-9]), hyphens ("-"), underscores
- ("_"), colons (":"), and periods (".")'. These regexps
- are slightly over-zealous, in that they remove colons
- and periods unnecessarily.
-
- Whitespace is transformed into underscores, and then
- anything which is not a hyphen or a character that
- matches \w (alphanumerics and underscore) is removed.
-
- """
- # Transform all whitespace to underscore
- idstring = re.sub(r'\s', "_", idstring)
- # Remove everything that is not a hyphen or a member of \w
- idstring = re.sub(r'(?!-)\W', "", idstring).lower()
- return idstring
-
- def as_html(self, table_class='code-difftable', line_class='line',
- old_lineno_class='lineno old', new_lineno_class='lineno new',
- no_lineno_class='lineno',
- code_class='code', enable_comments=False, parsed_lines=None):
- """
- Return given diff as html table with customized css classes
- """
- def _link_to_if(condition, label, url):
- """
- Generates a link if condition is meet or just the label if not.
- """
-
- if condition:
- return '''%(label)s''' % {
- 'url': url,
- 'label': label
- }
- else:
- return label
-
- diff_lines = self.parsed
- if parsed_lines:
- diff_lines = parsed_lines
-
- _html_empty = True
- _html = []
- _html.append('''\n''' % {
- 'table_class': table_class
- })
-
- for diff in diff_lines:
- for line in diff['chunks']:
- _html_empty = False
- for change in line:
- _html.append('''\n''' % {
- 'lc': line_class,
- 'action': change['action']
- })
- anchor_old_id = ''
- anchor_new_id = ''
- anchor_old = "%(filename)s_o%(oldline_no)s" % {
- 'filename': self._safe_id(diff['filename']),
- 'oldline_no': change['old_lineno']
- }
- anchor_new = "%(filename)s_n%(oldline_no)s" % {
- 'filename': self._safe_id(diff['filename']),
- 'oldline_no': change['new_lineno']
- }
- cond_old = (change['old_lineno'] != '...' and
- change['old_lineno'])
- cond_new = (change['new_lineno'] != '...' and
- change['new_lineno'])
- no_lineno = (change['old_lineno'] == '...' and
- change['new_lineno'] == '...')
- if cond_old:
- anchor_old_id = 'id="%s"' % anchor_old
- if cond_new:
- anchor_new_id = 'id="%s"' % anchor_new
- ###########################################################
- # OLD LINE NUMBER
- ###########################################################
- _html.append('''\t| ''' % {
- 'a_id': anchor_old_id,
- 'olc': no_lineno_class if no_lineno else old_lineno_class,
- 'colspan': 'colspan="2"' if no_lineno else ''
- })
-
- _html.append('''%(link)s''' % {
- 'link': _link_to_if(not no_lineno, change['old_lineno'],
- '#%s' % anchor_old)
- })
- _html.append(''' | \n''')
- ###########################################################
- # NEW LINE NUMBER
- ###########################################################
-
- if not no_lineno:
- _html.append('''\t''' % {
- 'a_id': anchor_new_id,
- 'nlc': new_lineno_class
- })
-
- _html.append('''%(link)s''' % {
- 'link': _link_to_if(True, change['new_lineno'],
- '#%s' % anchor_new)
- })
- _html.append(''' | \n''')
- ###########################################################
- # CODE
- ###########################################################
- comments = '' if enable_comments else 'no-comment'
- _html.append('''\t''' % {
- 'cc': code_class,
- 'inc': comments
- })
- _html.append('''\n\t\t%(code)s \n''' % {
- 'code': change['line']
- })
-
- _html.append('''\t | ''')
- _html.append('''\n
\n''')
- _html.append('''
''')
- if _html_empty:
- return None
- return ''.join(_html)
-
def stat(self):
"""
Returns tuple of added, and removed lines for this instance