summaryrefslogtreecommitdiffabout
path: root/ui-diff.c
authorRagnar Ouchterlony <ragnar@lysator.liu.se>2009-09-14 18:19:02 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-09-16 18:17:56 (UTC)
commitc358aa3dfebf4fc1f3005dd960aa5c1c020eed76 (patch) (unidiff)
tree475fa421d673b270c7d1bde872b96425abfafce8 /ui-diff.c
parent40e174d5364910750413d94b5417e57d108190ef (diff)
downloadcgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.zip
cgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.tar.gz
cgit-c358aa3dfebf4fc1f3005dd960aa5c1c020eed76.tar.bz2
Add possibility to switch between unidiff and side-by-side-diff.
A new config option side-by-side-diffs added, defaulting to 0, meaning unidiff. Also a query option (ss) is used toggle this. In the commit page you can switch between the two diff formats by clicking on the link on the "commit"-row, to the right of (patch). In the diff page you can switch by using the link at the start of the page. All commit-links and diff-links will remember the choice. Signed-off-by: Ragnar Ouchterlony <ragnar@lysator.liu.se> Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-diff.c') (more/less context) (ignore whitespace changes)
-rw-r--r--ui-diff.c22
1 files changed, 20 insertions, 2 deletions
diff --git a/ui-diff.c b/ui-diff.c
index 0c6f8d7..42e81ac 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -64,49 +64,49 @@ static void print_fileinfo(struct fileinfo *info)
64 case DIFF_STATUS_UNMERGED: 64 case DIFF_STATUS_UNMERGED:
65 class = "stg"; 65 class = "stg";
66 break; 66 break;
67 default: 67 default:
68 die("bug: unhandled diff status %c", info->status); 68 die("bug: unhandled diff status %c", info->status);
69 } 69 }
70 70
71 html("<tr>"); 71 html("<tr>");
72 htmlf("<td class='mode'>"); 72 htmlf("<td class='mode'>");
73 if (is_null_sha1(info->new_sha1)) { 73 if (is_null_sha1(info->new_sha1)) {
74 cgit_print_filemode(info->old_mode); 74 cgit_print_filemode(info->old_mode);
75 } else { 75 } else {
76 cgit_print_filemode(info->new_mode); 76 cgit_print_filemode(info->new_mode);
77 } 77 }
78 78
79 if (info->old_mode != info->new_mode && 79 if (info->old_mode != info->new_mode &&
80 !is_null_sha1(info->old_sha1) && 80 !is_null_sha1(info->old_sha1) &&
81 !is_null_sha1(info->new_sha1)) { 81 !is_null_sha1(info->new_sha1)) {
82 html("<span class='modechange'>["); 82 html("<span class='modechange'>[");
83 cgit_print_filemode(info->old_mode); 83 cgit_print_filemode(info->old_mode);
84 html("]</span>"); 84 html("]</span>");
85 } 85 }
86 htmlf("</td><td class='%s'>", class); 86 htmlf("</td><td class='%s'>", class);
87 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, 87 cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
88 ctx.qry.sha2, info->new_path); 88 ctx.qry.sha2, info->new_path, 0);
89 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) 89 if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED)
90 htmlf(" (%s from %s)", 90 htmlf(" (%s from %s)",
91 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed", 91 info->status == DIFF_STATUS_COPIED ? "copied" : "renamed",
92 info->old_path); 92 info->old_path);
93 html("</td><td class='right'>"); 93 html("</td><td class='right'>");
94 if (info->binary) { 94 if (info->binary) {
95 htmlf("bin</td><td class='graph'>%d -> %d bytes", 95 htmlf("bin</td><td class='graph'>%d -> %d bytes",
96 info->old_size, info->new_size); 96 info->old_size, info->new_size);
97 return; 97 return;
98 } 98 }
99 htmlf("%d", info->added + info->removed); 99 htmlf("%d", info->added + info->removed);
100 html("</td><td class='graph'>"); 100 html("</td><td class='graph'>");
101 htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes)); 101 htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
102 htmlf("<td class='add' style='width: %.1f%%;'/>", 102 htmlf("<td class='add' style='width: %.1f%%;'/>",
103 info->added * 100.0 / max_changes); 103 info->added * 100.0 / max_changes);
104 htmlf("<td class='rem' style='width: %.1f%%;'/>", 104 htmlf("<td class='rem' style='width: %.1f%%;'/>",
105 info->removed * 100.0 / max_changes); 105 info->removed * 100.0 / max_changes);
106 htmlf("<td class='none' style='width: %.1f%%;'/>", 106 htmlf("<td class='none' style='width: %.1f%%;'/>",
107 (max_changes - info->removed - info->added) * 100.0 / max_changes); 107 (max_changes - info->removed - info->added) * 100.0 / max_changes);
108 html("</tr></table></td></tr>\n"); 108 html("</tr></table></td></tr>\n");
109} 109}
110 110
111static void count_diff_lines(char *line, int len) 111static void count_diff_lines(char *line, int len)
112{ 112{
@@ -139,49 +139,49 @@ static void inspect_filepair(struct diff_filepair *pair)
139 hashcpy(items[files-1].old_sha1, pair->one->sha1); 139 hashcpy(items[files-1].old_sha1, pair->one->sha1);
140 hashcpy(items[files-1].new_sha1, pair->two->sha1); 140 hashcpy(items[files-1].new_sha1, pair->two->sha1);
141 items[files-1].old_mode = pair->one->mode; 141 items[files-1].old_mode = pair->one->mode;
142 items[files-1].new_mode = pair->two->mode; 142 items[files-1].new_mode = pair->two->mode;
143 items[files-1].old_path = xstrdup(pair->one->path); 143 items[files-1].old_path = xstrdup(pair->one->path);
144 items[files-1].new_path = xstrdup(pair->two->path); 144 items[files-1].new_path = xstrdup(pair->two->path);
145 items[files-1].added = lines_added; 145 items[files-1].added = lines_added;
146 items[files-1].removed = lines_removed; 146 items[files-1].removed = lines_removed;
147 items[files-1].old_size = old_size; 147 items[files-1].old_size = old_size;
148 items[files-1].new_size = new_size; 148 items[files-1].new_size = new_size;
149 items[files-1].binary = binary; 149 items[files-1].binary = binary;
150 if (lines_added + lines_removed > max_changes) 150 if (lines_added + lines_removed > max_changes)
151 max_changes = lines_added + lines_removed; 151 max_changes = lines_added + lines_removed;
152 total_adds += lines_added; 152 total_adds += lines_added;
153 total_rems += lines_removed; 153 total_rems += lines_removed;
154} 154}
155 155
156void cgit_print_diffstat(const unsigned char *old_sha1, 156void cgit_print_diffstat(const unsigned char *old_sha1,
157 const unsigned char *new_sha1) 157 const unsigned char *new_sha1)
158{ 158{
159 int i; 159 int i;
160 160
161 html("<div class='diffstat-header'>"); 161 html("<div class='diffstat-header'>");
162 cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1, 162 cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
163 ctx.qry.sha2, NULL); 163 ctx.qry.sha2, NULL, 0);
164 html("</div>"); 164 html("</div>");
165 html("<table summary='diffstat' class='diffstat'>"); 165 html("<table summary='diffstat' class='diffstat'>");
166 max_changes = 0; 166 max_changes = 0;
167 cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL); 167 cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, NULL);
168 for(i = 0; i<files; i++) 168 for(i = 0; i<files; i++)
169 print_fileinfo(&items[i]); 169 print_fileinfo(&items[i]);
170 html("</table>"); 170 html("</table>");
171 html("<div class='diffstat-summary'>"); 171 html("<div class='diffstat-summary'>");
172 htmlf("%d files changed, %d insertions, %d deletions", 172 htmlf("%d files changed, %d insertions, %d deletions",
173 files, total_adds, total_rems); 173 files, total_adds, total_rems);
174 html("</div>"); 174 html("</div>");
175} 175}
176 176
177 177
178/* 178/*
179 * print a single line returned from xdiff 179 * print a single line returned from xdiff
180 */ 180 */
181static void print_line(char *line, int len) 181static void print_line(char *line, int len)
182{ 182{
183 char *class = "ctx"; 183 char *class = "ctx";
184 char c = line[len-1]; 184 char c = line[len-1];
185 185
186 if (line[0] == '+') 186 if (line[0] == '+')
187 class = "add"; 187 class = "add";
@@ -229,48 +229,61 @@ static void header(unsigned char *sha1, char *path1, int mode1,
229 free(abbrev2); 229 free(abbrev2);
230 if (mode1 != 0 && mode2 != 0) { 230 if (mode1 != 0 && mode2 != 0) {
231 htmlf(" %.6o", mode1); 231 htmlf(" %.6o", mode1);
232 if (mode2 != mode1) 232 if (mode2 != mode1)
233 htmlf("..%.6o", mode2); 233 htmlf("..%.6o", mode2);
234 } 234 }
235 html("<br/>--- a/"); 235 html("<br/>--- a/");
236 if (mode1 != 0) 236 if (mode1 != 0)
237 cgit_tree_link(path1, NULL, NULL, ctx.qry.head, 237 cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
238 sha1_to_hex(old_rev_sha1), path1); 238 sha1_to_hex(old_rev_sha1), path1);
239 else 239 else
240 html_txt(path1); 240 html_txt(path1);
241 html("<br/>+++ b/"); 241 html("<br/>+++ b/");
242 if (mode2 != 0) 242 if (mode2 != 0)
243 cgit_tree_link(path2, NULL, NULL, ctx.qry.head, 243 cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
244 sha1_to_hex(new_rev_sha1), path2); 244 sha1_to_hex(new_rev_sha1), path2);
245 else 245 else
246 html_txt(path2); 246 html_txt(path2);
247 } 247 }
248 html("</div>"); 248 html("</div>");
249 if (use_ssdiff) 249 if (use_ssdiff)
250 cgit_ssdiff_header(); 250 cgit_ssdiff_header();
251} 251}
252 252
253static void print_ssdiff_link()
254{
255 if (!strcmp(ctx.qry.page, "diff")) {
256 if (use_ssdiff)
257 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head,
258 ctx.qry.sha1, ctx.qry.sha2, NULL, 1);
259 else
260 cgit_diff_link("Side-by-side diff", NULL, NULL,
261 ctx.qry.head, ctx.qry.sha1,
262 ctx.qry.sha2, NULL, 1);
263 }
264}
265
253static void filepair_cb(struct diff_filepair *pair) 266static void filepair_cb(struct diff_filepair *pair)
254{ 267{
255 unsigned long old_size = 0; 268 unsigned long old_size = 0;
256 unsigned long new_size = 0; 269 unsigned long new_size = 0;
257 int binary = 0; 270 int binary = 0;
258 linediff_fn print_line_fn = print_line; 271 linediff_fn print_line_fn = print_line;
259 272
260 header(pair->one->sha1, pair->one->path, pair->one->mode, 273 header(pair->one->sha1, pair->one->path, pair->one->mode,
261 pair->two->sha1, pair->two->path, pair->two->mode); 274 pair->two->sha1, pair->two->path, pair->two->mode);
262 if (use_ssdiff) { 275 if (use_ssdiff) {
263 cgit_ssdiff_header(); 276 cgit_ssdiff_header();
264 print_line_fn = cgit_ssdiff_line_cb; 277 print_line_fn = cgit_ssdiff_line_cb;
265 } 278 }
266 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { 279 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
267 if (S_ISGITLINK(pair->one->mode)) 280 if (S_ISGITLINK(pair->one->mode))
268 print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); 281 print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
269 if (S_ISGITLINK(pair->two->mode)) 282 if (S_ISGITLINK(pair->two->mode))
270 print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); 283 print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
271 return; 284 return;
272 } 285 }
273 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, 286 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
274 &new_size, &binary, print_line_fn)) 287 &new_size, &binary, print_line_fn))
275 cgit_print_error("Error running diff"); 288 cgit_print_error("Error running diff");
276 if (binary) 289 if (binary)
@@ -293,32 +306,37 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefi
293 cgit_print_error(fmt("Bad object name: %s", new_rev)); 306 cgit_print_error(fmt("Bad object name: %s", new_rev));
294 return; 307 return;
295 } 308 }
296 commit = lookup_commit_reference(new_rev_sha1); 309 commit = lookup_commit_reference(new_rev_sha1);
297 if (!commit || parse_commit(commit)) 310 if (!commit || parse_commit(commit))
298 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1))); 311 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1)));
299 312
300 if (old_rev) 313 if (old_rev)
301 get_sha1(old_rev, old_rev_sha1); 314 get_sha1(old_rev, old_rev_sha1);
302 else if (commit->parents && commit->parents->item) 315 else if (commit->parents && commit->parents->item)
303 hashcpy(old_rev_sha1, commit->parents->item->object.sha1); 316 hashcpy(old_rev_sha1, commit->parents->item->object.sha1);
304 else 317 else
305 hashclr(old_rev_sha1); 318 hashclr(old_rev_sha1);
306 319
307 if (!is_null_sha1(old_rev_sha1)) { 320 if (!is_null_sha1(old_rev_sha1)) {
308 type = sha1_object_info(old_rev_sha1, &size); 321 type = sha1_object_info(old_rev_sha1, &size);
309 if (type == OBJ_BAD) { 322 if (type == OBJ_BAD) {
310 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1))); 323 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1)));
311 return; 324 return;
312 } 325 }
313 commit2 = lookup_commit_reference(old_rev_sha1); 326 commit2 = lookup_commit_reference(old_rev_sha1);
314 if (!commit2 || parse_commit(commit2)) 327 if (!commit2 || parse_commit(commit2))
315 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1))); 328 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
316 } 329 }
330
331 if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff))
332 use_ssdiff = 1;
333
334 print_ssdiff_link();
317 cgit_print_diffstat(old_rev_sha1, new_rev_sha1); 335 cgit_print_diffstat(old_rev_sha1, new_rev_sha1);
318 336
319 html("<table summary='diff' class='diff'>"); 337 html("<table summary='diff' class='diff'>");
320 html("<tr><td>"); 338 html("<tr><td>");
321 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix); 339 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix);
322 html("</td></tr>"); 340 html("</td></tr>");
323 html("</table>"); 341 html("</table>");
324} 342}