summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.css10
-rw-r--r--ui-ssdiff.c145
2 files changed, 130 insertions, 25 deletions
diff --git a/cgit.css b/cgit.css
index 3f37165..9e6d2a4 100644
--- a/cgit.css
+++ b/cgit.css
@@ -1,692 +1,702 @@
1body, table, form { 1body, table, form {
2 padding: 0em; 2 padding: 0em;
3 margin: 0em; 3 margin: 0em;
4} 4}
5 5
6body { 6body {
7 font-family: sans-serif; 7 font-family: sans-serif;
8 font-size: 10pt; 8 font-size: 10pt;
9 color: #333; 9 color: #333;
10 background: white; 10 background: white;
11 padding: 4px; 11 padding: 4px;
12} 12}
13 13
14a { 14a {
15 color: blue; 15 color: blue;
16 text-decoration: none; 16 text-decoration: none;
17} 17}
18 18
19a:hover { 19a:hover {
20 text-decoration: underline; 20 text-decoration: underline;
21} 21}
22 22
23table { 23table {
24 border-collapse: collapse; 24 border-collapse: collapse;
25} 25}
26 26
27table#header { 27table#header {
28 width: 100%; 28 width: 100%;
29 margin-bottom: 1em; 29 margin-bottom: 1em;
30} 30}
31 31
32table#header td.logo { 32table#header td.logo {
33 width: 96px; 33 width: 96px;
34} 34}
35 35
36table#header td.main { 36table#header td.main {
37 font-size: 250%; 37 font-size: 250%;
38 padding-left: 10px; 38 padding-left: 10px;
39 white-space: nowrap; 39 white-space: nowrap;
40} 40}
41 41
42table#header td.main a { 42table#header td.main a {
43 color: #000; 43 color: #000;
44} 44}
45 45
46table#header td.form { 46table#header td.form {
47 text-align: right; 47 text-align: right;
48 vertical-align: bottom; 48 vertical-align: bottom;
49 padding-right: 1em; 49 padding-right: 1em;
50 padding-bottom: 2px; 50 padding-bottom: 2px;
51 white-space: nowrap; 51 white-space: nowrap;
52} 52}
53 53
54table#header td.form form, 54table#header td.form form,
55table#header td.form input, 55table#header td.form input,
56table#header td.form select { 56table#header td.form select {
57 font-size: 90%; 57 font-size: 90%;
58} 58}
59 59
60table#header td.sub { 60table#header td.sub {
61 color: #777; 61 color: #777;
62 border-top: solid 1px #ccc; 62 border-top: solid 1px #ccc;
63 padding-left: 10px; 63 padding-left: 10px;
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 /* border-bottom: solid 2px #ccc; */
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
71 width: 100%; 71 width: 100%;
72} 72}
73 73
74table.tabs td { 74table.tabs td {
75 padding: 0px 1em; 75 padding: 0px 1em;
76 vertical-align: bottom; 76 vertical-align: bottom;
77} 77}
78 78
79table.tabs td a { 79table.tabs td a {
80 padding: 2px 0.75em; 80 padding: 2px 0.75em;
81 color: #777; 81 color: #777;
82 font-size: 110%; 82 font-size: 110%;
83} 83}
84 84
85table.tabs td a.active { 85table.tabs td a.active {
86 color: #000; 86 color: #000;
87 background-color: #ccc; 87 background-color: #ccc;
88} 88}
89 89
90table.tabs td.form { 90table.tabs td.form {
91 text-align: right; 91 text-align: right;
92} 92}
93 93
94table.tabs td.form form { 94table.tabs td.form form {
95 padding-bottom: 2px; 95 padding-bottom: 2px;
96 font-size: 90%; 96 font-size: 90%;
97 white-space: nowrap; 97 white-space: nowrap;
98} 98}
99 99
100table.tabs td.form input, 100table.tabs td.form input,
101table.tabs td.form select { 101table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.content { 105div.content {
106 margin: 0px; 106 margin: 0px;
107 padding: 2em; 107 padding: 2em;
108 border-top: solid 3px #ccc; 108 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 109 border-bottom: solid 3px #ccc;
110} 110}
111 111
112 112
113table.list { 113table.list {
114 width: 100%; 114 width: 100%;
115 border: none; 115 border: none;
116 border-collapse: collapse; 116 border-collapse: collapse;
117} 117}
118 118
119table.list tr { 119table.list tr {
120 background: white; 120 background: white;
121} 121}
122 122
123table.list tr.logheader { 123table.list tr.logheader {
124 background: #eee; 124 background: #eee;
125} 125}
126 126
127table.list tr:hover { 127table.list tr:hover {
128 background: #eee; 128 background: #eee;
129} 129}
130 130
131table.list tr.nohover:hover { 131table.list tr.nohover:hover {
132 background: white; 132 background: white;
133} 133}
134 134
135table.list th { 135table.list th {
136 font-weight: bold; 136 font-weight: bold;
137 /* color: #888; 137 /* color: #888;
138 border-top: dashed 1px #888; 138 border-top: dashed 1px #888;
139 border-bottom: dashed 1px #888; 139 border-bottom: dashed 1px #888;
140 */ 140 */
141 padding: 0.1em 0.5em 0.05em 0.5em; 141 padding: 0.1em 0.5em 0.05em 0.5em;
142 vertical-align: baseline; 142 vertical-align: baseline;
143} 143}
144 144
145table.list td { 145table.list td {
146 border: none; 146 border: none;
147 padding: 0.1em 0.5em 0.1em 0.5em; 147 padding: 0.1em 0.5em 0.1em 0.5em;
148} 148}
149 149
150table.list td.logsubject { 150table.list td.logsubject {
151 font-family: monospace; 151 font-family: monospace;
152 font-weight: bold; 152 font-weight: bold;
153} 153}
154 154
155table.list td.logmsg { 155table.list td.logmsg {
156 font-family: monospace; 156 font-family: monospace;
157 white-space: pre; 157 white-space: pre;
158 padding: 1em 0.5em 2em 0.5em; 158 padding: 1em 0.5em 2em 0.5em;
159} 159}
160 160
161table.list td a { 161table.list td a {
162 color: black; 162 color: black;
163} 163}
164 164
165table.list td a:hover { 165table.list td a:hover {
166 color: #00f; 166 color: #00f;
167} 167}
168 168
169img { 169img {
170 border: none; 170 border: none;
171} 171}
172 172
173input#switch-btn { 173input#switch-btn {
174 margin: 2px 0px 0px 0px; 174 margin: 2px 0px 0px 0px;
175} 175}
176 176
177td#sidebar input.txt { 177td#sidebar input.txt {
178 width: 100%; 178 width: 100%;
179 margin: 2px 0px 0px 0px; 179 margin: 2px 0px 0px 0px;
180} 180}
181 181
182table#grid { 182table#grid {
183 margin: 0px; 183 margin: 0px;
184} 184}
185 185
186td#content { 186td#content {
187 vertical-align: top; 187 vertical-align: top;
188 padding: 1em 2em 1em 1em; 188 padding: 1em 2em 1em 1em;
189 border: none; 189 border: none;
190} 190}
191 191
192div#summary { 192div#summary {
193 vertical-align: top; 193 vertical-align: top;
194 margin-bottom: 1em; 194 margin-bottom: 1em;
195} 195}
196 196
197table#downloads { 197table#downloads {
198 float: right; 198 float: right;
199 border-collapse: collapse; 199 border-collapse: collapse;
200 border: solid 1px #777; 200 border: solid 1px #777;
201 margin-left: 0.5em; 201 margin-left: 0.5em;
202 margin-bottom: 0.5em; 202 margin-bottom: 0.5em;
203} 203}
204 204
205table#downloads th { 205table#downloads th {
206 background-color: #ccc; 206 background-color: #ccc;
207} 207}
208 208
209div#blob { 209div#blob {
210 border: solid 1px black; 210 border: solid 1px black;
211} 211}
212 212
213div.error { 213div.error {
214 color: red; 214 color: red;
215 font-weight: bold; 215 font-weight: bold;
216 margin: 1em 2em; 216 margin: 1em 2em;
217} 217}
218 218
219a.ls-blob, a.ls-dir, a.ls-mod { 219a.ls-blob, a.ls-dir, a.ls-mod {
220 font-family: monospace; 220 font-family: monospace;
221} 221}
222 222
223td.ls-size { 223td.ls-size {
224 text-align: right; 224 text-align: right;
225 font-family: monospace; 225 font-family: monospace;
226 width: 10em; 226 width: 10em;
227} 227}
228 228
229td.ls-mode { 229td.ls-mode {
230 font-family: monospace; 230 font-family: monospace;
231 width: 10em; 231 width: 10em;
232} 232}
233 233
234table.blob { 234table.blob {
235 margin-top: 0.5em; 235 margin-top: 0.5em;
236 border-top: solid 1px black; 236 border-top: solid 1px black;
237} 237}
238 238
239table.blob td.lines { 239table.blob td.lines {
240 margin: 0; padding: 0 0 0 0.5em; 240 margin: 0; padding: 0 0 0 0.5em;
241 vertical-align: top; 241 vertical-align: top;
242 color: black; 242 color: black;
243} 243}
244 244
245table.blob td.linenumbers { 245table.blob td.linenumbers {
246 margin: 0; padding: 0 0.5em 0 0.5em; 246 margin: 0; padding: 0 0.5em 0 0.5em;
247 vertical-align: top; 247 vertical-align: top;
248 text-align: right; 248 text-align: right;
249 border-right: 1px solid gray; 249 border-right: 1px solid gray;
250} 250}
251 251
252table.blob pre { 252table.blob pre {
253 padding: 0; margin: 0; 253 padding: 0; margin: 0;
254} 254}
255 255
256table.blob a.no { 256table.blob a.no {
257 color: gray; 257 color: gray;
258 text-align: right; 258 text-align: right;
259 text-decoration: none; 259 text-decoration: none;
260} 260}
261 261
262table.blob a.no a:hover { 262table.blob a.no a:hover {
263 color: black; 263 color: black;
264} 264}
265 265
266table.bin-blob { 266table.bin-blob {
267 margin-top: 0.5em; 267 margin-top: 0.5em;
268 border: solid 1px black; 268 border: solid 1px black;
269} 269}
270 270
271table.bin-blob th { 271table.bin-blob th {
272 font-family: monospace; 272 font-family: monospace;
273 white-space: pre; 273 white-space: pre;
274 border: solid 1px #777; 274 border: solid 1px #777;
275 padding: 0.5em 1em; 275 padding: 0.5em 1em;
276} 276}
277 277
278table.bin-blob td { 278table.bin-blob td {
279 font-family: monospace; 279 font-family: monospace;
280 white-space: pre; 280 white-space: pre;
281 border-left: solid 1px #777; 281 border-left: solid 1px #777;
282 padding: 0em 1em; 282 padding: 0em 1em;
283} 283}
284 284
285table.nowrap td { 285table.nowrap td {
286 white-space: nowrap; 286 white-space: nowrap;
287} 287}
288 288
289table.commit-info { 289table.commit-info {
290 border-collapse: collapse; 290 border-collapse: collapse;
291 margin-top: 1.5em; 291 margin-top: 1.5em;
292} 292}
293 293
294table.commit-info th { 294table.commit-info th {
295 text-align: left; 295 text-align: left;
296 font-weight: normal; 296 font-weight: normal;
297 padding: 0.1em 1em 0.1em 0.1em; 297 padding: 0.1em 1em 0.1em 0.1em;
298 vertical-align: top; 298 vertical-align: top;
299} 299}
300 300
301table.commit-info td { 301table.commit-info td {
302 font-weight: normal; 302 font-weight: normal;
303 padding: 0.1em 1em 0.1em 0.1em; 303 padding: 0.1em 1em 0.1em 0.1em;
304} 304}
305 305
306div.commit-subject { 306div.commit-subject {
307 font-weight: bold; 307 font-weight: bold;
308 font-size: 125%; 308 font-size: 125%;
309 margin: 1.5em 0em 0.5em 0em; 309 margin: 1.5em 0em 0.5em 0em;
310 padding: 0em; 310 padding: 0em;
311} 311}
312 312
313div.commit-msg { 313div.commit-msg {
314 white-space: pre; 314 white-space: pre;
315 font-family: monospace; 315 font-family: monospace;
316} 316}
317 317
318div.diffstat-header { 318div.diffstat-header {
319 font-weight: bold; 319 font-weight: bold;
320 padding-top: 1.5em; 320 padding-top: 1.5em;
321} 321}
322 322
323table.diffstat { 323table.diffstat {
324 border-collapse: collapse; 324 border-collapse: collapse;
325 border: solid 1px #aaa; 325 border: solid 1px #aaa;
326 background-color: #eee; 326 background-color: #eee;
327} 327}
328 328
329table.diffstat th { 329table.diffstat th {
330 font-weight: normal; 330 font-weight: normal;
331 text-align: left; 331 text-align: left;
332 text-decoration: underline; 332 text-decoration: underline;
333 padding: 0.1em 1em 0.1em 0.1em; 333 padding: 0.1em 1em 0.1em 0.1em;
334 font-size: 100%; 334 font-size: 100%;
335} 335}
336 336
337table.diffstat td { 337table.diffstat td {
338 padding: 0.2em 0.2em 0.1em 0.1em; 338 padding: 0.2em 0.2em 0.1em 0.1em;
339 font-size: 100%; 339 font-size: 100%;
340 border: none; 340 border: none;
341} 341}
342 342
343table.diffstat td.mode { 343table.diffstat td.mode {
344 white-space: nowrap; 344 white-space: nowrap;
345} 345}
346 346
347table.diffstat td span.modechange { 347table.diffstat td span.modechange {
348 padding-left: 1em; 348 padding-left: 1em;
349 color: red; 349 color: red;
350} 350}
351 351
352table.diffstat td.add a { 352table.diffstat td.add a {
353 color: green; 353 color: green;
354} 354}
355 355
356table.diffstat td.del a { 356table.diffstat td.del a {
357 color: red; 357 color: red;
358} 358}
359 359
360table.diffstat td.upd a { 360table.diffstat td.upd a {
361 color: blue; 361 color: blue;
362} 362}
363 363
364table.diffstat td.graph { 364table.diffstat td.graph {
365 width: 500px; 365 width: 500px;
366 vertical-align: middle; 366 vertical-align: middle;
367} 367}
368 368
369table.diffstat td.graph table { 369table.diffstat td.graph table {
370 border: none; 370 border: none;
371} 371}
372 372
373table.diffstat td.graph td { 373table.diffstat td.graph td {
374 padding: 0px; 374 padding: 0px;
375 border: 0px; 375 border: 0px;
376 height: 7pt; 376 height: 7pt;
377} 377}
378 378
379table.diffstat td.graph td.add { 379table.diffstat td.graph td.add {
380 background-color: #5c5; 380 background-color: #5c5;
381} 381}
382 382
383table.diffstat td.graph td.rem { 383table.diffstat td.graph td.rem {
384 background-color: #c55; 384 background-color: #c55;
385} 385}
386 386
387div.diffstat-summary { 387div.diffstat-summary {
388 color: #888; 388 color: #888;
389 padding-top: 0.5em; 389 padding-top: 0.5em;
390} 390}
391 391
392table.diff { 392table.diff {
393 width: 100%; 393 width: 100%;
394} 394}
395 395
396table.diff td { 396table.diff td {
397 font-family: monospace; 397 font-family: monospace;
398 white-space: pre; 398 white-space: pre;
399} 399}
400 400
401table.diff td div.head { 401table.diff td div.head {
402 font-weight: bold; 402 font-weight: bold;
403 margin-top: 1em; 403 margin-top: 1em;
404 color: black; 404 color: black;
405} 405}
406 406
407table.diff td div.hunk { 407table.diff td div.hunk {
408 color: #009; 408 color: #009;
409} 409}
410 410
411table.diff td div.add { 411table.diff td div.add {
412 color: green; 412 color: green;
413} 413}
414 414
415table.diff td div.del { 415table.diff td div.del {
416 color: red; 416 color: red;
417} 417}
418 418
419.sha1 { 419.sha1 {
420 font-family: monospace; 420 font-family: monospace;
421 font-size: 90%; 421 font-size: 90%;
422} 422}
423 423
424.left { 424.left {
425 text-align: left; 425 text-align: left;
426} 426}
427 427
428.right { 428.right {
429 text-align: right; 429 text-align: right;
430} 430}
431 431
432table.list td.reposection { 432table.list td.reposection {
433 font-style: italic; 433 font-style: italic;
434 color: #888; 434 color: #888;
435} 435}
436 436
437a.button { 437a.button {
438 font-size: 80%; 438 font-size: 80%;
439 padding: 0em 0.5em; 439 padding: 0em 0.5em;
440} 440}
441 441
442a.primary { 442a.primary {
443 font-size: 100%; 443 font-size: 100%;
444} 444}
445 445
446a.secondary { 446a.secondary {
447 font-size: 90%; 447 font-size: 90%;
448} 448}
449 449
450td.toplevel-repo { 450td.toplevel-repo {
451 451
452} 452}
453 453
454table.list td.sublevel-repo { 454table.list td.sublevel-repo {
455 padding-left: 1.5em; 455 padding-left: 1.5em;
456} 456}
457 457
458div.pager { 458div.pager {
459 text-align: center; 459 text-align: center;
460 margin: 1em 0em 0em 0em; 460 margin: 1em 0em 0em 0em;
461} 461}
462 462
463div.pager a { 463div.pager a {
464 color: #777; 464 color: #777;
465 margin: 0em 0.5em; 465 margin: 0em 0.5em;
466} 466}
467 467
468span.age-mins { 468span.age-mins {
469 font-weight: bold; 469 font-weight: bold;
470 color: #080; 470 color: #080;
471} 471}
472 472
473span.age-hours { 473span.age-hours {
474 color: #080; 474 color: #080;
475} 475}
476 476
477span.age-days { 477span.age-days {
478 color: #040; 478 color: #040;
479} 479}
480 480
481span.age-weeks { 481span.age-weeks {
482 color: #444; 482 color: #444;
483} 483}
484 484
485span.age-months { 485span.age-months {
486 color: #888; 486 color: #888;
487} 487}
488 488
489span.age-years { 489span.age-years {
490 color: #bbb; 490 color: #bbb;
491} 491}
492div.footer { 492div.footer {
493 margin-top: 0.5em; 493 margin-top: 0.5em;
494 text-align: center; 494 text-align: center;
495 font-size: 80%; 495 font-size: 80%;
496 color: #ccc; 496 color: #ccc;
497} 497}
498a.branch-deco { 498a.branch-deco {
499 margin: 0px 0.5em; 499 margin: 0px 0.5em;
500 padding: 0px 0.25em; 500 padding: 0px 0.25em;
501 background-color: #88ff88; 501 background-color: #88ff88;
502 border: solid 1px #007700; 502 border: solid 1px #007700;
503} 503}
504a.tag-deco { 504a.tag-deco {
505 margin: 0px 0.5em; 505 margin: 0px 0.5em;
506 padding: 0px 0.25em; 506 padding: 0px 0.25em;
507 background-color: #ffff88; 507 background-color: #ffff88;
508 border: solid 1px #777700; 508 border: solid 1px #777700;
509} 509}
510a.remote-deco { 510a.remote-deco {
511 margin: 0px 0.5em; 511 margin: 0px 0.5em;
512 padding: 0px 0.25em; 512 padding: 0px 0.25em;
513 background-color: #ccccff; 513 background-color: #ccccff;
514 border: solid 1px #000077; 514 border: solid 1px #000077;
515} 515}
516a.deco { 516a.deco {
517 margin: 0px 0.5em; 517 margin: 0px 0.5em;
518 padding: 0px 0.25em; 518 padding: 0px 0.25em;
519 background-color: #ff8888; 519 background-color: #ff8888;
520 border: solid 1px #770000; 520 border: solid 1px #770000;
521} 521}
522 522
523div.commit-subject a { 523div.commit-subject a {
524 margin-left: 1em; 524 margin-left: 1em;
525 font-size: 75%; 525 font-size: 75%;
526} 526}
527 527
528table.stats { 528table.stats {
529 border: solid 1px black; 529 border: solid 1px black;
530 border-collapse: collapse; 530 border-collapse: collapse;
531} 531}
532 532
533table.stats th { 533table.stats th {
534 text-align: left; 534 text-align: left;
535 padding: 1px 0.5em; 535 padding: 1px 0.5em;
536 background-color: #eee; 536 background-color: #eee;
537 border: solid 1px black; 537 border: solid 1px black;
538} 538}
539 539
540table.stats td { 540table.stats td {
541 text-align: right; 541 text-align: right;
542 padding: 1px 0.5em; 542 padding: 1px 0.5em;
543 border: solid 1px black; 543 border: solid 1px black;
544} 544}
545 545
546table.stats td.total { 546table.stats td.total {
547 font-weight: bold; 547 font-weight: bold;
548 text-align: left; 548 text-align: left;
549} 549}
550 550
551table.stats td.sum { 551table.stats td.sum {
552 color: #c00; 552 color: #c00;
553 font-weight: bold; 553 font-weight: bold;
554 /*background-color: #eee; */ 554 /*background-color: #eee; */
555} 555}
556 556
557table.stats td.left { 557table.stats td.left {
558 text-align: left; 558 text-align: left;
559} 559}
560 560
561table.vgraph { 561table.vgraph {
562 border-collapse: separate; 562 border-collapse: separate;
563 border: solid 1px black; 563 border: solid 1px black;
564 height: 200px; 564 height: 200px;
565} 565}
566 566
567table.vgraph th { 567table.vgraph th {
568 background-color: #eee; 568 background-color: #eee;
569 font-weight: bold; 569 font-weight: bold;
570 border: solid 1px white; 570 border: solid 1px white;
571 padding: 1px 0.5em; 571 padding: 1px 0.5em;
572} 572}
573 573
574table.vgraph td { 574table.vgraph td {
575 vertical-align: bottom; 575 vertical-align: bottom;
576 padding: 0px 10px; 576 padding: 0px 10px;
577} 577}
578 578
579table.vgraph div.bar { 579table.vgraph div.bar {
580 background-color: #eee; 580 background-color: #eee;
581} 581}
582 582
583table.hgraph { 583table.hgraph {
584 border: solid 1px black; 584 border: solid 1px black;
585 width: 800px; 585 width: 800px;
586} 586}
587 587
588table.hgraph th { 588table.hgraph th {
589 background-color: #eee; 589 background-color: #eee;
590 font-weight: bold; 590 font-weight: bold;
591 border: solid 1px black; 591 border: solid 1px black;
592 padding: 1px 0.5em; 592 padding: 1px 0.5em;
593} 593}
594 594
595table.hgraph td { 595table.hgraph td {
596 vertical-align: center; 596 vertical-align: center;
597 padding: 2px 2px; 597 padding: 2px 2px;
598} 598}
599 599
600table.hgraph div.bar { 600table.hgraph div.bar {
601 background-color: #eee; 601 background-color: #eee;
602 height: 1em; 602 height: 1em;
603} 603}
604 604
605table.ssdiff { 605table.ssdiff {
606 width: 100%; 606 width: 100%;
607} 607}
608 608
609table.ssdiff td { 609table.ssdiff td {
610 font-size: 75%; 610 font-size: 75%;
611 font-family: monospace; 611 font-family: monospace;
612 white-space: pre; 612 white-space: pre;
613 padding: 1px 4px 1px 4px; 613 padding: 1px 4px 1px 4px;
614 border-left: solid 1px #aaa; 614 border-left: solid 1px #aaa;
615 border-right: solid 1px #aaa; 615 border-right: solid 1px #aaa;
616} 616}
617 617
618table.ssdiff td.add { 618table.ssdiff td.add {
619 color: black; 619 color: black;
620 background: #cfc; 620 background: #cfc;
621 min-width: 50%; 621 min-width: 50%;
622} 622}
623 623
624table.ssdiff td.add_dark { 624table.ssdiff td.add_dark {
625 color: black; 625 color: black;
626 background: #aca; 626 background: #aca;
627 min-width: 50%; 627 min-width: 50%;
628} 628}
629 629
630table.ssdiff span.add {
631 background: #cfc;
632 font-weight: bold;
633}
634
630table.ssdiff td.del { 635table.ssdiff td.del {
631 color: black; 636 color: black;
632 background: #fcc; 637 background: #fcc;
633 min-width: 50%; 638 min-width: 50%;
634} 639}
635 640
636table.ssdiff td.del_dark { 641table.ssdiff td.del_dark {
637 color: black; 642 color: black;
638 background: #caa; 643 background: #caa;
639 min-width: 50%; 644 min-width: 50%;
640} 645}
641 646
647table.ssdiff span.del {
648 background: #fcc;
649 font-weight: bold;
650}
651
642table.ssdiff td.changed { 652table.ssdiff td.changed {
643 color: black; 653 color: black;
644 background: #ffc; 654 background: #ffc;
645 min-width: 50%; 655 min-width: 50%;
646} 656}
647 657
648table.ssdiff td.changed_dark { 658table.ssdiff td.changed_dark {
649 color: black; 659 color: black;
650 background: #cca; 660 background: #cca;
651 min-width: 50%; 661 min-width: 50%;
652} 662}
653 663
654table.ssdiff td.lineno { 664table.ssdiff td.lineno {
655 color: black; 665 color: black;
656 background: #eee; 666 background: #eee;
657 text-align: right; 667 text-align: right;
658 width: 3em; 668 width: 3em;
659 min-width: 3em; 669 min-width: 3em;
660} 670}
661 671
662table.ssdiff td.hunk { 672table.ssdiff td.hunk {
663 color: #black; 673 color: #black;
664 background: #ccf; 674 background: #ccf;
665 border-top: solid 1px #aaa; 675 border-top: solid 1px #aaa;
666 border-bottom: solid 1px #aaa; 676 border-bottom: solid 1px #aaa;
667} 677}
668 678
669table.ssdiff td.head { 679table.ssdiff td.head {
670 border-top: solid 1px #aaa; 680 border-top: solid 1px #aaa;
671 border-bottom: solid 1px #aaa; 681 border-bottom: solid 1px #aaa;
672} 682}
673 683
674table.ssdiff td.head div.head { 684table.ssdiff td.head div.head {
675 font-weight: bold; 685 font-weight: bold;
676 color: black; 686 color: black;
677} 687}
678 688
679table.ssdiff td.foot { 689table.ssdiff td.foot {
680 border-top: solid 1px #aaa; 690 border-top: solid 1px #aaa;
681 border-left: none; 691 border-left: none;
682 border-right: none; 692 border-right: none;
683 border-bottom: none; 693 border-bottom: none;
684} 694}
685 695
686table.ssdiff td.space { 696table.ssdiff td.space {
687 border: none; 697 border: none;
688} 698}
689 699
690table.ssdiff td.space div { 700table.ssdiff td.space div {
691 min-height: 3em; 701 min-height: 3em;
692} \ No newline at end of file 702} \ No newline at end of file
diff --git a/ui-ssdiff.c b/ui-ssdiff.c
index 5673642..408e620 100644
--- a/ui-ssdiff.c
+++ b/ui-ssdiff.c
@@ -1,274 +1,369 @@
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 4
5extern int use_ssdiff; 5extern int use_ssdiff;
6 6
7static int current_old_line, current_new_line; 7static int current_old_line, current_new_line;
8 8
9struct deferred_lines { 9struct deferred_lines {
10 int line_no; 10 int line_no;
11 char *line; 11 char *line;
12 struct deferred_lines *next; 12 struct deferred_lines *next;
13}; 13};
14 14
15static struct deferred_lines *deferred_old, *deferred_old_last; 15static struct deferred_lines *deferred_old, *deferred_old_last;
16static struct deferred_lines *deferred_new, *deferred_new_last; 16static struct deferred_lines *deferred_new, *deferred_new_last;
17 17
18static char *longest_common_subsequence(char *A, char *B)
19{
20 int i, j, ri;
21 int m = strlen(A);
22 int n = strlen(B);
23 int L[m + 1][n + 1];
24 int tmp1, tmp2;
25 int lcs_length;
26 char *result;
27
28 for (i = m; i >= 0; i--) {
29 for (j = n; j >= 0; j--) {
30 if (A[i] == '\0' || B[j] == '\0') {
31 L[i][j] = 0;
32 } else if (A[i] == B[j]) {
33 L[i][j] = 1 + L[i + 1][j + 1];
34 } else {
35 tmp1 = L[i + 1][j];
36 tmp2 = L[i][j + 1];
37 L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2);
38 }
39 }
40 }
41
42 lcs_length = L[0][0];
43 result = xmalloc(lcs_length + 2);
44 memset(result, 0, sizeof(*result) * (lcs_length + 2));
45
46 ri = 0;
47 i = 0;
48 j = 0;
49 while (i < m && j < n) {
50 if (A[i] == B[j]) {
51 result[ri] = A[i];
52 ri += 1;
53 i += 1;
54 j += 1;
55 } else if (L[i + 1][j] >= L[i][j + 1]) {
56 i += 1;
57 } else {
58 j += 1;
59 }
60 }
61 return result;
62}
63
18static int line_from_hunk(char *line, char type) 64static int line_from_hunk(char *line, char type)
19{ 65{
20 char *buf1, *buf2; 66 char *buf1, *buf2;
21 int len; 67 int len;
22 68
23 buf1 = strchr(line, type); 69 buf1 = strchr(line, type);
24 if (buf1 == NULL) 70 if (buf1 == NULL)
25 return 0; 71 return 0;
26 buf1 += 1; 72 buf1 += 1;
27 buf2 = strchr(buf1, ','); 73 buf2 = strchr(buf1, ',');
28 if (buf2 == NULL) 74 if (buf2 == NULL)
29 return 0; 75 return 0;
30 len = buf2 - buf1; 76 len = buf2 - buf1;
31 buf2 = xmalloc(len + 1); 77 buf2 = xmalloc(len + 1);
32 strncpy(buf2, buf1, len); 78 strncpy(buf2, buf1, len);
33 buf2[len] = '\0'; 79 buf2[len] = '\0';
34 int res = atoi(buf2); 80 int res = atoi(buf2);
35 free(buf2); 81 free(buf2);
36 return res; 82 return res;
37} 83}
38 84
39static char *replace_tabs(char *line) 85static char *replace_tabs(char *line)
40{ 86{
41 char *prev_buf = line; 87 char *prev_buf = line;
42 char *cur_buf; 88 char *cur_buf;
43 int linelen = strlen(line); 89 int linelen = strlen(line);
44 int n_tabs = 0; 90 int n_tabs = 0;
45 int i; 91 int i;
46 char *result; 92 char *result;
47 char *spaces = " "; 93 char *spaces = " ";
48 94
49 if (linelen == 0) { 95 if (linelen == 0) {
50 result = xmalloc(1); 96 result = xmalloc(1);
51 result[0] = '\0'; 97 result[0] = '\0';
52 return result; 98 return result;
53 } 99 }
54 100
55 for (i = 0; i < linelen; i++) 101 for (i = 0; i < linelen; i++)
56 if (line[i] == '\t') 102 if (line[i] == '\t')
57 n_tabs += 1; 103 n_tabs += 1;
58 result = xmalloc(linelen + n_tabs * 8 + 1); 104 result = xmalloc(linelen + n_tabs * 8 + 1);
59 result[0] = '\0'; 105 result[0] = '\0';
60 106
61 while (1) { 107 while (1) {
62 cur_buf = strchr(prev_buf, '\t'); 108 cur_buf = strchr(prev_buf, '\t');
63 if (!cur_buf) { 109 if (!cur_buf) {
64 strcat(result, prev_buf); 110 strcat(result, prev_buf);
65 break; 111 break;
66 } else { 112 } else {
67 strcat(result, " "); 113 strcat(result, " ");
68 strncat(result, spaces, 8 - (strlen(result) % 8)); 114 strncat(result, spaces, 8 - (strlen(result) % 8));
69 strncat(result, prev_buf, cur_buf - prev_buf); 115 strncat(result, prev_buf, cur_buf - prev_buf);
70 } 116 }
71 prev_buf = cur_buf + 1; 117 prev_buf = cur_buf + 1;
72 } 118 }
73 return result; 119 return result;
74} 120}
75 121
122static int calc_deferred_lines(struct deferred_lines *start)
123{
124 struct deferred_lines *item = start;
125 int result = 0;
126 while (item) {
127 result += 1;
128 item = item->next;
129 }
130 return result;
131}
132
76static void deferred_old_add(char *line, int line_no) 133static void deferred_old_add(char *line, int line_no)
77{ 134{
78 struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); 135 struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
79 item->line = xstrdup(line); 136 item->line = xstrdup(line);
80 item->line_no = line_no; 137 item->line_no = line_no;
81 item->next = NULL; 138 item->next = NULL;
82 if (deferred_old) { 139 if (deferred_old) {
83 deferred_old_last->next = item; 140 deferred_old_last->next = item;
84 deferred_old_last = item; 141 deferred_old_last = item;
85 } else { 142 } else {
86 deferred_old = deferred_old_last = item; 143 deferred_old = deferred_old_last = item;
87 } 144 }
88} 145}
89 146
90static void deferred_new_add(char *line, int line_no) 147static void deferred_new_add(char *line, int line_no)
91{ 148{
92 struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); 149 struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines));
93 item->line = xstrdup(line); 150 item->line = xstrdup(line);
94 item->line_no = line_no; 151 item->line_no = line_no;
95 item->next = NULL; 152 item->next = NULL;
96 if (deferred_new) { 153 if (deferred_new) {
97 deferred_new_last->next = item; 154 deferred_new_last->next = item;
98 deferred_new_last = item; 155 deferred_new_last = item;
99 } else { 156 } else {
100 deferred_new = deferred_new_last = item; 157 deferred_new = deferred_new_last = item;
101 } 158 }
102} 159}
103 160
104static void print_ssdiff_line(char *class, int old_line_no, char *old_line, 161static void print_part_with_lcs(char *class, char *line, char *lcs)
105 int new_line_no, char *new_line) 162{
163 int line_len = strlen(line);
164 int i, j;
165 char c[2] = " ";
166 int same = 1;
167
168 j = 0;
169 for (i = 0; i < line_len; i++) {
170 c[0] = line[i];
171 if (same) {
172 if (line[i] == lcs[j])
173 j += 1;
174 else {
175 same = 0;
176 htmlf("<span class='%s'>", class);
177 }
178 } else if (line[i] == lcs[j]) {
179 same = 1;
180 htmlf("</span>");
181 j += 1;
182 }
183 html_txt(c);
184 }
185}
186
187static void print_ssdiff_line(char *class,
188 int old_line_no,
189 char *old_line,
190 int new_line_no,
191 char *new_line, int individual_chars)
106{ 192{
193 char *lcs = NULL;
194 if (old_line)
195 old_line = replace_tabs(old_line + 1);
196 if (new_line)
197 new_line = replace_tabs(new_line + 1);
198 if (individual_chars && old_line && new_line)
199 lcs = longest_common_subsequence(old_line, new_line);
107 html("<tr>"); 200 html("<tr>");
108 if (old_line_no > 0) 201 if (old_line_no > 0)
109 htmlf("<td class='lineno'>%d</td><td class='%s'>", 202 htmlf("<td class='lineno'>%d</td><td class='%s'>",
110 old_line_no, class); 203 old_line_no, class);
111 else if (old_line) 204 else if (old_line)
112 htmlf("<td class='lineno'></td><td class='%s'>", class); 205 htmlf("<td class='lineno'></td><td class='%s'>", class);
113 else 206 else
114 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 207 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
115
116 if (old_line) { 208 if (old_line) {
117 old_line = replace_tabs(old_line + 1); 209 if (lcs)
118 html_txt(old_line); 210 print_part_with_lcs("del", old_line, lcs);
119 free(old_line); 211 else
212 html_txt(old_line);
120 } 213 }
121 214
122 html("</td>"); 215 html("</td>");
123
124 if (new_line_no > 0) 216 if (new_line_no > 0)
125 htmlf("<td class='lineno'>%d</td><td class='%s'>", 217 htmlf("<td class='lineno'>%d</td><td class='%s'>",
126 new_line_no, class); 218 new_line_no, class);
127 else if (new_line) 219 else if (new_line)
128 htmlf("<td class='lineno'></td><td class='%s'>", class); 220 htmlf("<td class='lineno'></td><td class='%s'>", class);
129 else 221 else
130 htmlf("<td class='lineno'></td><td class='%s_dark'>", class); 222 htmlf("<td class='lineno'></td><td class='%s_dark'>", class);
131
132 if (new_line) { 223 if (new_line) {
133 new_line = replace_tabs(new_line + 1); 224 if (lcs)
134 html_txt(new_line); 225 print_part_with_lcs("add", new_line, lcs);
135 free(new_line); 226 else
227 html_txt(new_line);
136 } 228 }
137 229
138 html("</td></tr>"); 230 html("</td></tr>");
231 if (lcs)
232 free(lcs);
233 if (new_line)
234 free(new_line);
235 if (old_line)
236 free(old_line);
139} 237}
140 238
141static void print_deferred_old_lines() 239static void print_deferred_old_lines()
142{ 240{
143 struct deferred_lines *iter_old, *tmp; 241 struct deferred_lines *iter_old, *tmp;
144
145 iter_old = deferred_old; 242 iter_old = deferred_old;
146 while (iter_old) { 243 while (iter_old) {
147 print_ssdiff_line("del", iter_old->line_no, 244 print_ssdiff_line("del", iter_old->line_no,
148 iter_old->line, -1, NULL); 245 iter_old->line, -1, NULL, 0);
149 tmp = iter_old->next; 246 tmp = iter_old->next;
150 free(iter_old); 247 free(iter_old);
151 iter_old = tmp; 248 iter_old = tmp;
152 } 249 }
153} 250}
154 251
155static void print_deferred_new_lines() 252static void print_deferred_new_lines()
156{ 253{
157 struct deferred_lines *iter_new, *tmp; 254 struct deferred_lines *iter_new, *tmp;
158
159 iter_new = deferred_new; 255 iter_new = deferred_new;
160 while (iter_new) { 256 while (iter_new) {
161 print_ssdiff_line("add", -1, NULL, iter_new->line_no, 257 print_ssdiff_line("add", -1, NULL,
162 iter_new->line); 258 iter_new->line_no, iter_new->line, 0);
163 tmp = iter_new->next; 259 tmp = iter_new->next;
164 free(iter_new); 260 free(iter_new);
165 iter_new = tmp; 261 iter_new = tmp;
166 } 262 }
167} 263}
168 264
169static void print_deferred_changed_lines() 265static void print_deferred_changed_lines()
170{ 266{
171 struct deferred_lines *iter_old, *iter_new, *tmp; 267 struct deferred_lines *iter_old, *iter_new, *tmp;
268 int n_old_lines = calc_deferred_lines(deferred_old);
269 int n_new_lines = calc_deferred_lines(deferred_new);
270 int individual_chars = (n_old_lines == n_new_lines ? 1 : 0);
172 271
173 iter_old = deferred_old; 272 iter_old = deferred_old;
174 iter_new = deferred_new; 273 iter_new = deferred_new;
175 while (iter_old || iter_new) { 274 while (iter_old || iter_new) {
176 if (iter_old && iter_new) 275 if (iter_old && iter_new)
177 print_ssdiff_line("changed", iter_old->line_no, 276 print_ssdiff_line("changed", iter_old->line_no,
178 iter_old->line, 277 iter_old->line,
179 iter_new->line_no, iter_new->line); 278 iter_new->line_no, iter_new->line,
279 individual_chars);
180 else if (iter_old) 280 else if (iter_old)
181 print_ssdiff_line("changed", iter_old->line_no, 281 print_ssdiff_line("changed", iter_old->line_no,
182 iter_old->line, -1, NULL); 282 iter_old->line, -1, NULL, 0);
183 else if (iter_new) 283 else if (iter_new)
184 print_ssdiff_line("changed", -1, NULL, 284 print_ssdiff_line("changed", -1, NULL,
185 iter_new->line_no, iter_new->line); 285 iter_new->line_no, iter_new->line, 0);
186
187 if (iter_old) { 286 if (iter_old) {
188 tmp = iter_old->next; 287 tmp = iter_old->next;
189 free(iter_old); 288 free(iter_old);
190 iter_old = tmp; 289 iter_old = tmp;
191 } 290 }
192 291
193 if (iter_new) { 292 if (iter_new) {
194 tmp = iter_new->next; 293 tmp = iter_new->next;
195 free(iter_new); 294 free(iter_new);
196 iter_new = tmp; 295 iter_new = tmp;
197 } 296 }
198 } 297 }
199} 298}
200 299
201void cgit_ssdiff_print_deferred_lines() 300void cgit_ssdiff_print_deferred_lines()
202{ 301{
203 if (!deferred_old && !deferred_new) 302 if (!deferred_old && !deferred_new)
204 return; 303 return;
205
206 if (deferred_old && !deferred_new) 304 if (deferred_old && !deferred_new)
207 print_deferred_old_lines(); 305 print_deferred_old_lines();
208 else if (!deferred_old && deferred_new) 306 else if (!deferred_old && deferred_new)
209 print_deferred_new_lines(); 307 print_deferred_new_lines();
210 else 308 else
211 print_deferred_changed_lines(); 309 print_deferred_changed_lines();
212
213 deferred_old = deferred_old_last = NULL; 310 deferred_old = deferred_old_last = NULL;
214 deferred_new = deferred_new_last = NULL; 311 deferred_new = deferred_new_last = NULL;
215} 312}
216 313
217/* 314/*
218 * print a single line returned from xdiff 315 * print a single line returned from xdiff
219 */ 316 */
220void cgit_ssdiff_line_cb(char *line, int len) 317void cgit_ssdiff_line_cb(char *line, int len)
221{ 318{
222 char c = line[len - 1]; 319 char c = line[len - 1];
223
224 line[len - 1] = '\0'; 320 line[len - 1] = '\0';
225
226 if (line[0] == '@') { 321 if (line[0] == '@') {
227 current_old_line = line_from_hunk(line, '-'); 322 current_old_line = line_from_hunk(line, '-');
228 current_new_line = line_from_hunk(line, '+'); 323 current_new_line = line_from_hunk(line, '+');
229 } 324 }
230 325
231 if (line[0] == ' ') { 326 if (line[0] == ' ') {
232 if (deferred_old || deferred_new) 327 if (deferred_old || deferred_new)
233 cgit_ssdiff_print_deferred_lines(); 328 cgit_ssdiff_print_deferred_lines();
234 print_ssdiff_line("ctx", current_old_line, line, 329 print_ssdiff_line("ctx", current_old_line, line,
235 current_new_line, line); 330 current_new_line, line, 0);
236 current_old_line += 1; 331 current_old_line += 1;
237 current_new_line += 1; 332 current_new_line += 1;
238 } else if (line[0] == '+') { 333 } else if (line[0] == '+') {
239 deferred_new_add(line, current_new_line); 334 deferred_new_add(line, current_new_line);
240 current_new_line += 1; 335 current_new_line += 1;
241 } else if (line[0] == '-') { 336 } else if (line[0] == '-') {
242 deferred_old_add(line, current_old_line); 337 deferred_old_add(line, current_old_line);
243 current_old_line += 1; 338 current_old_line += 1;
244 } else if (line[0] == '@') { 339 } else if (line[0] == '@') {
245 html("<tr><td colspan='4' class='hunk'>"); 340 html("<tr><td colspan='4' class='hunk'>");
246 html_txt(line); 341 html_txt(line);
247 html("</td></tr>"); 342 html("</td></tr>");
248 } else { 343 } else {
249 html("<tr><td colspan='4' class='ctx'>"); 344 html("<tr><td colspan='4' class='ctx'>");
250 html_txt(line); 345 html_txt(line);
251 html("</td></tr>"); 346 html("</td></tr>");
252 } 347 }
253 line[len - 1] = c; 348 line[len - 1] = c;
254} 349}
255 350
256void cgit_ssdiff_header_begin() 351void cgit_ssdiff_header_begin()
257{ 352{
258 current_old_line = -1; 353 current_old_line = -1;
259 current_new_line = -1; 354 current_new_line = -1;
260 html("<tr><td class='space' colspan='4'><div></div></td></tr>"); 355 html("<tr><td class='space' colspan='4'><div></div></td></tr>");
261 html("<tr><td class='head' colspan='4'>"); 356 html("<tr><td class='head' colspan='4'>");
262} 357}
263 358
264void cgit_ssdiff_header_end() 359void cgit_ssdiff_header_end()
265{ 360{
266 html("</td><tr>"); 361 html("</td><tr>");
267} 362}
268 363
269void cgit_ssdiff_footer() 364void cgit_ssdiff_footer()
270{ 365{
271 if (deferred_old || deferred_new) 366 if (deferred_old || deferred_new)
272 cgit_ssdiff_print_deferred_lines(); 367 cgit_ssdiff_print_deferred_lines();
273 html("<tr><td class='foot' colspan='4'></td></tr>"); 368 html("<tr><td class='foot' colspan='4'></td></tr>");
274} 369}