summaryrefslogtreecommitdiffabout
path: root/ui-diff.c
authorRagnar Ouchterlony <ragnar@lysator.liu.se>2009-09-13 17:36:35 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-09-16 18:17:56 (UTC)
commit40e174d5364910750413d94b5417e57d108190ef (patch) (unidiff)
tree21d71be66e1b058cecc45b861523c071fb4ee126 /ui-diff.c
parent27479ac54c99584612f7246c9456119e88621eaa (diff)
downloadcgit-40e174d5364910750413d94b5417e57d108190ef.zip
cgit-40e174d5364910750413d94b5417e57d108190ef.tar.gz
cgit-40e174d5364910750413d94b5417e57d108190ef.tar.bz2
First version of side-by-side diff.
This constitutes the first prototype of a side-by-side diff. It is not possible to switch between unidiff and side-by-side diff at all at this stage. 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.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/ui-diff.c b/ui-diff.c
index 2196745..0c6f8d7 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -1,82 +1,84 @@
1/* ui-diff.c: show diff between two blobs 1/* ui-diff.c: show diff between two blobs
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * 4 *
5 * Licensed under GNU General Public License v2 5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 6 * (see COPYING for full license text)
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include "html.h" 10#include "html.h"
11#include "ui-shared.h" 11#include "ui-shared.h"
12#include "ui-ssdiff.h"
12 13
13unsigned char old_rev_sha1[20]; 14unsigned char old_rev_sha1[20];
14unsigned char new_rev_sha1[20]; 15unsigned char new_rev_sha1[20];
15 16
16static int files, slots; 17static int files, slots;
17static int total_adds, total_rems, max_changes; 18static int total_adds, total_rems, max_changes;
18static int lines_added, lines_removed; 19static int lines_added, lines_removed;
19 20
20static struct fileinfo { 21static struct fileinfo {
21 char status; 22 char status;
22 unsigned char old_sha1[20]; 23 unsigned char old_sha1[20];
23 unsigned char new_sha1[20]; 24 unsigned char new_sha1[20];
24 unsigned short old_mode; 25 unsigned short old_mode;
25 unsigned short new_mode; 26 unsigned short new_mode;
26 char *old_path; 27 char *old_path;
27 char *new_path; 28 char *new_path;
28 unsigned int added; 29 unsigned int added;
29 unsigned int removed; 30 unsigned int removed;
30 unsigned long old_size; 31 unsigned long old_size;
31 unsigned long new_size; 32 unsigned long new_size;
32 int binary:1; 33 int binary:1;
33} *items; 34} *items;
34 35
36static int use_ssdiff = 0;
35 37
36static void print_fileinfo(struct fileinfo *info) 38static void print_fileinfo(struct fileinfo *info)
37{ 39{
38 char *class; 40 char *class;
39 41
40 switch (info->status) { 42 switch (info->status) {
41 case DIFF_STATUS_ADDED: 43 case DIFF_STATUS_ADDED:
42 class = "add"; 44 class = "add";
43 break; 45 break;
44 case DIFF_STATUS_COPIED: 46 case DIFF_STATUS_COPIED:
45 class = "cpy"; 47 class = "cpy";
46 break; 48 break;
47 case DIFF_STATUS_DELETED: 49 case DIFF_STATUS_DELETED:
48 class = "del"; 50 class = "del";
49 break; 51 break;
50 case DIFF_STATUS_MODIFIED: 52 case DIFF_STATUS_MODIFIED:
51 class = "upd"; 53 class = "upd";
52 break; 54 break;
53 case DIFF_STATUS_RENAMED: 55 case DIFF_STATUS_RENAMED:
54 class = "mov"; 56 class = "mov";
55 break; 57 break;
56 case DIFF_STATUS_TYPE_CHANGED: 58 case DIFF_STATUS_TYPE_CHANGED:
57 class = "typ"; 59 class = "typ";
58 break; 60 break;
59 case DIFF_STATUS_UNKNOWN: 61 case DIFF_STATUS_UNKNOWN:
60 class = "unk"; 62 class = "unk";
61 break; 63 break;
62 case DIFF_STATUS_UNMERGED: 64 case DIFF_STATUS_UNMERGED:
63 class = "stg"; 65 class = "stg";
64 break; 66 break;
65 default: 67 default:
66 die("bug: unhandled diff status %c", info->status); 68 die("bug: unhandled diff status %c", info->status);
67 } 69 }
68 70
69 html("<tr>"); 71 html("<tr>");
70 htmlf("<td class='mode'>"); 72 htmlf("<td class='mode'>");
71 if (is_null_sha1(info->new_sha1)) { 73 if (is_null_sha1(info->new_sha1)) {
72 cgit_print_filemode(info->old_mode); 74 cgit_print_filemode(info->old_mode);
73 } else { 75 } else {
74 cgit_print_filemode(info->new_mode); 76 cgit_print_filemode(info->new_mode);
75 } 77 }
76 78
77 if (info->old_mode != info->new_mode && 79 if (info->old_mode != info->new_mode &&
78 !is_null_sha1(info->old_sha1) && 80 !is_null_sha1(info->old_sha1) &&
79 !is_null_sha1(info->new_sha1)) { 81 !is_null_sha1(info->new_sha1)) {
80 html("<span class='modechange'>["); 82 html("<span class='modechange'>[");
81 cgit_print_filemode(info->old_mode); 83 cgit_print_filemode(info->old_mode);
82 html("]</span>"); 84 html("]</span>");
@@ -199,115 +201,124 @@ static void header(unsigned char *sha1, char *path1, int mode1,
199 unsigned char *sha2, char *path2, int mode2) 201 unsigned char *sha2, char *path2, int mode2)
200{ 202{
201 char *abbrev1, *abbrev2; 203 char *abbrev1, *abbrev2;
202 int subproject; 204 int subproject;
203 205
204 subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2)); 206 subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2));
205 html("<div class='head'>"); 207 html("<div class='head'>");
206 html("diff --git a/"); 208 html("diff --git a/");
207 html_txt(path1); 209 html_txt(path1);
208 html(" b/"); 210 html(" b/");
209 html_txt(path2); 211 html_txt(path2);
210 212
211 if (is_null_sha1(sha1)) 213 if (is_null_sha1(sha1))
212 path1 = "dev/null"; 214 path1 = "dev/null";
213 if (is_null_sha1(sha2)) 215 if (is_null_sha1(sha2))
214 path2 = "dev/null"; 216 path2 = "dev/null";
215 217
216 if (mode1 == 0) 218 if (mode1 == 0)
217 htmlf("<br/>new file mode %.6o", mode2); 219 htmlf("<br/>new file mode %.6o", mode2);
218 220
219 if (mode2 == 0) 221 if (mode2 == 0)
220 htmlf("<br/>deleted file mode %.6o", mode1); 222 htmlf("<br/>deleted file mode %.6o", mode1);
221 223
222 if (!subproject) { 224 if (!subproject) {
223 abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV)); 225 abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
224 abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV)); 226 abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV));
225 htmlf("<br/>index %s..%s", abbrev1, abbrev2); 227 htmlf("<br/>index %s..%s", abbrev1, abbrev2);
226 free(abbrev1); 228 free(abbrev1);
227 free(abbrev2); 229 free(abbrev2);
228 if (mode1 != 0 && mode2 != 0) { 230 if (mode1 != 0 && mode2 != 0) {
229 htmlf(" %.6o", mode1); 231 htmlf(" %.6o", mode1);
230 if (mode2 != mode1) 232 if (mode2 != mode1)
231 htmlf("..%.6o", mode2); 233 htmlf("..%.6o", mode2);
232 } 234 }
233 html("<br/>--- a/"); 235 html("<br/>--- a/");
234 if (mode1 != 0) 236 if (mode1 != 0)
235 cgit_tree_link(path1, NULL, NULL, ctx.qry.head, 237 cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
236 sha1_to_hex(old_rev_sha1), path1); 238 sha1_to_hex(old_rev_sha1), path1);
237 else 239 else
238 html_txt(path1); 240 html_txt(path1);
239 html("<br/>+++ b/"); 241 html("<br/>+++ b/");
240 if (mode2 != 0) 242 if (mode2 != 0)
241 cgit_tree_link(path2, NULL, NULL, ctx.qry.head, 243 cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
242 sha1_to_hex(new_rev_sha1), path2); 244 sha1_to_hex(new_rev_sha1), path2);
243 else 245 else
244 html_txt(path2); 246 html_txt(path2);
245 } 247 }
246 html("</div>"); 248 html("</div>");
249 if (use_ssdiff)
250 cgit_ssdiff_header();
247} 251}
248 252
249static void filepair_cb(struct diff_filepair *pair) 253static void filepair_cb(struct diff_filepair *pair)
250{ 254{
251 unsigned long old_size = 0; 255 unsigned long old_size = 0;
252 unsigned long new_size = 0; 256 unsigned long new_size = 0;
253 int binary = 0; 257 int binary = 0;
258 linediff_fn print_line_fn = print_line;
254 259
255 header(pair->one->sha1, pair->one->path, pair->one->mode, 260 header(pair->one->sha1, pair->one->path, pair->one->mode,
256 pair->two->sha1, pair->two->path, pair->two->mode); 261 pair->two->sha1, pair->two->path, pair->two->mode);
262 if (use_ssdiff) {
263 cgit_ssdiff_header();
264 print_line_fn = cgit_ssdiff_line_cb;
265 }
257 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { 266 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
258 if (S_ISGITLINK(pair->one->mode)) 267 if (S_ISGITLINK(pair->one->mode))
259 print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); 268 print_line(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
260 if (S_ISGITLINK(pair->two->mode)) 269 if (S_ISGITLINK(pair->two->mode))
261 print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); 270 print_line(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
262 return; 271 return;
263 } 272 }
264 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, 273 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
265 &new_size, &binary, print_line)) 274 &new_size, &binary, print_line_fn))
266 cgit_print_error("Error running diff"); 275 cgit_print_error("Error running diff");
267 if (binary) 276 if (binary)
268 html("Binary files differ"); 277 html("Binary files differ");
278 if (use_ssdiff)
279 cgit_ssdiff_footer();
269} 280}
270 281
271void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefix) 282void cgit_print_diff(const char *new_rev, const char *old_rev, const char *prefix)
272{ 283{
273 enum object_type type; 284 enum object_type type;
274 unsigned long size; 285 unsigned long size;
275 struct commit *commit, *commit2; 286 struct commit *commit, *commit2;
276 287
277 if (!new_rev) 288 if (!new_rev)
278 new_rev = ctx.qry.head; 289 new_rev = ctx.qry.head;
279 get_sha1(new_rev, new_rev_sha1); 290 get_sha1(new_rev, new_rev_sha1);
280 type = sha1_object_info(new_rev_sha1, &size); 291 type = sha1_object_info(new_rev_sha1, &size);
281 if (type == OBJ_BAD) { 292 if (type == OBJ_BAD) {
282 cgit_print_error(fmt("Bad object name: %s", new_rev)); 293 cgit_print_error(fmt("Bad object name: %s", new_rev));
283 return; 294 return;
284 } 295 }
285 commit = lookup_commit_reference(new_rev_sha1); 296 commit = lookup_commit_reference(new_rev_sha1);
286 if (!commit || parse_commit(commit)) 297 if (!commit || parse_commit(commit))
287 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1))); 298 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1)));
288 299
289 if (old_rev) 300 if (old_rev)
290 get_sha1(old_rev, old_rev_sha1); 301 get_sha1(old_rev, old_rev_sha1);
291 else if (commit->parents && commit->parents->item) 302 else if (commit->parents && commit->parents->item)
292 hashcpy(old_rev_sha1, commit->parents->item->object.sha1); 303 hashcpy(old_rev_sha1, commit->parents->item->object.sha1);
293 else 304 else
294 hashclr(old_rev_sha1); 305 hashclr(old_rev_sha1);
295 306
296 if (!is_null_sha1(old_rev_sha1)) { 307 if (!is_null_sha1(old_rev_sha1)) {
297 type = sha1_object_info(old_rev_sha1, &size); 308 type = sha1_object_info(old_rev_sha1, &size);
298 if (type == OBJ_BAD) { 309 if (type == OBJ_BAD) {
299 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1))); 310 cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1)));
300 return; 311 return;
301 } 312 }
302 commit2 = lookup_commit_reference(old_rev_sha1); 313 commit2 = lookup_commit_reference(old_rev_sha1);
303 if (!commit2 || parse_commit(commit2)) 314 if (!commit2 || parse_commit(commit2))
304 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1))); 315 cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
305 } 316 }
306 cgit_print_diffstat(old_rev_sha1, new_rev_sha1); 317 cgit_print_diffstat(old_rev_sha1, new_rev_sha1);
307 318
308 html("<table summary='diff' class='diff'>"); 319 html("<table summary='diff' class='diff'>");
309 html("<tr><td>"); 320 html("<tr><td>");
310 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix); 321 cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix);
311 html("</td></tr>"); 322 html("</td></tr>");
312 html("</table>"); 323 html("</table>");
313} 324}