|
|
<%def name="diff_line_anchor(filename, line, type)"><%
|
|
|
return '%s_%s_%i' % (h.safeid(filename), type, line)
|
|
|
%></%def>
|
|
|
|
|
|
<%def name="action_class(action)"><%
|
|
|
return {
|
|
|
'-': 'cb-deletion',
|
|
|
'+': 'cb-addition',
|
|
|
' ': 'cb-context',
|
|
|
}.get(action, 'cb-empty')
|
|
|
%></%def>
|
|
|
|
|
|
<%def name="op_class(op_id)"><%
|
|
|
return {
|
|
|
DEL_FILENODE: 'deletion', # file deleted
|
|
|
BIN_FILENODE: 'warning' # binary diff hidden
|
|
|
}.get(op_id, 'addition')
|
|
|
%></%def>
|
|
|
|
|
|
<%def name="link_for(**kw)"><%
|
|
|
new_args = request.GET.mixed()
|
|
|
new_args.update(kw)
|
|
|
return h.url('', **new_args)
|
|
|
%></%def>
|
|
|
|
|
|
<%def name="render_diffset(diffset, commit_id=None,
|
|
|
|
|
|
# collapse all file diff entries when there are more than this amount of files in the diff
|
|
|
collapse_when_files_over=20,
|
|
|
|
|
|
# collapse lines in the diff when more than this amount of lines changed in the file diff
|
|
|
lines_changed_limit=500,
|
|
|
|
|
|
# add a ruler at to the output
|
|
|
ruler_at_chars=0,
|
|
|
)">
|
|
|
<%
|
|
|
# TODO: dan: move this to an argument - and set a cookie so that it is saved
|
|
|
# default option for future requests
|
|
|
diff_mode = request.GET.get('diffmode', 'sideside')
|
|
|
if diff_mode not in ('sideside', 'unified'):
|
|
|
diff_mode = 'sideside'
|
|
|
|
|
|
collapse_all = len(diffset.files) > collapse_when_files_over
|
|
|
%>
|
|
|
|
|
|
%if diff_mode == 'sideside':
|
|
|
<style>
|
|
|
.wrapper {
|
|
|
max-width: 1600px !important;
|
|
|
}
|
|
|
</style>
|
|
|
%endif
|
|
|
%if ruler_at_chars:
|
|
|
<style>
|
|
|
.diff table.cb .cb-content:after {
|
|
|
content: "";
|
|
|
border-left: 1px solid blue;
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
height: 18px;
|
|
|
opacity: .2;
|
|
|
z-index: 10;
|
|
|
## +5 to account for diff action (+/-)
|
|
|
left: ${ruler_at_chars + 5}ch;
|
|
|
</style>
|
|
|
%endif
|
|
|
% if diffset.limited_diff:
|
|
|
<div class="alert alert-warning">
|
|
|
${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
|
|
|
</div>
|
|
|
% endif
|
|
|
|
|
|
<div class="diffset">
|
|
|
<div class="diffset-heading">
|
|
|
%if diffset.files:
|
|
|
<div class="pull-right">
|
|
|
<div class="btn-group">
|
|
|
<a
|
|
|
class="btn ${diff_mode == 'sideside' and 'btn-primary'} tooltip"
|
|
|
title="${_('View side by side')}"
|
|
|
href="${link_for(diffmode='sideside')}">
|
|
|
<span>${_('Side by Side')}</span>
|
|
|
</a>
|
|
|
<a
|
|
|
class="btn ${diff_mode == 'unified' and 'btn-primary'} tooltip"
|
|
|
title="${_('View unified')}" href="${link_for(diffmode='unified')}">
|
|
|
<span>${_('Unified')}</span>
|
|
|
</a>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="pull-left">
|
|
|
<div class="btn-group">
|
|
|
<a
|
|
|
class="btn"
|
|
|
href="#"
|
|
|
onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a>
|
|
|
<a
|
|
|
class="btn"
|
|
|
href="#"
|
|
|
onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a>
|
|
|
</div>
|
|
|
</div>
|
|
|
%endif
|
|
|
<h2 style="padding: 5px; text-align: center;">
|
|
|
%if diffset.limited_diff:
|
|
|
${ungettext('%(num)s file changed', '%(num)s files changed', diffset.changed_files) % {'num': diffset.changed_files}}
|
|
|
%else:
|
|
|
${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
|
|
|
'%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}}
|
|
|
%endif
|
|
|
</h2>
|
|
|
</div>
|
|
|
|
|
|
%if not diffset.files:
|
|
|
<p class="empty_data">${_('No files')}</p>
|
|
|
%endif
|
|
|
|
|
|
<div class="filediffs">
|
|
|
%for i, filediff in enumerate(diffset.files):
|
|
|
<%
|
|
|
lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
|
|
|
over_lines_changed_limit = lines_changed > lines_changed_limit
|
|
|
%>
|
|
|
<input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
|
|
|
<div
|
|
|
class="filediff"
|
|
|
data-f-path="${filediff['patch']['filename']}"
|
|
|
id="a_${h.FID(commit_id or '', filediff['patch']['filename'])}">
|
|
|
<label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
|
|
|
<div class="filediff-collapse-indicator"></div>
|
|
|
${diff_ops(filediff)}
|
|
|
</label>
|
|
|
${diff_menu(filediff)}
|
|
|
<table class="cb cb-diff-${diff_mode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}">
|
|
|
%if not filediff.hunks:
|
|
|
%for op_id, op_text in filediff['patch']['stats']['ops'].items():
|
|
|
<tr>
|
|
|
<td class="cb-text cb-${op_class(op_id)}" ${diff_mode == 'unified' and 'colspan=3' or 'colspan=4'}>
|
|
|
%if op_id == DEL_FILENODE:
|
|
|
${_('File was deleted')}
|
|
|
%elif op_id == BIN_FILENODE:
|
|
|
${_('Binary file hidden')}
|
|
|
%else:
|
|
|
${op_text}
|
|
|
%endif
|
|
|
</td>
|
|
|
</tr>
|
|
|
%endfor
|
|
|
%endif
|
|
|
%if over_lines_changed_limit:
|
|
|
<tr class="cb-warning cb-collapser">
|
|
|
<td class="cb-text" ${diff_mode == 'unified' and 'colspan=3' or 'colspan=4'}>
|
|
|
${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
|
|
|
<a href="#" class="cb-expand"
|
|
|
onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
|
|
|
</a>
|
|
|
<a href="#" class="cb-collapse"
|
|
|
onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')}
|
|
|
</a>
|
|
|
</td>
|
|
|
</tr>
|
|
|
%endif
|
|
|
%if filediff.patch['is_limited_diff']:
|
|
|
<tr class="cb-warning cb-collapser">
|
|
|
<td class="cb-text" ${diff_mode == 'unified' and 'colspan=3' or 'colspan=4'}>
|
|
|
${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a>
|
|
|
</td>
|
|
|
</tr>
|
|
|
%endif
|
|
|
%for hunk in filediff.hunks:
|
|
|
<tr class="cb-hunk">
|
|
|
<td ${diff_mode == 'unified' and 'colspan=2' or ''}>
|
|
|
## TODO: dan: add ajax loading of more context here
|
|
|
## <a href="#">
|
|
|
<i class="icon-more"></i>
|
|
|
## </a>
|
|
|
</td>
|
|
|
<td ${diff_mode == 'sideside' and 'colspan=3' or ''}>
|
|
|
@@
|
|
|
-${hunk.source_start},${hunk.source_length}
|
|
|
+${hunk.target_start},${hunk.target_length}
|
|
|
${hunk.section_header}
|
|
|
</td>
|
|
|
</tr>
|
|
|
%if diff_mode == 'unified':
|
|
|
${render_hunk_lines_unified(hunk)}
|
|
|
%elif diff_mode == 'sideside':
|
|
|
${render_hunk_lines_sideside(hunk)}
|
|
|
%else:
|
|
|
<tr class="cb-line">
|
|
|
<td>unknown diff mode</td>
|
|
|
</tr>
|
|
|
%endif
|
|
|
%endfor
|
|
|
</table>
|
|
|
</div>
|
|
|
%endfor
|
|
|
</div>
|
|
|
</div>
|
|
|
</%def>
|
|
|
|
|
|
<%def name="diff_ops(filediff)">
|
|
|
<%
|
|
|
stats = filediff['patch']['stats']
|
|
|
from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
|
|
|
MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
|
|
|
%>
|
|
|
<span class="pill">
|
|
|
%if filediff.source_file_path and filediff.target_file_path:
|
|
|
%if filediff.source_file_path != filediff.target_file_path: # file was renamed
|
|
|
<strong>${filediff.target_file_path}</strong> ⬅ <del>${filediff.source_file_path}</del>
|
|
|
%else:
|
|
|
## file was modified
|
|
|
<strong>${filediff.source_file_path}</strong>
|
|
|
%endif
|
|
|
%else:
|
|
|
%if filediff.source_file_path:
|
|
|
## file was deleted
|
|
|
<strong>${filediff.source_file_path}</strong>
|
|
|
%else:
|
|
|
## file was added
|
|
|
<strong>${filediff.target_file_path}</strong>
|
|
|
%endif
|
|
|
%endif
|
|
|
</span>
|
|
|
<span class="pill-group" style="float: left">
|
|
|
%if filediff.patch['is_limited_diff']:
|
|
|
<span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
|
|
|
%endif
|
|
|
%if RENAMED_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="renamed">renamed</span>
|
|
|
%endif
|
|
|
|
|
|
%if NEW_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="created">created</span>
|
|
|
%if filediff['target_mode'].startswith('120'):
|
|
|
<span class="pill" op="symlink">symlink</span>
|
|
|
%else:
|
|
|
<span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
|
|
|
%endif
|
|
|
%endif
|
|
|
|
|
|
%if DEL_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="removed">removed</span>
|
|
|
%endif
|
|
|
|
|
|
%if CHMOD_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="mode">
|
|
|
${nice_mode(filediff['source_mode'])} âž¡ ${nice_mode(filediff['target_mode'])}
|
|
|
</span>
|
|
|
%endif
|
|
|
</span>
|
|
|
|
|
|
<a class="pill filediff-anchor" href="#a_${h.FID(commit_id or '', filediff.patch['filename'])}">¶</a>
|
|
|
|
|
|
<span class="pill-group" style="float: right">
|
|
|
%if BIN_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="binary">binary</span>
|
|
|
%if MOD_FILENODE in stats['ops']:
|
|
|
<span class="pill" op="modified">modified</span>
|
|
|
%endif
|
|
|
%endif
|
|
|
%if stats['added']:
|
|
|
<span class="pill" op="added">+${stats['added']}</span>
|
|
|
%endif
|
|
|
%if stats['deleted']:
|
|
|
<span class="pill" op="deleted">-${stats['deleted']}</span>
|
|
|
%endif
|
|
|
</span>
|
|
|
|
|
|
</%def>
|
|
|
|
|
|
<%def name="nice_mode(filemode)">
|
|
|
${filemode.startswith('100') and filemode[3:] or filemode}
|
|
|
</%def>
|
|
|
|
|
|
<%def name="diff_menu(filediff)">
|
|
|
<div class="filediff-menu">
|
|
|
%if filediff.diffset.source_ref:
|
|
|
%if filediff.patch['operation'] in ['D', 'M']:
|
|
|
<a
|
|
|
class="tooltip"
|
|
|
href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}"
|
|
|
title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
|
|
|
>
|
|
|
${_('Show file before')}
|
|
|
</a>
|
|
|
%else:
|
|
|
<span
|
|
|
class="tooltip"
|
|
|
title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
|
|
|
>
|
|
|
${_('Show file before')}
|
|
|
</span>
|
|
|
%endif
|
|
|
%if filediff.patch['operation'] in ['A', 'M']:
|
|
|
<a
|
|
|
class="tooltip"
|
|
|
href="${h.url('files_home',repo_name=c.repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}"
|
|
|
title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
|
|
|
>
|
|
|
${_('Show file after')}
|
|
|
</a>
|
|
|
%else:
|
|
|
<span
|
|
|
class="tooltip"
|
|
|
title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
|
|
|
>
|
|
|
${_('Show file after')}
|
|
|
</span>
|
|
|
%endif
|
|
|
<a
|
|
|
class="tooltip"
|
|
|
title="${h.tooltip(_('Raw diff'))}"
|
|
|
href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}"
|
|
|
>
|
|
|
${_('Raw diff')}
|
|
|
</a>
|
|
|
<a
|
|
|
class="tooltip"
|
|
|
title="${h.tooltip(_('Download diff'))}"
|
|
|
href="${h.url('files_diff_home',repo_name=c.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}"
|
|
|
>
|
|
|
${_('Download diff')}
|
|
|
</a>
|
|
|
%endif
|
|
|
</div>
|
|
|
</%def>
|
|
|
|
|
|
|
|
|
<%def name="render_hunk_lines_sideside(hunk)">
|
|
|
%for i, line in enumerate(hunk.sideside):
|
|
|
<%
|
|
|
old_line_anchor, new_line_anchor = None, None
|
|
|
if line.original.lineno:
|
|
|
old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o')
|
|
|
if line.modified.lineno:
|
|
|
new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
|
|
|
%>
|
|
|
<tr class="cb-line">
|
|
|
<td class="cb-lineno ${action_class(line.original.action)}"
|
|
|
data-line-number="${line.original.lineno}"
|
|
|
%if old_line_anchor:
|
|
|
id="${old_line_anchor}"
|
|
|
%endif
|
|
|
>
|
|
|
%if line.original.lineno:
|
|
|
<a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
|
|
|
%endif
|
|
|
</td>
|
|
|
<td class="cb-content ${action_class(line.original.action)}"
|
|
|
data-line-number="o${line.original.lineno}"
|
|
|
><span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span>
|
|
|
</td>
|
|
|
<td class="cb-lineno ${action_class(line.modified.action)}"
|
|
|
data-line-number="${line.modified.lineno}"
|
|
|
%if new_line_anchor:
|
|
|
id="${new_line_anchor}"
|
|
|
%endif
|
|
|
>
|
|
|
%if line.modified.lineno:
|
|
|
<a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
|
|
|
%endif
|
|
|
</td>
|
|
|
<td class="cb-content ${action_class(line.modified.action)}"
|
|
|
data-line-number="n${line.modified.lineno}"
|
|
|
>
|
|
|
<span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span>
|
|
|
</td>
|
|
|
</tr>
|
|
|
%endfor
|
|
|
</%def>
|
|
|
|
|
|
|
|
|
<%def name="render_hunk_lines_unified(hunk)">
|
|
|
%for old_line_no, new_line_no, action, content in hunk.unified:
|
|
|
<%
|
|
|
old_line_anchor, new_line_anchor = None, None
|
|
|
if old_line_no:
|
|
|
old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o')
|
|
|
if new_line_no:
|
|
|
new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
|
|
|
%>
|
|
|
<tr class="cb-line">
|
|
|
<td class="cb-lineno ${action_class(action)}"
|
|
|
data-line-number="${old_line_no}"
|
|
|
%if old_line_anchor:
|
|
|
id="${old_line_anchor}"
|
|
|
%endif
|
|
|
>
|
|
|
%if old_line_anchor:
|
|
|
<a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
|
|
|
%endif
|
|
|
</td>
|
|
|
<td class="cb-lineno ${action_class(action)}"
|
|
|
data-line-number="${new_line_no}"
|
|
|
%if new_line_anchor:
|
|
|
id="${new_line_anchor}"
|
|
|
%endif
|
|
|
>
|
|
|
%if new_line_anchor:
|
|
|
<a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
|
|
|
%endif
|
|
|
</td>
|
|
|
<td class="cb-content ${action_class(action)}"
|
|
|
data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}"
|
|
|
><span class="cb-code">${action} ${content or '' | n}</span>
|
|
|
</td>
|
|
|
</tr>
|
|
|
%endfor
|
|
|
</%def>
|
|
|
|