##// END OF EJS Templates
implements #307, configurable diffs...
marcink -
r1776:22333ddd beta
parent child Browse files
Show More
@@ -25,12 +25,18 b''
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26 import logging
26 import logging
27 import traceback
27 import traceback
28 from collections import defaultdict
29 from webob.exc import HTTPForbidden
28
30
29 from pylons import tmpl_context as c, url, request, response
31 from pylons import tmpl_context as c, url, request, response
30 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
31 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
32 from pylons.decorators import jsonify
34 from pylons.decorators import jsonify
33
35
36 from vcs.exceptions import RepositoryError, ChangesetError, \
37 ChangesetDoesNotExistError
38 from vcs.nodes import FileNode
39
34 import rhodecode.lib.helpers as h
40 import rhodecode.lib.helpers as h
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
41 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.base import BaseRepoController, render
42 from rhodecode.lib.base import BaseRepoController, render
@@ -39,16 +45,109 b' from rhodecode.lib.compat import Ordered'
39 from rhodecode.lib import diffs
45 from rhodecode.lib import diffs
40 from rhodecode.model.db import ChangesetComment
46 from rhodecode.model.db import ChangesetComment
41 from rhodecode.model.comment import ChangesetCommentsModel
47 from rhodecode.model.comment import ChangesetCommentsModel
42
43 from vcs.exceptions import RepositoryError, ChangesetError, \
44 ChangesetDoesNotExistError
45 from vcs.nodes import FileNode
46 from webob.exc import HTTPForbidden
47 from rhodecode.model.meta import Session
48 from rhodecode.model.meta import Session
48
49
49 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
50
51
51
52
53 def anchor_url(revision,path):
54 fid = h.FID(revision, path)
55 return h.url.current(anchor=fid,**request.GET)
56
57 def get_ignore_ws(fid, GET):
58 ig_ws_global = request.GET.get('ignorews')
59 ig_ws = filter(lambda k:k.startswith('WS'),GET.getall(fid))
60 if ig_ws:
61 try:
62 return int(ig_ws[0].split(':')[-1])
63 except:
64 pass
65 return ig_ws_global
66
67 def _ignorews_url(fileid=None):
68
69 params = defaultdict(list)
70 lbl = _('show white space')
71 ig_ws = get_ignore_ws(fileid, request.GET)
72 ln_ctx = get_line_ctx(fileid, request.GET)
73 # global option
74 if fileid is None:
75 if ig_ws is None:
76 params['ignorews'] += [1]
77 lbl = _('ignore white space')
78 ctx_key = 'context'
79 ctx_val = ln_ctx
80 # per file options
81 else:
82 if ig_ws is None:
83 params[fileid] += ['WS:1']
84 lbl = _('ignore white space')
85
86 ctx_key = fileid
87 ctx_val = 'C:%s' % ln_ctx
88 # if we have passed in ln_ctx pass it along to our params
89 if ln_ctx:
90 params[ctx_key] += [ctx_val]
91
92 params['anchor'] = fileid
93 return h.link_to(lbl, h.url.current(**params))
94
95 def get_line_ctx(fid, GET):
96 ln_ctx_global = request.GET.get('context')
97 ln_ctx = filter(lambda k:k.startswith('C'),GET.getall(fid))
98
99 if ln_ctx:
100 retval = ln_ctx[0].split(':')[-1]
101 else:
102 retval = ln_ctx_global
103
104 try:
105 return int(retval)
106 except:
107 return
108
109 def _context_url(fileid=None):
110 """
111 Generates url for context lines
112
113 :param fileid:
114 """
115 ig_ws = get_ignore_ws(fileid, request.GET)
116 ln_ctx = (get_line_ctx(fileid, request.GET) or 3) * 2
117
118 params = defaultdict(list)
119
120 # global option
121 if fileid is None:
122 if ln_ctx > 0:
123 params['context'] += [ln_ctx]
124
125 if ig_ws:
126 ig_ws_key = 'ignorews'
127 ig_ws_val = 1
128
129 # per file option
130 else:
131 params[fileid] += ['C:%s' % ln_ctx]
132 ig_ws_key = fileid
133 ig_ws_val = 'WS:%s' % 1
134
135 if ig_ws:
136 params[ig_ws_key] += [ig_ws_val]
137
138 lbl = _('%s line context') % ln_ctx
139
140 params['anchor'] = fileid
141 return h.link_to(lbl, h.url.current(**params))
142
143 def wrap_to_table(str_):
144 return '''<table class="code-difftable">
145 <tr class="line">
146 <td class="lineno new"></td>
147 <td class="code"><pre>%s</pre></td>
148 </tr>
149 </table>''' % str_
150
52 class ChangesetController(BaseRepoController):
151 class ChangesetController(BaseRepoController):
53
152
54 @LoginRequired()
153 @LoginRequired()
@@ -59,16 +158,10 b' class ChangesetController(BaseRepoContro'
59 c.affected_files_cut_off = 60
158 c.affected_files_cut_off = 60
60
159
61 def index(self, revision):
160 def index(self, revision):
62 ignore_whitespace = request.GET.get('ignorews') == '1'
63 line_context = request.GET.get('context', 3)
64 def wrap_to_table(str):
65
161
66 return '''<table class="code-difftable">
162 c.anchor_url = anchor_url
67 <tr class="line">
163 c.ignorews_url = _ignorews_url
68 <td class="lineno new"></td>
164 c.context_url = _context_url
69 <td class="code"><pre>%s</pre></td>
70 </tr>
71 </table>''' % str
72
165
73 #get ranges of revisions if preset
166 #get ranges of revisions if preset
74 rev_range = revision.split('...')[:2]
167 rev_range = revision.split('...')[:2]
@@ -130,10 +223,13 b' class ChangesetController(BaseRepoContro'
130 # added nodes and their size defines how many changes were
223 # added nodes and their size defines how many changes were
131 # made
224 # made
132 c.sum_added += node.size
225 c.sum_added += node.size
226 fid = h.FID(revision, node.path)
227 line_context_lcl = get_line_ctx(fid, request.GET)
228 ignore_whitespace_lcl = get_ignore_ws(fid, request.GET)
133 if c.sum_added < self.cut_off_limit:
229 if c.sum_added < self.cut_off_limit:
134 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
230 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
135 ignore_whitespace=ignore_whitespace,
231 ignore_whitespace=ignore_whitespace_lcl,
136 context=line_context)
232 context=line_context_lcl)
137 d = diffs.DiffProcessor(f_gitdiff, format='gitdiff')
233 d = diffs.DiffProcessor(f_gitdiff, format='gitdiff')
138
234
139 st = d.stat()
235 st = d.stat()
@@ -171,9 +267,12 b' class ChangesetController(BaseRepoContro'
171 else:
267 else:
172
268
173 if c.sum_removed < self.cut_off_limit:
269 if c.sum_removed < self.cut_off_limit:
270 fid = h.FID(revision, node.path)
271 line_context_lcl = get_line_ctx(fid, request.GET)
272 ignore_whitespace_lcl = get_ignore_ws(fid, request.GET,)
174 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
273 f_gitdiff = diffs.get_gitdiff(filenode_old, node,
175 ignore_whitespace=ignore_whitespace,
274 ignore_whitespace=ignore_whitespace_lcl,
176 context=line_context)
275 context=line_context_lcl)
177 d = diffs.DiffProcessor(f_gitdiff,
276 d = diffs.DiffProcessor(f_gitdiff,
178 format='gitdiff')
277 format='gitdiff')
179 st = d.stat()
278 st = d.stat()
@@ -52,6 +52,17 b' def _reset(name, value=None, id=NotGiven'
52 reset = _reset
52 reset = _reset
53 safeid = _make_safe_id_component
53 safeid = _make_safe_id_component
54
54
55
56 def FID(raw_id,path):
57 """
58 Creates a uniqe ID for filenode based on it's path and revision
59
60 :param raw_id:
61 :param path:
62 """
63 return 'C-%s-%s' % (short_id(raw_id), safeid(safe_unicode(path)))
64
65
55 def get_token():
66 def get_token():
56 """Return the current authentication token, creating one if one doesn't
67 """Return the current authentication token, creating one if one doesn't
57 already exist.
68 already exist.
@@ -1890,7 +1890,9 b' h3.files_location {'
1890 color: #556CB5;
1890 color: #556CB5;
1891 white-space: pre-wrap;
1891 white-space: pre-wrap;
1892 }
1892 }
1893
1893 #changeset_content .container .left .message a:hover {
1894 text-decoration: none;
1895 }
1894 .cs_files .cur_cs {
1896 .cs_files .cur_cs {
1895 margin: 10px 2px;
1897 margin: 10px 2px;
1896 font-weight: bold;
1898 font-weight: bold;
@@ -2254,7 +2256,7 b' table.code-browser .browser-file {'
2254 float: left;
2256 float: left;
2255 }
2257 }
2256
2258
2257 .diffblock .changeset_header .diff-menu{
2259 .diffblock .diff-menu{
2258 position: absolute;
2260 position: absolute;
2259 background: none repeat scroll 0 0 #FFFFFF;
2261 background: none repeat scroll 0 0 #FFFFFF;
2260 border-color: #003367 #666666 #666666;
2262 border-color: #003367 #666666 #666666;
@@ -2267,14 +2269,14 b' table.code-browser .browser-file {'
2267
2269
2268 }
2270 }
2269
2271
2270 .diffblock .changeset_header .diff-menu ul li {
2272 .diffblock .diff-menu ul li {
2271 padding: 0px 0px 0px 0px !important;
2273 padding: 0px 0px 0px 0px !important;
2272 }
2274 }
2273 .diffblock .changeset_header .diff-menu ul li a{
2275 .diffblock .diff-menu ul li a{
2274 display: block;
2276 display: block;
2275 padding: 3px 8px 3px 8px !important;
2277 padding: 3px 8px 3px 8px !important;
2276 }
2278 }
2277 .diffblock .changeset_header .diff-menu ul li a:hover{
2279 .diffblock .diff-menu ul li a:hover{
2278 text-decoration: none;
2280 text-decoration: none;
2279 background-color: #EEEEEE;
2281 background-color: #EEEEEE;
2280 }
2282 }
@@ -3689,6 +3691,11 b' div.diffblock .code-header{'
3689 border-bottom: 1px solid #CCCCCC;
3691 border-bottom: 1px solid #CCCCCC;
3690 background: #EEEEEE;
3692 background: #EEEEEE;
3691 padding:10px 0 10px 0;
3693 padding:10px 0 10px 0;
3694 height: 14px;
3695 }
3696 div.diffblock .code-header .date{
3697 float:left;
3698 text-transform: uppercase;
3692 }
3699 }
3693 div.diffblock .code-header div{
3700 div.diffblock .code-header div{
3694 margin-left:4px;
3701 margin-left:4px;
@@ -18,12 +18,6 b''
18 ${self.menu('changelog')}
18 ${self.menu('changelog')}
19 </%def>
19 </%def>
20
20
21 <%def name="fid(raw_id,path)" filter="strip">
22 <%
23 return 'C-%s-%s' % (h.short_id(raw_id),h.safeid(h.safe_unicode(path)))
24 %>
25 </%def>
26
27 <%def name="main()">
21 <%def name="main()">
28 <div class="box">
22 <div class="box">
29 <!-- box / title -->
23 <!-- box / title -->
@@ -33,19 +27,24 b''
33 <div class="table">
27 <div class="table">
34 <div class="diffblock">
28 <div class="diffblock">
35 <div class="code-header">
29 <div class="code-header">
36 <div>
30 <div class="date">${_('commit')} ${c.changeset.revision}:${h.short_id(c.changeset.raw_id)} ${c.changeset.date}</div>
37 <span>${h.link_to(_('raw diff'),
31 <div class="diff-menu-wrapper">
38 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</span>
32 <img class="diff-menu-activate" style="cursor: pointer" alt="diff-menu" src="${h.url('/images/icons/script_gear.png')}" />
39 &raquo; <span>${h.link_to(_('download diff'),
33 <div class="diff-menu" style="display:none">
40 h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</span>
34 <ul>
41 <div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
35 <li>${h.link_to(_('raw diff'),h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='show'))}</li>
42 </div>
36 <li>${h.link_to(_('download diff'),h.url('raw_changeset_home',repo_name=c.repo_name,revision=c.changeset.raw_id,diff='download'))}</li>
37 <li>${c.ignorews_url()}</li>
38 <li>${c.context_url()}</li>
39 </ul>
40 </div>
41 </div>
42 <div class="comments-number" style="float:right;padding-right:5px">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
43 </div>
43 </div>
44 </div>
44 </div>
45 <div id="changeset_content">
45 <div id="changeset_content">
46 <div class="container">
46 <div class="container">
47 <div class="left">
47 <div class="left">
48 <div class="date">${_('commit')} ${c.changeset.revision}: ${h.short_id(c.changeset.raw_id)}@${c.changeset.date}</div>
49 <div class="author">
48 <div class="author">
50 <div class="gravatar">
49 <div class="gravatar">
51 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
50 <img alt="gravatar" src="${h.gravatar_url(h.email(c.changeset.author),20)}"/>
@@ -100,9 +99,9 b''
100 <div class="cs_${change}">
99 <div class="cs_${change}">
101 <div class="node">
100 <div class="node">
102 %if change != 'removed':
101 %if change != 'removed':
103 ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=self.fid(filenode.changeset.raw_id,filenode.path)))}
102 ${h.link_to(h.safe_unicode(filenode.path),c.anchor_url(filenode.changeset.raw_id,filenode.path))}
104 %else:
103 %else:
105 ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=self.fid('',filenode.path)))}
104 ${h.link_to(h.safe_unicode(filenode.path),h.url.current(anchor=h.FID('',filenode.path)))}
106 %endif
105 %endif
107 </div>
106 </div>
108 <div class="changes">${h.fancy_file_stats(stat)}</div>
107 <div class="changes">${h.fancy_file_stats(stat)}</div>
@@ -118,8 +117,8 b''
118
117
119 %for change,filenode,diff,cs1,cs2,stat in c.changes:
118 %for change,filenode,diff,cs1,cs2,stat in c.changes:
120 %if change !='removed':
119 %if change !='removed':
121 <div style="clear:both;height:10px"></div>
120 <div id="${h.FID(filenode.changeset.raw_id,filenode.path)}" style="clear:both;height:90px;margin-top:-60px"></div>
122 <div class="diffblock margined comm" id="${self.fid(filenode.changeset.raw_id,filenode.path)}">
121 <div class="diffblock margined comm">
123 <div class="code-header">
122 <div class="code-header">
124 <div class="changeset_header">
123 <div class="changeset_header">
125 <div class="changeset_file">
124 <div class="changeset_file">
@@ -133,13 +132,15 b''
133 <li>${h.link_to(_('diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</li>
132 <li>${h.link_to(_('diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='diff'))}</li>
134 <li>${h.link_to(_('raw diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</li>
133 <li>${h.link_to(_('raw diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='raw'))}</li>
135 <li>${h.link_to(_('download diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</li>
134 <li>${h.link_to(_('download diff'),h.url('files_diff_home',repo_name=c.repo_name,f_path=h.safe_unicode(filenode.path),diff2=cs2,diff1=cs1,diff='download'))}</li>
135 <li>${c.ignorews_url(h.FID(filenode.changeset.raw_id,filenode.path))}</li>
136 <li>${c.context_url(h.FID(filenode.changeset.raw_id,filenode.path))}</li>
136 </ul>
137 </ul>
137 </div>
138 </div>
138 </div>
139 </div>
139 <span style="float:right;margin-top:-3px">
140 <span style="float:right;margin-top:-3px">
140 <label>
141 <label>
141 ${_('show inline comments')}
142 ${_('show inline comments')}
142 ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=self.fid(filenode.changeset.raw_id,filenode.path))}
143 ${h.checkbox('',checked="checked",class_="show-inline-comments",id_for=h.FID(filenode.changeset.raw_id,filenode.path))}
143 </label>
144 </label>
144 </span>
145 </span>
145 </div>
146 </div>
@@ -164,7 +165,7 b''
164 <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
165 <div class="comments-number">${len(c.comments)} comment(s) (${c.inline_cnt} ${_('inline')})</div>
165
166
166 %for path, lines in c.inline_comments:
167 %for path, lines in c.inline_comments:
167 <div style="display:none" class="inline-comment-placeholder" path="${path}" target_id="${self.fid(c.changeset.raw_id,path)}">
168 <div style="display:none" class="inline-comment-placeholder" path="${path}" target_id="${h.FID(c.changeset.raw_id,path)}">
168 % for line,comments in lines.iteritems():
169 % for line,comments in lines.iteritems():
169 <div class="inline-comment-placeholder-line" line="${line}" target_id="${h.safeid(h.safe_unicode(path))}">
170 <div class="inline-comment-placeholder-line" line="${line}" target_id="${h.safeid(h.safe_unicode(path))}">
170 %for co in comments:
171 %for co in comments:
General Comments 0
You need to be logged in to leave comments. Login now