summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (show whitespace changes)
-rw-r--r--cgit.css2
-rw-r--r--ui-diff.c12
-rw-r--r--ui-diff.h6
-rw-r--r--ui-ssdiff.c32
4 files changed, 42 insertions, 10 deletions
diff --git a/cgit.css b/cgit.css
index a2a685b..3ed1989 100644
--- a/cgit.css
+++ b/cgit.css
@@ -254,49 +254,49 @@ td.ls-mode {
254} 254}
255 255
256table.blob { 256table.blob {
257 margin-top: 0.5em; 257 margin-top: 0.5em;
258 border-top: solid 1px black; 258 border-top: solid 1px black;
259} 259}
260 260
261table.blob td.lines { 261table.blob td.lines {
262 margin: 0; padding: 0 0 0 0.5em; 262 margin: 0; padding: 0 0 0 0.5em;
263 vertical-align: top; 263 vertical-align: top;
264 color: black; 264 color: black;
265} 265}
266 266
267table.blob td.linenumbers { 267table.blob td.linenumbers {
268 margin: 0; padding: 0 0.5em 0 0.5em; 268 margin: 0; padding: 0 0.5em 0 0.5em;
269 vertical-align: top; 269 vertical-align: top;
270 text-align: right; 270 text-align: right;
271 border-right: 1px solid gray; 271 border-right: 1px solid gray;
272} 272}
273 273
274table.blob pre { 274table.blob pre {
275 padding: 0; margin: 0; 275 padding: 0; margin: 0;
276} 276}
277 277
278table.blob a.no { 278table.blob a.no, table.ssdiff a.no {
279 color: gray; 279 color: gray;
280 text-align: right; 280 text-align: right;
281 text-decoration: none; 281 text-decoration: none;
282} 282}
283 283
284table.blob a.no a:hover { 284table.blob a.no a:hover {
285 color: black; 285 color: black;
286} 286}
287 287
288table.bin-blob { 288table.bin-blob {
289 margin-top: 0.5em; 289 margin-top: 0.5em;
290 border: solid 1px black; 290 border: solid 1px black;
291} 291}
292 292
293table.bin-blob th { 293table.bin-blob th {
294 font-family: monospace; 294 font-family: monospace;
295 white-space: pre; 295 white-space: pre;
296 border: solid 1px #777; 296 border: solid 1px #777;
297 padding: 0.5em 1em; 297 padding: 0.5em 1em;
298} 298}
299 299
300table.bin-blob td { 300table.bin-blob td {
301 font-family: monospace; 301 font-family: monospace;
302 white-space: pre; 302 white-space: pre;
diff --git a/ui-diff.c b/ui-diff.c
index 7ff7e46..a53425d 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -13,48 +13,59 @@
13 13
14unsigned char old_rev_sha1[20]; 14unsigned char old_rev_sha1[20];
15unsigned char new_rev_sha1[20]; 15unsigned char new_rev_sha1[20];
16 16
17static int files, slots; 17static int files, slots;
18static int total_adds, total_rems, max_changes; 18static int total_adds, total_rems, max_changes;
19static int lines_added, lines_removed; 19static int lines_added, lines_removed;
20 20
21static struct fileinfo { 21static struct fileinfo {
22 char status; 22 char status;
23 unsigned char old_sha1[20]; 23 unsigned char old_sha1[20];
24 unsigned char new_sha1[20]; 24 unsigned char new_sha1[20];
25 unsigned short old_mode; 25 unsigned short old_mode;
26 unsigned short new_mode; 26 unsigned short new_mode;
27 char *old_path; 27 char *old_path;
28 char *new_path; 28 char *new_path;
29 unsigned int added; 29 unsigned int added;
30 unsigned int removed; 30 unsigned int removed;
31 unsigned long old_size; 31 unsigned long old_size;
32 unsigned long new_size; 32 unsigned long new_size;
33 int binary:1; 33 int binary:1;
34} *items; 34} *items;
35 35
36static int use_ssdiff = 0; 36static int use_ssdiff = 0;
37static struct diff_filepair *current_filepair;
38
39struct diff_filespec *cgit_get_current_old_file(void)
40{
41 return current_filepair->one;
42}
43
44struct diff_filespec *cgit_get_current_new_file(void)
45{
46 return current_filepair->two;
47}
37 48
38static void print_fileinfo(struct fileinfo *info) 49static void print_fileinfo(struct fileinfo *info)
39{ 50{
40 char *class; 51 char *class;
41 52
42 switch (info->status) { 53 switch (info->status) {
43 case DIFF_STATUS_ADDED: 54 case DIFF_STATUS_ADDED:
44 class = "add"; 55 class = "add";
45 break; 56 break;
46 case DIFF_STATUS_COPIED: 57 case DIFF_STATUS_COPIED:
47 class = "cpy"; 58 class = "cpy";
48 break; 59 break;
49 case DIFF_STATUS_DELETED: 60 case DIFF_STATUS_DELETED:
50 class = "del"; 61 class = "del";
51 break; 62 break;
52 case DIFF_STATUS_MODIFIED: 63 case DIFF_STATUS_MODIFIED:
53 class = "upd"; 64 class = "upd";
54 break; 65 break;
55 case DIFF_STATUS_RENAMED: 66 case DIFF_STATUS_RENAMED:
56 class = "mov"; 67 class = "mov";
57 break; 68 break;
58 case DIFF_STATUS_TYPE_CHANGED: 69 case DIFF_STATUS_TYPE_CHANGED:
59 class = "typ"; 70 class = "typ";
60 break; 71 break;
@@ -263,48 +274,49 @@ static void header(unsigned char *sha1, char *path1, int mode1,
263 } 274 }
264 html("</div>"); 275 html("</div>");
265} 276}
266 277
267static void print_ssdiff_link() 278static void print_ssdiff_link()
268{ 279{
269 if (!strcmp(ctx.qry.page, "diff")) { 280 if (!strcmp(ctx.qry.page, "diff")) {
270 if (use_ssdiff) 281 if (use_ssdiff)
271 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head, 282 cgit_diff_link("Unidiff", NULL, NULL, ctx.qry.head,
272 ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path, 1); 283 ctx.qry.sha1, ctx.qry.sha2, ctx.qry.path, 1);
273 else 284 else
274 cgit_diff_link("Side-by-side diff", NULL, NULL, 285 cgit_diff_link("Side-by-side diff", NULL, NULL,
275 ctx.qry.head, ctx.qry.sha1, 286 ctx.qry.head, ctx.qry.sha1,
276 ctx.qry.sha2, ctx.qry.path, 1); 287 ctx.qry.sha2, ctx.qry.path, 1);
277 } 288 }
278} 289}
279 290
280static void filepair_cb(struct diff_filepair *pair) 291static void filepair_cb(struct diff_filepair *pair)
281{ 292{
282 unsigned long old_size = 0; 293 unsigned long old_size = 0;
283 unsigned long new_size = 0; 294 unsigned long new_size = 0;
284 int binary = 0; 295 int binary = 0;
285 linediff_fn print_line_fn = print_line; 296 linediff_fn print_line_fn = print_line;
286 297
298 current_filepair = pair;
287 if (use_ssdiff) { 299 if (use_ssdiff) {
288 cgit_ssdiff_header_begin(); 300 cgit_ssdiff_header_begin();
289 print_line_fn = cgit_ssdiff_line_cb; 301 print_line_fn = cgit_ssdiff_line_cb;
290 } 302 }
291 header(pair->one->sha1, pair->one->path, pair->one->mode, 303 header(pair->one->sha1, pair->one->path, pair->one->mode,
292 pair->two->sha1, pair->two->path, pair->two->mode); 304 pair->two->sha1, pair->two->path, pair->two->mode);
293 if (use_ssdiff) 305 if (use_ssdiff)
294 cgit_ssdiff_header_end(); 306 cgit_ssdiff_header_end();
295 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) { 307 if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
296 if (S_ISGITLINK(pair->one->mode)) 308 if (S_ISGITLINK(pair->one->mode))
297 print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52); 309 print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
298 if (S_ISGITLINK(pair->two->mode)) 310 if (S_ISGITLINK(pair->two->mode))
299 print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52); 311 print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
300 if (use_ssdiff) 312 if (use_ssdiff)
301 cgit_ssdiff_footer(); 313 cgit_ssdiff_footer();
302 return; 314 return;
303 } 315 }
304 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size, 316 if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
305 &new_size, &binary, ctx.qry.context, 317 &new_size, &binary, ctx.qry.context,
306 ctx.qry.ignorews, print_line_fn)) 318 ctx.qry.ignorews, print_line_fn))
307 cgit_print_error("Error running diff"); 319 cgit_print_error("Error running diff");
308 if (binary) { 320 if (binary) {
309 if (use_ssdiff) 321 if (use_ssdiff)
310 html("<tr><td colspan='4'>Binary files differ</td></tr>"); 322 html("<tr><td colspan='4'>Binary files differ</td></tr>");
diff --git a/ui-diff.h b/ui-diff.h
index 70b2926..12d0c62 100644
--- a/ui-diff.h
+++ b/ui-diff.h
@@ -1,10 +1,16 @@
1#ifndef UI_DIFF_H 1#ifndef UI_DIFF_H
2#define UI_DIFF_H 2#define UI_DIFF_H
3 3
4extern void cgit_print_diffstat(const unsigned char *old_sha1, 4extern void cgit_print_diffstat(const unsigned char *old_sha1,
5 const unsigned char *new_sha1); 5 const unsigned char *new_sha1);
6 6
7extern void cgit_print_diff(const char *new_hex, const char *old_hex, 7extern void cgit_print_diff(const char *new_hex, const char *old_hex,
8 const char *prefix); 8 const char *prefix);
9 9
10extern struct diff_filespec *cgit_get_current_old_file(void);
11extern struct diff_filespec *cgit_get_current_new_file(void);
12
13extern unsigned char old_rev_sha1[20];
14extern unsigned char new_rev_sha1[20];
15
10#endif /* UI_DIFF_H */ 16#endif /* UI_DIFF_H */
diff --git a/ui-ssdiff.c b/ui-ssdiff.c
index 408e620..2481585 100644
--- a/ui-ssdiff.c
+++ b/ui-ssdiff.c
@@ -1,27 +1,28 @@
1#include "cgit.h" 1#include "cgit.h"
2#include "html.h" 2#include "html.h"
3#include "ui-shared.h" 3#include "ui-shared.h"
4#include "ui-diff.h"
4 5
5extern int use_ssdiff; 6extern int use_ssdiff;
6 7
7static int current_old_line, current_new_line; 8static int current_old_line, current_new_line;
8 9
9struct deferred_lines { 10struct deferred_lines {
10 int line_no; 11 int line_no;
11 char *line; 12 char *line;
12 struct deferred_lines *next; 13 struct deferred_lines *next;
13}; 14};
14 15
15static struct deferred_lines *deferred_old, *deferred_old_last; 16static struct deferred_lines *deferred_old, *deferred_old_last;
16static struct deferred_lines *deferred_new, *deferred_new_last; 17static struct deferred_lines *deferred_new, *deferred_new_last;
17 18
18static char *longest_common_subsequence(char *A, char *B) 19static char *longest_common_subsequence(char *A, char *B)
19{ 20{
20 int i, j, ri; 21 int i, j, ri;
21 int m = strlen(A); 22 int m = strlen(A);
22 int n = strlen(B); 23 int n = strlen(B);
23 int L[m + 1][n + 1]; 24 int L[m + 1][n + 1];
24 int tmp1, tmp2; 25 int tmp1, tmp2;
25 int lcs_length; 26 int lcs_length;
26 char *result; 27 char *result;
27 28
@@ -170,74 +171,87 @@ static void print_part_with_lcs(char *class, char *line, char *lcs)
170 c[0] = line[i]; 171 c[0] = line[i];
171 if (same) { 172 if (same) {
172 if (line[i] == lcs[j]) 173 if (line[i] == lcs[j])
173 j += 1; 174 j += 1;
174 else { 175 else {
175 same = 0; 176 same = 0;
176 htmlf("<span class='%s'>", class); 177 htmlf("<span class='%s'>", class);
177 } 178 }
178 } else if (line[i] == lcs[j]) { 179 } else if (line[i] == lcs[j]) {
179 same = 1; 180 same = 1;
180 htmlf("</span>"); 181 htmlf("</span>");
181 j += 1; 182 j += 1;
182 } 183 }
183 html_txt(c); 184 html_txt(c);
184 } 185 }
185} 186}
186 187
187static void print_ssdiff_line(char *class, 188static void print_ssdiff_line(char *class,
188 int old_line_no, 189 int old_line_no,
189 char *old_line, 190 char *old_line,
190 int new_line_no, 191 int new_line_no,
191 char *new_line, int individual_chars) 192 char *new_line, int individual_chars)
192{ 193{
193 char *lcs = NULL; 194 char *lcs = NULL;
195
194 if (old_line) 196 if (old_line)
195 old_line = replace_tabs(old_line + 1); 197 old_line = replace_tabs(old_line + 1);
196 if (new_line) 198 if (new_line)
197 new_line = replace_tabs(new_line + 1); 199 new_line = replace_tabs(new_line + 1);
198 if (individual_chars && old_line && new_line) 200 if (individual_chars && old_line && new_line)
199 lcs = longest_common_subsequence(old_line, new_line); 201 lcs = longest_common_subsequence(old_line, new_line);
200 html("<tr>"); 202 html("<tr>\n");
201 if (old_line_no > 0) 203 if (old_line_no > 0) {
202 htmlf("<td class='lineno'>%d</td><td class='%s'>", 204 struct diff_filespec *old_file = cgit_get_current_old_file();
203 old_line_no, class); 205 char *lineno_str = fmt("n%d", old_line_no);
204 else if (old_line) 206 char *id_str = fmt("%s#%s", is_null_sha1(old_file->sha1)?"HEAD":sha1_to_hex(old_rev_sha1), lineno_str);
207 html("<td class='lineno'><a class='no' href='");
208 html(cgit_fileurl(ctx.repo->url, "tree", old_file->path, id_str));
209 htmlf("' id='%s' name='%s'>%s</a>", lineno_str, lineno_str, lineno_str + 1);
210 html("</td>");
211 htmlf("<td class='%s'>", class);
212 } else if (old_line)
205 htmlf("<td class='lineno'></td><td class='%s'>", class); 213 htmlf("<td class='lineno'></td><td class='%s'>", class);
206 else 214 else
207 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 215 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
208 if (old_line) { 216 if (old_line) {
209 if (lcs) 217 if (lcs)
210 print_part_with_lcs("del", old_line, lcs); 218 print_part_with_lcs("del", old_line, lcs);
211 else 219 else
212 html_txt(old_line); 220 html_txt(old_line);
213 } 221 }
214 222
223 html("</td>\n");
224 if (new_line_no > 0) {
225 struct diff_filespec *new_file = cgit_get_current_new_file();
226 char *lineno_str = fmt("n%d", new_line_no);
227 char *id_str = fmt("%s#%s", is_null_sha1(new_file->sha1)?"HEAD":sha1_to_hex(new_rev_sha1), lineno_str);
228 html("<td class='lineno'><a class='no' href='");
229 html(cgit_fileurl(ctx.repo->url, "tree", new_file->path, id_str));
230 htmlf("' id='%s' name='%s'>%s</a>", lineno_str, lineno_str, lineno_str + 1);
215 html("</td>"); 231 html("</td>");
216 if (new_line_no > 0) 232 htmlf("<td class='%s'>", class);
217 htmlf("<td class='lineno'>%d</td><td class='%s'>", 233 } else if (new_line)
218 new_line_no, class);
219 else if (new_line)
220 htmlf("<td class='lineno'></td><td class='%s'>", class); 234 htmlf("<td class='lineno'></td><td class='%s'>", class);
221 else 235 else
222 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 236 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
223 if (new_line) { 237 if (new_line) {
224 if (lcs) 238 if (lcs)
225 print_part_with_lcs("add", new_line, lcs); 239 print_part_with_lcs("add", new_line, lcs);
226 else 240 else
227 html_txt(new_line); 241 html_txt(new_line);
228 } 242 }
229 243
230 html("</td></tr>"); 244 html("</td></tr>");
231 if (lcs) 245 if (lcs)
232 free(lcs); 246 free(lcs);
233 if (new_line) 247 if (new_line)
234 free(new_line); 248 free(new_line);
235 if (old_line) 249 if (old_line)
236 free(old_line); 250 free(old_line);
237} 251}
238 252
239static void print_deferred_old_lines() 253static void print_deferred_old_lines()
240{ 254{
241 struct deferred_lines *iter_old, *tmp; 255 struct deferred_lines *iter_old, *tmp;
242 iter_old = deferred_old; 256 iter_old = deferred_old;
243 while (iter_old) { 257 while (iter_old) {