Fossil SCM

Merge the retro-sbsdiff changes into trunk.

drh 2012-02-04 21:09 trunk merge
Commit 72c0183ac898fab980ba501134139119e964ef09
+225 -265
--- src/diff.c
+++ src/diff.c
@@ -25,15 +25,18 @@
2525
2626
#if INTERFACE
2727
/*
2828
** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
2929
*/
30
-#define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31
-#define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32
-#define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33
-#define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34
-#define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
30
+#define DIFF_CONTEXT_MASK 0x0000ffff /* Lines of context. Default if 0 */
31
+#define DIFF_WIDTH_MASK 0x00ff0000 /* side-by-side column width */
32
+#define DIFF_IGNORE_EOLWS 0x01000000 /* Ignore end-of-line whitespace */
33
+#define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */
34
+#define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */
35
+#define DIFF_INLINE 0x08000000 /* Inline (not side-by-side) diff */
36
+#define DIFF_HTML 0x10000000 /* Render for HTML */
37
+#define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */
3538
3639
#endif /* INTERFACE */
3740
3841
/*
3942
** Maximum length of a line in a text file. (8192)
@@ -146,15 +149,49 @@
146149
}
147150
148151
/*
149152
** Append a single line of "diff" output to pOut.
150153
*/
151
-static void appendDiffLine(Blob *pOut, char *zPrefix, DLine *pLine){
152
- blob_append(pOut, zPrefix, 1);
153
- blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
154
+static void appendDiffLine(Blob *pOut, char cPrefix, DLine *pLine, int html){
155
+ blob_append(pOut, &cPrefix, 1);
156
+ if( html ){
157
+ char *zHtml;
158
+ if( cPrefix=='+' ){
159
+ blob_append(pOut, "<span class=\"diffadd\">", -1);
160
+ }else if( cPrefix=='-' ){
161
+ blob_append(pOut, "<span class=\"diffrm\">", -1);
162
+ }
163
+ zHtml = htmlize(pLine->z, (pLine->h & LENGTH_MASK));
164
+ blob_append(pOut, zHtml, -1);
165
+ fossil_free(zHtml);
166
+ if( cPrefix!=' ' ){
167
+ blob_append(pOut, "</span>", -1);
168
+ }
169
+ }else{
170
+ blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
171
+ }
154172
blob_append(pOut, "\n", 1);
155173
}
174
+
175
+/*
176
+** Append line numbers to the context diff output. Zero or negative numbers
177
+** are blanks.
178
+*/
179
+static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){
180
+ if( html ) blob_append(pOut, "<span class=\"diffln\">", -1);
181
+ if( lnA>0 ){
182
+ blob_appendf(pOut, "%6d ", lnA);
183
+ }else{
184
+ blob_append(pOut, " ", 7);
185
+ }
186
+ if( lnB>0 ){
187
+ blob_appendf(pOut, "%6d ", lnB);
188
+ }else{
189
+ blob_append(pOut, " ", 8);
190
+ }
191
+ if( html ) blob_append(pOut, "</span>", -1);
192
+}
156193
157194
/*
158195
** Expand the size of aEdit[] array to hold nEdit elements.
159196
*/
160197
static void expandEdit(DContext *p, int nEdit){
@@ -198,11 +235,17 @@
198235
199236
/*
200237
** Given a diff context in which the aEdit[] array has been filled
201238
** in, compute a context diff into pOut.
202239
*/
203
-static void contextDiff(DContext *p, Blob *pOut, int nContext){
240
+static void contextDiff(
241
+ DContext *p, /* The difference */
242
+ Blob *pOut, /* Output a context diff to here */
243
+ int nContext, /* Number of lines of context */
244
+ int showLn, /* Show line numbers */
245
+ int html /* Render as HTML */
246
+){
204247
DLine *A; /* Left side of the diff */
205248
DLine *B; /* Right side of the diff */
206249
int a = 0; /* Index of next line in A[] */
207250
int b = 0; /* Index of next line in B[] */
208251
int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -252,40 +295,57 @@
252295
/*
253296
* If the patch changes an empty file or results in an empty file,
254297
* the block header must use 0,0 as position indicator and not 1,0.
255298
* Otherwise, patch would be confused and may reject the diff.
256299
*/
257
- blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n",
258
- na ? a+skip+1 : 0, na,
259
- nb ? b+skip+1 : 0, nb);
300
+ if( showLn ){
301
+ if( r==0 ){
302
+ /* Do not show a top divider */
303
+ }else if( html ){
304
+ blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
305
+ }else{
306
+ blob_appendf(pOut, "%.80c\n", '.');
307
+ }
308
+ }else{
309
+ if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
310
+ blob_appendf(pOut,"@@ -%d,%d +%d,%d @@",
311
+ na ? a+skip+1 : 0, na,
312
+ nb ? b+skip+1 : 0, nb);
313
+ if( html ) blob_appendf(pOut, "</span>");
314
+ blob_append(pOut, "\n", 1);
315
+ }
260316
261317
/* Show the initial common area */
262318
a += skip;
263319
b += skip;
264320
m = R[r] - skip;
265321
for(j=0; j<m; j++){
266
- appendDiffLine(pOut, " ", &A[a+j]);
322
+ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
323
+ appendDiffLine(pOut, ' ', &A[a+j], html);
267324
}
268325
a += m;
269326
b += m;
270327
271328
/* Show the differences */
272329
for(i=0; i<nr; i++){
273330
m = R[r+i*3+1];
274331
for(j=0; j<m; j++){
275
- appendDiffLine(pOut, "-", &A[a+j]);
332
+ if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
333
+ appendDiffLine(pOut, '-', &A[a+j], html);
276334
}
277335
a += m;
278336
m = R[r+i*3+2];
279337
for(j=0; j<m; j++){
280
- appendDiffLine(pOut, "+", &B[b+j]);
338
+ if( showLn ) appendDiffLineno(pOut, 0, b+j+1, html);
339
+ appendDiffLine(pOut, '+', &B[b+j], html);
281340
}
282341
b += m;
283342
if( i<nr-1 ){
284343
m = R[r+i*3+3];
285344
for(j=0; j<m; j++){
286
- appendDiffLine(pOut, " ", &B[b+j]);
345
+ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
346
+ appendDiffLine(pOut, ' ', &B[b+j], html);
287347
}
288348
b += m;
289349
a += m;
290350
}
291351
}
@@ -293,57 +353,124 @@
293353
/* Show the final common area */
294354
assert( nr==i );
295355
m = R[r+nr*3];
296356
if( m>nContext ) m = nContext;
297357
for(j=0; j<m; j++){
298
- appendDiffLine(pOut, " ", &B[b+j]);
358
+ if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
359
+ appendDiffLine(pOut, ' ', &B[b+j], html);
299360
}
300361
}
301362
}
302363
303364
/*
304
-** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305
-** have space for at least 7 characters.
365
+** Status of a single output line
366
+*/
367
+typedef struct SbsLine SbsLine;
368
+struct SbsLine {
369
+ char *zLine; /* The output line under construction */
370
+ int n; /* Index of next unused slot in the zLine[] */
371
+ int width; /* Maximum width of a column in the output */
372
+ unsigned char escHtml; /* True to escape html characters */
373
+};
374
+
375
+/*
376
+** Flags for sbsWriteText()
306377
*/
307
-static void sbsWriteLineno(char *z, int ln){
308
- sqlite3_snprintf(7, z, "%6d", ln+1);
309
- z[6] = ' ';
310
-}
378
+#define SBS_NEWLINE 0x0001 /* End with \n\000 */
379
+#define SBS_PAD 0x0002 /* Pad output to width spaces */
380
+#define SBS_ENDSPAN 0x0004 /* Write a </span> after text */
311381
312382
/*
313383
** Write up to width characters of pLine into z[]. Translate tabs into
314
-** spaces. If trunc is true, then append \n\000 after the last character
315
-** written.
384
+** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters
385
+** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set.
316386
*/
317
-static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
387
+static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
318388
int n = pLine->h & LENGTH_MASK;
319389
int i, j;
320390
const char *zIn = pLine->z;
321
- for(i=j=0; i<n && j<width; i++){
391
+ char *z = &p->zLine[p->n];
392
+ int w = p->width;
393
+ if( n>w ) n = w;
394
+ for(i=j=0; i<n; i++){
322395
char c = zIn[i];
323396
if( c=='\t' ){
324397
z[j++] = ' ';
325
- while( (j&7)!=0 && j<width ) z[j++] = ' ';
398
+ while( (j&7)!=0 && j<n ) z[j++] = ' ';
326399
}else if( c=='\r' || c=='\f' ){
327400
z[j++] = ' ';
401
+ }else if( c=='<' && p->escHtml ){
402
+ memcpy(&z[j], "&lt;", 4);
403
+ j += 4;
404
+ }else if( c=='&' && p->escHtml ){
405
+ memcpy(&z[j], "&amp;", 5);
406
+ j += 5;
407
+ }else if( c=='>' && p->escHtml ){
408
+ memcpy(&z[j], "&gt;", 4);
409
+ j += 4;
328410
}else{
329411
z[j++] = c;
330412
}
331413
}
332
- if( trunc ){
414
+ if( (flags & SBS_ENDSPAN) && p->escHtml ){
415
+ memcpy(&z[j], "</span>", 7);
416
+ j += 7;
417
+ }
418
+ if( (flags & SBS_PAD)!=0 ){
419
+ while( i<w ){ i++; z[j++] = ' '; }
420
+ }
421
+ if( flags & SBS_NEWLINE ){
333422
z[j++] = '\n';
334
- z[j] = 0;
335423
}
336
- return j;
424
+ p->n += j;
425
+}
426
+
427
+/*
428
+** Append a string to an SbSLine with coding, interpretation, or padding.
429
+*/
430
+static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
431
+ memcpy(p->zLine+p->n, zIn, nIn);
432
+ p->n += nIn;
433
+}
434
+
435
+/*
436
+** Append n spaces to the string.
437
+*/
438
+static void sbsWriteSpace(SbsLine *p, int n){
439
+ while( n-- ) p->zLine[p->n++] = ' ';
440
+}
441
+
442
+/*
443
+** Append a string to the output only if we are rendering HTML.
444
+*/
445
+static void sbsWriteHtml(SbsLine *p, const char *zIn){
446
+ if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
447
+}
448
+
449
+/*
450
+** Write a 6-digit line number followed by a single space onto the line.
451
+*/
452
+static void sbsWriteLineno(SbsLine *p, int ln){
453
+ sbsWriteHtml(p, "<span class=\"diffln\">");
454
+ sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
455
+ p->n += 6;
456
+ sbsWriteHtml(p, "</span>");
457
+ p->zLine[p->n++] = ' ';
337458
}
338459
339460
340461
/*
341462
** Given a diff context in which the aEdit[] array has been filled
342463
** in, compute a side-by-side diff into pOut.
343464
*/
344
-static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
465
+static void sbsDiff(
466
+ DContext *p, /* The computed diff */
467
+ Blob *pOut, /* Write the results here */
468
+ int nContext, /* Number of lines of context around each change */
469
+ int width, /* Width of each column of output */
470
+ int escHtml /* True to generate HTML output */
471
+){
345472
DLine *A; /* Left side of the diff */
346473
DLine *B; /* Right side of the diff */
347474
int a = 0; /* Index of next line in A[] */
348475
int b = 0; /* Index of next line in B[] */
349476
int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -352,18 +479,16 @@
352479
int mxr; /* Maximum value for r */
353480
int na, nb; /* Number of lines shown from A and B */
354481
int i, j; /* Loop counters */
355482
int m, ma, mb;/* Number of lines to output */
356483
int skip; /* Number of lines to skip */
357
- int mxLine; /* Length of a line of text */
358
- char *zLine; /* A line of text being formatted */
359
- int len; /* Length of an output line */
360
-
361
- mxLine = width*2 + 2*7 + 3 + 1;
362
- zLine = fossil_malloc( mxLine + 1 );
363
- if( zLine==0 ) return;
364
- zLine[mxLine] = 0;
484
+ SbsLine s; /* Output line buffer */
485
+
486
+ s.zLine = fossil_malloc( 10*width + 100 );
487
+ if( s.zLine==0 ) return;
488
+ s.width = width;
489
+ s.escHtml = escHtml;
365490
A = p->aFrom;
366491
B = p->aTo;
367492
R = p->aEdit;
368493
mxr = p->nEdit;
369494
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -400,23 +525,31 @@
400525
/*
401526
* If the patch changes an empty file or results in an empty file,
402527
* the block header must use 0,0 as position indicator and not 1,0.
403528
* Otherwise, patch would be confused and may reject the diff.
404529
*/
405
- if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');
530
+ if( r>0 ){
531
+ if( escHtml ){
532
+ blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
533
+ width*2+16, '.');
534
+ }else{
535
+ blob_appendf(pOut, "%.*c\n", width*2+16, '.');
536
+ }
537
+ }
406538
407539
/* Show the initial common area */
408540
a += skip;
409541
b += skip;
410542
m = R[r] - skip;
411543
for(j=0; j<m; j++){
412
- memset(zLine, ' ', mxLine);
413
- sbsWriteLineno(zLine, a+j);
414
- sbsWriteText(&zLine[7], &A[a+j], width, 0);
415
- sbsWriteLineno(&zLine[width+10], b+j);
416
- len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
417
- blob_append(pOut, zLine, len+width+17);
544
+ s.n = 0;
545
+ sbsWriteLineno(&s, a+j);
546
+ sbsWriteText(&s, &A[a+j], SBS_PAD);
547
+ sbsWrite(&s, " ", 3);
548
+ sbsWriteLineno(&s, b+j);
549
+ sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
550
+ blob_append(pOut, s.zLine, s.n);
418551
}
419552
a += m;
420553
b += m;
421554
422555
/* Show the differences */
@@ -423,49 +556,53 @@
423556
for(i=0; i<nr; i++){
424557
ma = R[r+i*3+1];
425558
mb = R[r+i*3+2];
426559
m = ma<mb ? ma : mb;
427560
for(j=0; j<m; j++){
428
- memset(zLine, ' ', mxLine);
429
- sbsWriteLineno(zLine, a+j);
430
- sbsWriteText(&zLine[7], &A[a+j], width, 0);
431
- zLine[width+8] = '|';
432
- sbsWriteLineno(&zLine[width+10], b+j);
433
- len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
434
- blob_append(pOut, zLine, len+width+17);
561
+ s.n = 0;
562
+ sbsWriteLineno(&s, a+j);
563
+ sbsWriteHtml(&s, "<span class=\"diffchng\">");
564
+ sbsWriteText(&s, &A[a+j], SBS_PAD | SBS_ENDSPAN);
565
+ sbsWrite(&s, " | ", 3);
566
+ sbsWriteLineno(&s, b+j);
567
+ sbsWriteHtml(&s, "<span class=\"diffchng\">");
568
+ sbsWriteText(&s, &B[b+j], SBS_NEWLINE | SBS_ENDSPAN);
569
+ blob_append(pOut, s.zLine, s.n);
435570
}
436571
a += m;
437572
b += m;
438573
ma -= m;
439574
mb -= m;
440575
for(j=0; j<ma; j++){
441
- memset(zLine, ' ', width+7);
442
- sbsWriteLineno(zLine, a+j);
443
- sbsWriteText(&zLine[7], &A[a+j], width, 0);
444
- zLine[width+8] = '<';
445
- zLine[width+9] = '\n';
446
- zLine[width+10] = 0;
447
- blob_append(pOut, zLine, width+10);
576
+ s.n = 0;
577
+ sbsWriteLineno(&s, a+j);
578
+ sbsWriteHtml(&s, "<span class=\"diffrm\">");
579
+ sbsWriteText(&s, &A[a+j], SBS_PAD | SBS_ENDSPAN);
580
+ sbsWrite(&s, " <\n", 3);
581
+ blob_append(pOut, s.zLine, s.n);
448582
}
449583
a += ma;
450584
for(j=0; j<mb; j++){
451
- memset(zLine, ' ', mxLine);
452
- zLine[width+8] = '>';
453
- sbsWriteLineno(&zLine[width+10], b+j);
454
- len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
455
- blob_append(pOut, zLine, len+width+17);
585
+ s.n = 0;
586
+ sbsWriteSpace(&s, width + 7);
587
+ sbsWrite(&s, " > ", 3);
588
+ sbsWriteLineno(&s, b+j);
589
+ sbsWriteHtml(&s, "<span class=\"diffadd\">");
590
+ sbsWriteText(&s, &B[b+j], SBS_NEWLINE | SBS_ENDSPAN);
591
+ blob_append(pOut, s.zLine, s.n);
456592
}
457593
b += mb;
458594
if( i<nr-1 ){
459595
m = R[r+i*3+3];
460596
for(j=0; j<m; j++){
461
- memset(zLine, ' ', mxLine);
462
- sbsWriteLineno(zLine, a+j);
463
- sbsWriteText(&zLine[7], &A[a+j], width, 0);
464
- sbsWriteLineno(&zLine[width+10], b+j);
465
- len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
466
- blob_append(pOut, zLine, len+width+17);
597
+ s.n = 0;
598
+ sbsWriteLineno(&s, a+j);
599
+ sbsWriteText(&s, &A[a+j], SBS_PAD);
600
+ sbsWrite(&s, " ", 3);
601
+ sbsWriteLineno(&s, b+j);
602
+ sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
603
+ blob_append(pOut, s.zLine, s.n);
467604
}
468605
b += m;
469606
a += m;
470607
}
471608
}
@@ -473,19 +610,20 @@
473610
/* Show the final common area */
474611
assert( nr==i );
475612
m = R[r+nr*3];
476613
if( m>nContext ) m = nContext;
477614
for(j=0; j<m; j++){
478
- memset(zLine, ' ', mxLine);
479
- sbsWriteLineno(zLine, a+j);
480
- sbsWriteText(&zLine[7], &A[a+j], width, 0);
481
- sbsWriteLineno(&zLine[width+10], b+j);
482
- len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
483
- blob_append(pOut, zLine, len+width+17);
615
+ s.n = 0;
616
+ sbsWriteLineno(&s, a+j);
617
+ sbsWriteText(&s, &A[a+j], SBS_PAD);
618
+ sbsWrite(&s, " ", 3);
619
+ sbsWriteLineno(&s, b+j);
620
+ sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
621
+ blob_append(pOut, s.zLine, s.n);
484622
}
485623
}
486
- free(zLine);
624
+ free(s.zLine);
487625
}
488626
489627
/*
490628
** Compute the optimal longest common subsequence (LCS) using an
491629
** exhaustive search. This version of the LCS is only used for
@@ -786,15 +924,17 @@
786924
/* Compute the difference */
787925
diff_all(&c);
788926
789927
if( pOut ){
790928
/* Compute a context or side-by-side diff into pOut */
929
+ int escHtml = (diffFlags & DIFF_HTML)!=0;
791930
if( diffFlags & DIFF_SIDEBYSIDE ){
792931
int width = diff_width(diffFlags);
793
- sbsDiff(&c, pOut, nContext, width);
932
+ sbsDiff(&c, pOut, nContext, width, escHtml);
794933
}else{
795
- contextDiff(&c, pOut, nContext);
934
+ int showLn = (diffFlags & DIFF_LINENO)!=0;
935
+ contextDiff(&c, pOut, nContext, showLn, escHtml);
796936
}
797937
free(c.aFrom);
798938
free(c.aTo);
799939
free(c.aEdit);
800940
return 0;
@@ -805,194 +945,10 @@
805945
free(c.aFrom);
806946
free(c.aTo);
807947
return c.aEdit;
808948
}
809949
}
810
-
811
-/*
812
-** Copy a line with a limit. Used for side-by-side diffs to enforce a maximum
813
-** line length limit.
814
-*/
815
-static char *copylimline(char *out, DLine *dl, int lim){
816
- int len;
817
- len = dl->h & LENGTH_MASK;
818
- if( lim && len > lim ){
819
- memcpy(out, dl->z, lim-3);
820
- memcpy(&out[lim-3], "...", 4);
821
- }else{
822
- memcpy(out, dl->z, len);
823
- out[len] = '\0';
824
- }
825
- return out;
826
-}
827
-
828
-/*
829
-** Output table body of a side-by-side diff. Prior to the call, the caller
830
-** should have output:
831
-** <table class="sbsdiff">
832
-** <tr><th colspan="2" class="diffhdr">Old title</th><th/>
833
-** <th colspan="2" class="diffhdr">New title</th></tr>
834
-**
835
-** And after the call, it should output:
836
-** </table>
837
-**
838
-** Some good reference diffs in the fossil repository for testing:
839
-** /vdiff?from=080d27a&to=4b0f813&detail=1
840
-** /vdiff?from=636804745b&to=c1d78e0556&detail=1
841
-** /vdiff?from=c0b6c28d29&to=25169506b7&detail=1
842
-** /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1
843
-*/
844
-int html_sbsdiff(
845
- Blob *pA_Blob, /* FROM file */
846
- Blob *pB_Blob, /* TO file */
847
- int nContext, /* Amount of context to unified diff */
848
- int ignoreEolWs /* Ignore whitespace at the end of lines */
849
-){
850
- DContext c;
851
- int i;
852
- int iFrom, iTo;
853
- char *linebuf;
854
- int collim=0; /* Currently not settable; allows a column limit for diffs */
855
- int allowExp=0; /* Currently not settable; (dis)allow expansion of rows */
856
-
857
- /* Prepare the input files */
858
- memset(&c, 0, sizeof(c));
859
- c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
860
- &c.nFrom, ignoreEolWs);
861
- c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
862
- &c.nTo, ignoreEolWs);
863
- if( c.aFrom==0 || c.aTo==0 ){
864
- free(c.aFrom);
865
- free(c.aTo);
866
- /* Note: This would be generated within a table. */
867
- @ <p class="generalError" style="white-space: nowrap">cannot compute
868
- @ difference between binary files</p>
869
- return 0;
870
- }
871
-
872
- collim = collim < 4 ? 0 : collim;
873
-
874
- /* Compute the difference */
875
- diff_all(&c);
876
-
877
- linebuf = fossil_malloc(LENGTH_MASK+1);
878
- if( !linebuf ){
879
- free(c.aFrom);
880
- free(c.aTo);
881
- free(c.aEdit);
882
- return 0;
883
- }
884
-
885
- iFrom=iTo=0;
886
- i=0;
887
- while( i<c.nEdit ){
888
- int j;
889
- /* Copied lines */
890
- for( j=0; j<c.aEdit[i]; j++){
891
- /* Hide lines which are copied and are further away from block boundaries
892
- ** than nContext lines. For each block with hidden lines, show a row
893
- ** notifying the user about the hidden rows.
894
- */
895
- if( j<nContext || j>c.aEdit[i]-nContext-1 ){
896
- @ <tr>
897
- }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
898
- @ <tr>
899
- @ <td class="meta" colspan="5" style="white-space: nowrap;">
900
- @ %d(c.aEdit[i]-2*nContext) hidden lines</td>
901
- @ </tr>
902
- if( !allowExp )
903
- continue;
904
- @ <tr style="display:none;">
905
- }else{
906
- if( !allowExp )
907
- continue;
908
- @ <tr style="display:none;">
909
- }
910
-
911
- copylimline(linebuf, &c.aFrom[iFrom+j], collim);
912
- @ <td class="lineno">%d(iFrom+j+1)</td>
913
- @ <td class="srcline">%h(linebuf)</td>
914
-
915
- @ <td> </td>
916
-
917
- copylimline(linebuf, &c.aTo[iTo+j], collim);
918
- @ <td class="lineno">%d(iTo+j+1)</td>
919
- @ <td class="srcline">%h(linebuf)</td>
920
-
921
- @ </tr>
922
- }
923
- iFrom+=c.aEdit[i];
924
- iTo+=c.aEdit[i];
925
-
926
- if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){
927
- int lim;
928
- lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2];
929
-
930
- /* Assume changed lines */
931
- for( j=0; j<lim; j++ ){
932
- @ <tr>
933
-
934
- if( j<c.aEdit[i+1] ){
935
- copylimline(linebuf, &c.aFrom[iFrom+j], collim);
936
- @ <td class="changed lineno">%d(iFrom+j+1)</td>
937
- @ <td class="changed srcline">%h(linebuf)</td>
938
- }else{
939
- @ <td colspan="2" class="changedvoid"/>
940
- }
941
-
942
- @ <td class="changed">|</td>
943
-
944
- if( j<c.aEdit[i+2] ){
945
- copylimline(linebuf, &c.aTo[iTo+j], collim);
946
- @ <td class="changed lineno">%d(iTo+j+1)</td>
947
- @ <td class="changed srcline">%h(linebuf)</td>
948
- }else{
949
- @ <td colspan="2" class="changedvoid"/>
950
- }
951
-
952
- @ </tr>
953
- }
954
- iFrom+=c.aEdit[i+1];
955
- iTo+=c.aEdit[i+2];
956
- }else{
957
-
958
- /* Process deleted lines */
959
- for( j=0; j<c.aEdit[i+1]; j++ ){
960
- @ <tr>
961
-
962
- copylimline(linebuf, &c.aFrom[iFrom+j], collim);
963
- @ <td class="removed lineno">%d(iFrom+j+1)</td>
964
- @ <td class="removed srcline">%h(linebuf)</td>
965
- @ <td>&lt;</td>
966
- @ <td colspan="2" class="removedvoid"/>
967
- @ </tr>
968
- }
969
- iFrom+=c.aEdit[i+1];
970
-
971
- /* Process inserted lines */
972
- for( j=0; j<c.aEdit[i+2]; j++ ){
973
- @ <tr>
974
- @ <td colspan="2" class="addedvoid"/>
975
- @ <td>&gt;</td>
976
- copylimline(linebuf, &c.aTo[iTo+j], collim);
977
- @ <td class="added lineno">%d(iTo+j+1)</td>
978
- @ <td class="added srcline">%h(linebuf)</td>
979
- @ </tr>
980
- }
981
- iTo+=c.aEdit[i+2];
982
- }
983
-
984
- i+=3;
985
- }
986
-
987
- free(linebuf);
988
- free(c.aFrom);
989
- free(c.aTo);
990
- free(c.aEdit);
991
- return 1;
992
-}
993
-
994950
995951
/*
996952
** COMMAND: test-rawdiff
997953
*/
998954
void test_rawdiff_cmd(void){
@@ -1019,10 +975,12 @@
1019975
** "diffFlags" integer.
1020976
**
1021977
** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
1022978
** --context|-c N N lines of context. DIFF_CONTEXT_MASK
1023979
** --width|-W N N character lines. DIFF_WIDTH_MASK
980
+** --html Format for HTML DIFF_HTML
981
+** --linenum|-n Show line numbers DIFF_LINENO
1024982
*/
1025983
int diff_options(void){
1026984
int diffFlags = 0;
1027985
const char *z;
1028986
int f;
@@ -1034,10 +992,12 @@
1034992
if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
1035993
f *= DIFF_CONTEXT_MASK+1;
1036994
if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
1037995
diffFlags |= f;
1038996
}
997
+ if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;
998
+ if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
1039999
return diffFlags;
10401000
}
10411001
10421002
/*
10431003
** COMMAND: test-udiff
10441004
--- src/diff.c
+++ src/diff.c
@@ -25,15 +25,18 @@
25
26 #if INTERFACE
27 /*
28 ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29 */
30 #define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */
31 #define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */
32 #define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */
33 #define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */
34 #define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */
 
 
 
35
36 #endif /* INTERFACE */
37
38 /*
39 ** Maximum length of a line in a text file. (8192)
@@ -146,15 +149,49 @@
146 }
147
148 /*
149 ** Append a single line of "diff" output to pOut.
150 */
151 static void appendDiffLine(Blob *pOut, char *zPrefix, DLine *pLine){
152 blob_append(pOut, zPrefix, 1);
153 blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154 blob_append(pOut, "\n", 1);
155 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
157 /*
158 ** Expand the size of aEdit[] array to hold nEdit elements.
159 */
160 static void expandEdit(DContext *p, int nEdit){
@@ -198,11 +235,17 @@
198
199 /*
200 ** Given a diff context in which the aEdit[] array has been filled
201 ** in, compute a context diff into pOut.
202 */
203 static void contextDiff(DContext *p, Blob *pOut, int nContext){
 
 
 
 
 
 
204 DLine *A; /* Left side of the diff */
205 DLine *B; /* Right side of the diff */
206 int a = 0; /* Index of next line in A[] */
207 int b = 0; /* Index of next line in B[] */
208 int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -252,40 +295,57 @@
252 /*
253 * If the patch changes an empty file or results in an empty file,
254 * the block header must use 0,0 as position indicator and not 1,0.
255 * Otherwise, patch would be confused and may reject the diff.
256 */
257 blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n",
258 na ? a+skip+1 : 0, na,
259 nb ? b+skip+1 : 0, nb);
 
 
 
 
 
 
 
 
 
 
 
 
 
260
261 /* Show the initial common area */
262 a += skip;
263 b += skip;
264 m = R[r] - skip;
265 for(j=0; j<m; j++){
266 appendDiffLine(pOut, " ", &A[a+j]);
 
267 }
268 a += m;
269 b += m;
270
271 /* Show the differences */
272 for(i=0; i<nr; i++){
273 m = R[r+i*3+1];
274 for(j=0; j<m; j++){
275 appendDiffLine(pOut, "-", &A[a+j]);
 
276 }
277 a += m;
278 m = R[r+i*3+2];
279 for(j=0; j<m; j++){
280 appendDiffLine(pOut, "+", &B[b+j]);
 
281 }
282 b += m;
283 if( i<nr-1 ){
284 m = R[r+i*3+3];
285 for(j=0; j<m; j++){
286 appendDiffLine(pOut, " ", &B[b+j]);
 
287 }
288 b += m;
289 a += m;
290 }
291 }
@@ -293,57 +353,124 @@
293 /* Show the final common area */
294 assert( nr==i );
295 m = R[r+nr*3];
296 if( m>nContext ) m = nContext;
297 for(j=0; j<m; j++){
298 appendDiffLine(pOut, " ", &B[b+j]);
 
299 }
300 }
301 }
302
303 /*
304 ** Write a 6-digit line number into the buffer z[]. z[] is guaranteed to
305 ** have space for at least 7 characters.
 
 
 
 
 
 
 
 
 
 
306 */
307 static void sbsWriteLineno(char *z, int ln){
308 sqlite3_snprintf(7, z, "%6d", ln+1);
309 z[6] = ' ';
310 }
311
312 /*
313 ** Write up to width characters of pLine into z[]. Translate tabs into
314 ** spaces. If trunc is true, then append \n\000 after the last character
315 ** written.
316 */
317 static int sbsWriteText(char *z, DLine *pLine, int width, int trunc){
318 int n = pLine->h & LENGTH_MASK;
319 int i, j;
320 const char *zIn = pLine->z;
321 for(i=j=0; i<n && j<width; i++){
 
 
 
322 char c = zIn[i];
323 if( c=='\t' ){
324 z[j++] = ' ';
325 while( (j&7)!=0 && j<width ) z[j++] = ' ';
326 }else if( c=='\r' || c=='\f' ){
327 z[j++] = ' ';
 
 
 
 
 
 
 
 
 
328 }else{
329 z[j++] = c;
330 }
331 }
332 if( trunc ){
 
 
 
 
 
 
 
333 z[j++] = '\n';
334 z[j] = 0;
335 }
336 return j;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
337 }
338
339
340 /*
341 ** Given a diff context in which the aEdit[] array has been filled
342 ** in, compute a side-by-side diff into pOut.
343 */
344 static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){
 
 
 
 
 
 
345 DLine *A; /* Left side of the diff */
346 DLine *B; /* Right side of the diff */
347 int a = 0; /* Index of next line in A[] */
348 int b = 0; /* Index of next line in B[] */
349 int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -352,18 +479,16 @@
352 int mxr; /* Maximum value for r */
353 int na, nb; /* Number of lines shown from A and B */
354 int i, j; /* Loop counters */
355 int m, ma, mb;/* Number of lines to output */
356 int skip; /* Number of lines to skip */
357 int mxLine; /* Length of a line of text */
358 char *zLine; /* A line of text being formatted */
359 int len; /* Length of an output line */
360
361 mxLine = width*2 + 2*7 + 3 + 1;
362 zLine = fossil_malloc( mxLine + 1 );
363 if( zLine==0 ) return;
364 zLine[mxLine] = 0;
365 A = p->aFrom;
366 B = p->aTo;
367 R = p->aEdit;
368 mxr = p->nEdit;
369 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -400,23 +525,31 @@
400 /*
401 * If the patch changes an empty file or results in an empty file,
402 * the block header must use 0,0 as position indicator and not 1,0.
403 * Otherwise, patch would be confused and may reject the diff.
404 */
405 if( r>0 ) blob_appendf(pOut,"%.*c\n", width*2+16, '.');
 
 
 
 
 
 
 
406
407 /* Show the initial common area */
408 a += skip;
409 b += skip;
410 m = R[r] - skip;
411 for(j=0; j<m; j++){
412 memset(zLine, ' ', mxLine);
413 sbsWriteLineno(zLine, a+j);
414 sbsWriteText(&zLine[7], &A[a+j], width, 0);
415 sbsWriteLineno(&zLine[width+10], b+j);
416 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
417 blob_append(pOut, zLine, len+width+17);
 
418 }
419 a += m;
420 b += m;
421
422 /* Show the differences */
@@ -423,49 +556,53 @@
423 for(i=0; i<nr; i++){
424 ma = R[r+i*3+1];
425 mb = R[r+i*3+2];
426 m = ma<mb ? ma : mb;
427 for(j=0; j<m; j++){
428 memset(zLine, ' ', mxLine);
429 sbsWriteLineno(zLine, a+j);
430 sbsWriteText(&zLine[7], &A[a+j], width, 0);
431 zLine[width+8] = '|';
432 sbsWriteLineno(&zLine[width+10], b+j);
433 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
434 blob_append(pOut, zLine, len+width+17);
 
 
435 }
436 a += m;
437 b += m;
438 ma -= m;
439 mb -= m;
440 for(j=0; j<ma; j++){
441 memset(zLine, ' ', width+7);
442 sbsWriteLineno(zLine, a+j);
443 sbsWriteText(&zLine[7], &A[a+j], width, 0);
444 zLine[width+8] = '<';
445 zLine[width+9] = '\n';
446 zLine[width+10] = 0;
447 blob_append(pOut, zLine, width+10);
448 }
449 a += ma;
450 for(j=0; j<mb; j++){
451 memset(zLine, ' ', mxLine);
452 zLine[width+8] = '>';
453 sbsWriteLineno(&zLine[width+10], b+j);
454 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
455 blob_append(pOut, zLine, len+width+17);
 
 
456 }
457 b += mb;
458 if( i<nr-1 ){
459 m = R[r+i*3+3];
460 for(j=0; j<m; j++){
461 memset(zLine, ' ', mxLine);
462 sbsWriteLineno(zLine, a+j);
463 sbsWriteText(&zLine[7], &A[a+j], width, 0);
464 sbsWriteLineno(&zLine[width+10], b+j);
465 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
466 blob_append(pOut, zLine, len+width+17);
 
467 }
468 b += m;
469 a += m;
470 }
471 }
@@ -473,19 +610,20 @@
473 /* Show the final common area */
474 assert( nr==i );
475 m = R[r+nr*3];
476 if( m>nContext ) m = nContext;
477 for(j=0; j<m; j++){
478 memset(zLine, ' ', mxLine);
479 sbsWriteLineno(zLine, a+j);
480 sbsWriteText(&zLine[7], &A[a+j], width, 0);
481 sbsWriteLineno(&zLine[width+10], b+j);
482 len = sbsWriteText(&zLine[width+17], &B[b+j], width, 1);
483 blob_append(pOut, zLine, len+width+17);
 
484 }
485 }
486 free(zLine);
487 }
488
489 /*
490 ** Compute the optimal longest common subsequence (LCS) using an
491 ** exhaustive search. This version of the LCS is only used for
@@ -786,15 +924,17 @@
786 /* Compute the difference */
787 diff_all(&c);
788
789 if( pOut ){
790 /* Compute a context or side-by-side diff into pOut */
 
791 if( diffFlags & DIFF_SIDEBYSIDE ){
792 int width = diff_width(diffFlags);
793 sbsDiff(&c, pOut, nContext, width);
794 }else{
795 contextDiff(&c, pOut, nContext);
 
796 }
797 free(c.aFrom);
798 free(c.aTo);
799 free(c.aEdit);
800 return 0;
@@ -805,194 +945,10 @@
805 free(c.aFrom);
806 free(c.aTo);
807 return c.aEdit;
808 }
809 }
810
811 /*
812 ** Copy a line with a limit. Used for side-by-side diffs to enforce a maximum
813 ** line length limit.
814 */
815 static char *copylimline(char *out, DLine *dl, int lim){
816 int len;
817 len = dl->h & LENGTH_MASK;
818 if( lim && len > lim ){
819 memcpy(out, dl->z, lim-3);
820 memcpy(&out[lim-3], "...", 4);
821 }else{
822 memcpy(out, dl->z, len);
823 out[len] = '\0';
824 }
825 return out;
826 }
827
828 /*
829 ** Output table body of a side-by-side diff. Prior to the call, the caller
830 ** should have output:
831 ** <table class="sbsdiff">
832 ** <tr><th colspan="2" class="diffhdr">Old title</th><th/>
833 ** <th colspan="2" class="diffhdr">New title</th></tr>
834 **
835 ** And after the call, it should output:
836 ** </table>
837 **
838 ** Some good reference diffs in the fossil repository for testing:
839 ** /vdiff?from=080d27a&to=4b0f813&detail=1
840 ** /vdiff?from=636804745b&to=c1d78e0556&detail=1
841 ** /vdiff?from=c0b6c28d29&to=25169506b7&detail=1
842 ** /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1
843 */
844 int html_sbsdiff(
845 Blob *pA_Blob, /* FROM file */
846 Blob *pB_Blob, /* TO file */
847 int nContext, /* Amount of context to unified diff */
848 int ignoreEolWs /* Ignore whitespace at the end of lines */
849 ){
850 DContext c;
851 int i;
852 int iFrom, iTo;
853 char *linebuf;
854 int collim=0; /* Currently not settable; allows a column limit for diffs */
855 int allowExp=0; /* Currently not settable; (dis)allow expansion of rows */
856
857 /* Prepare the input files */
858 memset(&c, 0, sizeof(c));
859 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
860 &c.nFrom, ignoreEolWs);
861 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
862 &c.nTo, ignoreEolWs);
863 if( c.aFrom==0 || c.aTo==0 ){
864 free(c.aFrom);
865 free(c.aTo);
866 /* Note: This would be generated within a table. */
867 @ <p class="generalError" style="white-space: nowrap">cannot compute
868 @ difference between binary files</p>
869 return 0;
870 }
871
872 collim = collim < 4 ? 0 : collim;
873
874 /* Compute the difference */
875 diff_all(&c);
876
877 linebuf = fossil_malloc(LENGTH_MASK+1);
878 if( !linebuf ){
879 free(c.aFrom);
880 free(c.aTo);
881 free(c.aEdit);
882 return 0;
883 }
884
885 iFrom=iTo=0;
886 i=0;
887 while( i<c.nEdit ){
888 int j;
889 /* Copied lines */
890 for( j=0; j<c.aEdit[i]; j++){
891 /* Hide lines which are copied and are further away from block boundaries
892 ** than nContext lines. For each block with hidden lines, show a row
893 ** notifying the user about the hidden rows.
894 */
895 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
896 @ <tr>
897 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
898 @ <tr>
899 @ <td class="meta" colspan="5" style="white-space: nowrap;">
900 @ %d(c.aEdit[i]-2*nContext) hidden lines</td>
901 @ </tr>
902 if( !allowExp )
903 continue;
904 @ <tr style="display:none;">
905 }else{
906 if( !allowExp )
907 continue;
908 @ <tr style="display:none;">
909 }
910
911 copylimline(linebuf, &c.aFrom[iFrom+j], collim);
912 @ <td class="lineno">%d(iFrom+j+1)</td>
913 @ <td class="srcline">%h(linebuf)</td>
914
915 @ <td> </td>
916
917 copylimline(linebuf, &c.aTo[iTo+j], collim);
918 @ <td class="lineno">%d(iTo+j+1)</td>
919 @ <td class="srcline">%h(linebuf)</td>
920
921 @ </tr>
922 }
923 iFrom+=c.aEdit[i];
924 iTo+=c.aEdit[i];
925
926 if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){
927 int lim;
928 lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2];
929
930 /* Assume changed lines */
931 for( j=0; j<lim; j++ ){
932 @ <tr>
933
934 if( j<c.aEdit[i+1] ){
935 copylimline(linebuf, &c.aFrom[iFrom+j], collim);
936 @ <td class="changed lineno">%d(iFrom+j+1)</td>
937 @ <td class="changed srcline">%h(linebuf)</td>
938 }else{
939 @ <td colspan="2" class="changedvoid"/>
940 }
941
942 @ <td class="changed">|</td>
943
944 if( j<c.aEdit[i+2] ){
945 copylimline(linebuf, &c.aTo[iTo+j], collim);
946 @ <td class="changed lineno">%d(iTo+j+1)</td>
947 @ <td class="changed srcline">%h(linebuf)</td>
948 }else{
949 @ <td colspan="2" class="changedvoid"/>
950 }
951
952 @ </tr>
953 }
954 iFrom+=c.aEdit[i+1];
955 iTo+=c.aEdit[i+2];
956 }else{
957
958 /* Process deleted lines */
959 for( j=0; j<c.aEdit[i+1]; j++ ){
960 @ <tr>
961
962 copylimline(linebuf, &c.aFrom[iFrom+j], collim);
963 @ <td class="removed lineno">%d(iFrom+j+1)</td>
964 @ <td class="removed srcline">%h(linebuf)</td>
965 @ <td>&lt;</td>
966 @ <td colspan="2" class="removedvoid"/>
967 @ </tr>
968 }
969 iFrom+=c.aEdit[i+1];
970
971 /* Process inserted lines */
972 for( j=0; j<c.aEdit[i+2]; j++ ){
973 @ <tr>
974 @ <td colspan="2" class="addedvoid"/>
975 @ <td>&gt;</td>
976 copylimline(linebuf, &c.aTo[iTo+j], collim);
977 @ <td class="added lineno">%d(iTo+j+1)</td>
978 @ <td class="added srcline">%h(linebuf)</td>
979 @ </tr>
980 }
981 iTo+=c.aEdit[i+2];
982 }
983
984 i+=3;
985 }
986
987 free(linebuf);
988 free(c.aFrom);
989 free(c.aTo);
990 free(c.aEdit);
991 return 1;
992 }
993
994
995 /*
996 ** COMMAND: test-rawdiff
997 */
998 void test_rawdiff_cmd(void){
@@ -1019,10 +975,12 @@
1019 ** "diffFlags" integer.
1020 **
1021 ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
1022 ** --context|-c N N lines of context. DIFF_CONTEXT_MASK
1023 ** --width|-W N N character lines. DIFF_WIDTH_MASK
 
 
1024 */
1025 int diff_options(void){
1026 int diffFlags = 0;
1027 const char *z;
1028 int f;
@@ -1034,10 +992,12 @@
1034 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
1035 f *= DIFF_CONTEXT_MASK+1;
1036 if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
1037 diffFlags |= f;
1038 }
 
 
1039 return diffFlags;
1040 }
1041
1042 /*
1043 ** COMMAND: test-udiff
1044
--- src/diff.c
+++ src/diff.c
@@ -25,15 +25,18 @@
25
26 #if INTERFACE
27 /*
28 ** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions:
29 */
30 #define DIFF_CONTEXT_MASK 0x0000ffff /* Lines of context. Default if 0 */
31 #define DIFF_WIDTH_MASK 0x00ff0000 /* side-by-side column width */
32 #define DIFF_IGNORE_EOLWS 0x01000000 /* Ignore end-of-line whitespace */
33 #define DIFF_SIDEBYSIDE 0x02000000 /* Generate a side-by-side diff */
34 #define DIFF_NEWFILE 0x04000000 /* Missing files are as empty files */
35 #define DIFF_INLINE 0x08000000 /* Inline (not side-by-side) diff */
36 #define DIFF_HTML 0x10000000 /* Render for HTML */
37 #define DIFF_LINENO 0x20000000 /* Show line numbers in context diff */
38
39 #endif /* INTERFACE */
40
41 /*
42 ** Maximum length of a line in a text file. (8192)
@@ -146,15 +149,49 @@
149 }
150
151 /*
152 ** Append a single line of "diff" output to pOut.
153 */
154 static void appendDiffLine(Blob *pOut, char cPrefix, DLine *pLine, int html){
155 blob_append(pOut, &cPrefix, 1);
156 if( html ){
157 char *zHtml;
158 if( cPrefix=='+' ){
159 blob_append(pOut, "<span class=\"diffadd\">", -1);
160 }else if( cPrefix=='-' ){
161 blob_append(pOut, "<span class=\"diffrm\">", -1);
162 }
163 zHtml = htmlize(pLine->z, (pLine->h & LENGTH_MASK));
164 blob_append(pOut, zHtml, -1);
165 fossil_free(zHtml);
166 if( cPrefix!=' ' ){
167 blob_append(pOut, "</span>", -1);
168 }
169 }else{
170 blob_append(pOut, pLine->z, pLine->h & LENGTH_MASK);
171 }
172 blob_append(pOut, "\n", 1);
173 }
174
175 /*
176 ** Append line numbers to the context diff output. Zero or negative numbers
177 ** are blanks.
178 */
179 static void appendDiffLineno(Blob *pOut, int lnA, int lnB, int html){
180 if( html ) blob_append(pOut, "<span class=\"diffln\">", -1);
181 if( lnA>0 ){
182 blob_appendf(pOut, "%6d ", lnA);
183 }else{
184 blob_append(pOut, " ", 7);
185 }
186 if( lnB>0 ){
187 blob_appendf(pOut, "%6d ", lnB);
188 }else{
189 blob_append(pOut, " ", 8);
190 }
191 if( html ) blob_append(pOut, "</span>", -1);
192 }
193
194 /*
195 ** Expand the size of aEdit[] array to hold nEdit elements.
196 */
197 static void expandEdit(DContext *p, int nEdit){
@@ -198,11 +235,17 @@
235
236 /*
237 ** Given a diff context in which the aEdit[] array has been filled
238 ** in, compute a context diff into pOut.
239 */
240 static void contextDiff(
241 DContext *p, /* The difference */
242 Blob *pOut, /* Output a context diff to here */
243 int nContext, /* Number of lines of context */
244 int showLn, /* Show line numbers */
245 int html /* Render as HTML */
246 ){
247 DLine *A; /* Left side of the diff */
248 DLine *B; /* Right side of the diff */
249 int a = 0; /* Index of next line in A[] */
250 int b = 0; /* Index of next line in B[] */
251 int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -252,40 +295,57 @@
295 /*
296 * If the patch changes an empty file or results in an empty file,
297 * the block header must use 0,0 as position indicator and not 1,0.
298 * Otherwise, patch would be confused and may reject the diff.
299 */
300 if( showLn ){
301 if( r==0 ){
302 /* Do not show a top divider */
303 }else if( html ){
304 blob_appendf(pOut, "<span class=\"diffhr\">%.80c</span>\n", '.');
305 }else{
306 blob_appendf(pOut, "%.80c\n", '.');
307 }
308 }else{
309 if( html ) blob_appendf(pOut, "<span class=\"diffln\">");
310 blob_appendf(pOut,"@@ -%d,%d +%d,%d @@",
311 na ? a+skip+1 : 0, na,
312 nb ? b+skip+1 : 0, nb);
313 if( html ) blob_appendf(pOut, "</span>");
314 blob_append(pOut, "\n", 1);
315 }
316
317 /* Show the initial common area */
318 a += skip;
319 b += skip;
320 m = R[r] - skip;
321 for(j=0; j<m; j++){
322 if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
323 appendDiffLine(pOut, ' ', &A[a+j], html);
324 }
325 a += m;
326 b += m;
327
328 /* Show the differences */
329 for(i=0; i<nr; i++){
330 m = R[r+i*3+1];
331 for(j=0; j<m; j++){
332 if( showLn ) appendDiffLineno(pOut, a+j+1, 0, html);
333 appendDiffLine(pOut, '-', &A[a+j], html);
334 }
335 a += m;
336 m = R[r+i*3+2];
337 for(j=0; j<m; j++){
338 if( showLn ) appendDiffLineno(pOut, 0, b+j+1, html);
339 appendDiffLine(pOut, '+', &B[b+j], html);
340 }
341 b += m;
342 if( i<nr-1 ){
343 m = R[r+i*3+3];
344 for(j=0; j<m; j++){
345 if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
346 appendDiffLine(pOut, ' ', &B[b+j], html);
347 }
348 b += m;
349 a += m;
350 }
351 }
@@ -293,57 +353,124 @@
353 /* Show the final common area */
354 assert( nr==i );
355 m = R[r+nr*3];
356 if( m>nContext ) m = nContext;
357 for(j=0; j<m; j++){
358 if( showLn ) appendDiffLineno(pOut, a+j+1, b+j+1, html);
359 appendDiffLine(pOut, ' ', &B[b+j], html);
360 }
361 }
362 }
363
364 /*
365 ** Status of a single output line
366 */
367 typedef struct SbsLine SbsLine;
368 struct SbsLine {
369 char *zLine; /* The output line under construction */
370 int n; /* Index of next unused slot in the zLine[] */
371 int width; /* Maximum width of a column in the output */
372 unsigned char escHtml; /* True to escape html characters */
373 };
374
375 /*
376 ** Flags for sbsWriteText()
377 */
378 #define SBS_NEWLINE 0x0001 /* End with \n\000 */
379 #define SBS_PAD 0x0002 /* Pad output to width spaces */
380 #define SBS_ENDSPAN 0x0004 /* Write a </span> after text */
 
381
382 /*
383 ** Write up to width characters of pLine into z[]. Translate tabs into
384 ** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters
385 ** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set.
386 */
387 static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
388 int n = pLine->h & LENGTH_MASK;
389 int i, j;
390 const char *zIn = pLine->z;
391 char *z = &p->zLine[p->n];
392 int w = p->width;
393 if( n>w ) n = w;
394 for(i=j=0; i<n; i++){
395 char c = zIn[i];
396 if( c=='\t' ){
397 z[j++] = ' ';
398 while( (j&7)!=0 && j<n ) z[j++] = ' ';
399 }else if( c=='\r' || c=='\f' ){
400 z[j++] = ' ';
401 }else if( c=='<' && p->escHtml ){
402 memcpy(&z[j], "&lt;", 4);
403 j += 4;
404 }else if( c=='&' && p->escHtml ){
405 memcpy(&z[j], "&amp;", 5);
406 j += 5;
407 }else if( c=='>' && p->escHtml ){
408 memcpy(&z[j], "&gt;", 4);
409 j += 4;
410 }else{
411 z[j++] = c;
412 }
413 }
414 if( (flags & SBS_ENDSPAN) && p->escHtml ){
415 memcpy(&z[j], "</span>", 7);
416 j += 7;
417 }
418 if( (flags & SBS_PAD)!=0 ){
419 while( i<w ){ i++; z[j++] = ' '; }
420 }
421 if( flags & SBS_NEWLINE ){
422 z[j++] = '\n';
 
423 }
424 p->n += j;
425 }
426
427 /*
428 ** Append a string to an SbSLine with coding, interpretation, or padding.
429 */
430 static void sbsWrite(SbsLine *p, const char *zIn, int nIn){
431 memcpy(p->zLine+p->n, zIn, nIn);
432 p->n += nIn;
433 }
434
435 /*
436 ** Append n spaces to the string.
437 */
438 static void sbsWriteSpace(SbsLine *p, int n){
439 while( n-- ) p->zLine[p->n++] = ' ';
440 }
441
442 /*
443 ** Append a string to the output only if we are rendering HTML.
444 */
445 static void sbsWriteHtml(SbsLine *p, const char *zIn){
446 if( p->escHtml ) sbsWrite(p, zIn, strlen(zIn));
447 }
448
449 /*
450 ** Write a 6-digit line number followed by a single space onto the line.
451 */
452 static void sbsWriteLineno(SbsLine *p, int ln){
453 sbsWriteHtml(p, "<span class=\"diffln\">");
454 sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
455 p->n += 6;
456 sbsWriteHtml(p, "</span>");
457 p->zLine[p->n++] = ' ';
458 }
459
460
461 /*
462 ** Given a diff context in which the aEdit[] array has been filled
463 ** in, compute a side-by-side diff into pOut.
464 */
465 static void sbsDiff(
466 DContext *p, /* The computed diff */
467 Blob *pOut, /* Write the results here */
468 int nContext, /* Number of lines of context around each change */
469 int width, /* Width of each column of output */
470 int escHtml /* True to generate HTML output */
471 ){
472 DLine *A; /* Left side of the diff */
473 DLine *B; /* Right side of the diff */
474 int a = 0; /* Index of next line in A[] */
475 int b = 0; /* Index of next line in B[] */
476 int *R; /* Array of COPY/DELETE/INSERT triples */
@@ -352,18 +479,16 @@
479 int mxr; /* Maximum value for r */
480 int na, nb; /* Number of lines shown from A and B */
481 int i, j; /* Loop counters */
482 int m, ma, mb;/* Number of lines to output */
483 int skip; /* Number of lines to skip */
484 SbsLine s; /* Output line buffer */
485
486 s.zLine = fossil_malloc( 10*width + 100 );
487 if( s.zLine==0 ) return;
488 s.width = width;
489 s.escHtml = escHtml;
 
 
490 A = p->aFrom;
491 B = p->aTo;
492 R = p->aEdit;
493 mxr = p->nEdit;
494 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -400,23 +525,31 @@
525 /*
526 * If the patch changes an empty file or results in an empty file,
527 * the block header must use 0,0 as position indicator and not 1,0.
528 * Otherwise, patch would be confused and may reject the diff.
529 */
530 if( r>0 ){
531 if( escHtml ){
532 blob_appendf(pOut, "<span class=\"diffhr\">%.*c</span>\n",
533 width*2+16, '.');
534 }else{
535 blob_appendf(pOut, "%.*c\n", width*2+16, '.');
536 }
537 }
538
539 /* Show the initial common area */
540 a += skip;
541 b += skip;
542 m = R[r] - skip;
543 for(j=0; j<m; j++){
544 s.n = 0;
545 sbsWriteLineno(&s, a+j);
546 sbsWriteText(&s, &A[a+j], SBS_PAD);
547 sbsWrite(&s, " ", 3);
548 sbsWriteLineno(&s, b+j);
549 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
550 blob_append(pOut, s.zLine, s.n);
551 }
552 a += m;
553 b += m;
554
555 /* Show the differences */
@@ -423,49 +556,53 @@
556 for(i=0; i<nr; i++){
557 ma = R[r+i*3+1];
558 mb = R[r+i*3+2];
559 m = ma<mb ? ma : mb;
560 for(j=0; j<m; j++){
561 s.n = 0;
562 sbsWriteLineno(&s, a+j);
563 sbsWriteHtml(&s, "<span class=\"diffchng\">");
564 sbsWriteText(&s, &A[a+j], SBS_PAD | SBS_ENDSPAN);
565 sbsWrite(&s, " | ", 3);
566 sbsWriteLineno(&s, b+j);
567 sbsWriteHtml(&s, "<span class=\"diffchng\">");
568 sbsWriteText(&s, &B[b+j], SBS_NEWLINE | SBS_ENDSPAN);
569 blob_append(pOut, s.zLine, s.n);
570 }
571 a += m;
572 b += m;
573 ma -= m;
574 mb -= m;
575 for(j=0; j<ma; j++){
576 s.n = 0;
577 sbsWriteLineno(&s, a+j);
578 sbsWriteHtml(&s, "<span class=\"diffrm\">");
579 sbsWriteText(&s, &A[a+j], SBS_PAD | SBS_ENDSPAN);
580 sbsWrite(&s, " <\n", 3);
581 blob_append(pOut, s.zLine, s.n);
 
582 }
583 a += ma;
584 for(j=0; j<mb; j++){
585 s.n = 0;
586 sbsWriteSpace(&s, width + 7);
587 sbsWrite(&s, " > ", 3);
588 sbsWriteLineno(&s, b+j);
589 sbsWriteHtml(&s, "<span class=\"diffadd\">");
590 sbsWriteText(&s, &B[b+j], SBS_NEWLINE | SBS_ENDSPAN);
591 blob_append(pOut, s.zLine, s.n);
592 }
593 b += mb;
594 if( i<nr-1 ){
595 m = R[r+i*3+3];
596 for(j=0; j<m; j++){
597 s.n = 0;
598 sbsWriteLineno(&s, a+j);
599 sbsWriteText(&s, &A[a+j], SBS_PAD);
600 sbsWrite(&s, " ", 3);
601 sbsWriteLineno(&s, b+j);
602 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
603 blob_append(pOut, s.zLine, s.n);
604 }
605 b += m;
606 a += m;
607 }
608 }
@@ -473,19 +610,20 @@
610 /* Show the final common area */
611 assert( nr==i );
612 m = R[r+nr*3];
613 if( m>nContext ) m = nContext;
614 for(j=0; j<m; j++){
615 s.n = 0;
616 sbsWriteLineno(&s, a+j);
617 sbsWriteText(&s, &A[a+j], SBS_PAD);
618 sbsWrite(&s, " ", 3);
619 sbsWriteLineno(&s, b+j);
620 sbsWriteText(&s, &B[b+j], SBS_NEWLINE);
621 blob_append(pOut, s.zLine, s.n);
622 }
623 }
624 free(s.zLine);
625 }
626
627 /*
628 ** Compute the optimal longest common subsequence (LCS) using an
629 ** exhaustive search. This version of the LCS is only used for
@@ -786,15 +924,17 @@
924 /* Compute the difference */
925 diff_all(&c);
926
927 if( pOut ){
928 /* Compute a context or side-by-side diff into pOut */
929 int escHtml = (diffFlags & DIFF_HTML)!=0;
930 if( diffFlags & DIFF_SIDEBYSIDE ){
931 int width = diff_width(diffFlags);
932 sbsDiff(&c, pOut, nContext, width, escHtml);
933 }else{
934 int showLn = (diffFlags & DIFF_LINENO)!=0;
935 contextDiff(&c, pOut, nContext, showLn, escHtml);
936 }
937 free(c.aFrom);
938 free(c.aTo);
939 free(c.aEdit);
940 return 0;
@@ -805,194 +945,10 @@
945 free(c.aFrom);
946 free(c.aTo);
947 return c.aEdit;
948 }
949 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
950
951 /*
952 ** COMMAND: test-rawdiff
953 */
954 void test_rawdiff_cmd(void){
@@ -1019,10 +975,12 @@
975 ** "diffFlags" integer.
976 **
977 ** --side-by-side|-y Side-by-side diff. DIFF_SIDEBYSIDE
978 ** --context|-c N N lines of context. DIFF_CONTEXT_MASK
979 ** --width|-W N N character lines. DIFF_WIDTH_MASK
980 ** --html Format for HTML DIFF_HTML
981 ** --linenum|-n Show line numbers DIFF_LINENO
982 */
983 int diff_options(void){
984 int diffFlags = 0;
985 const char *z;
986 int f;
@@ -1034,10 +992,12 @@
992 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
993 f *= DIFF_CONTEXT_MASK+1;
994 if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK;
995 diffFlags |= f;
996 }
997 if( find_option("html",0,0)!=0 ) diffFlags |= DIFF_HTML;
998 if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
999 return diffFlags;
1000 }
1001
1002 /*
1003 ** COMMAND: test-udiff
1004
+78 -73
--- src/info.c
+++ src/info.c
@@ -251,11 +251,11 @@
251251
252252
253253
/*
254254
** Append the difference between two RIDs to the output
255255
*/
256
-static void append_diff(const char *zFrom, const char *zTo){
256
+static void append_diff(const char *zFrom, const char *zTo, int diffFlags){
257257
int fromid;
258258
int toid;
259259
Blob from, to, out;
260260
if( zFrom ){
261261
fromid = uuid_to_rid(zFrom, 0);
@@ -268,46 +268,26 @@
268268
content_get(toid, &to);
269269
}else{
270270
blob_zero(&to);
271271
}
272272
blob_zero(&out);
273
- text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
274
- @ %h(blob_str(&out))
273
+ if( diffFlags & DIFF_SIDEBYSIDE ){
274
+ text_diff(&from, &to, &out, diffFlags | DIFF_HTML);
275
+ @ <div class="sbsdiff">
276
+ @ %s(blob_str(&out))
277
+ @ </div>
278
+ }else{
279
+ text_diff(&from, &to, &out, diffFlags | DIFF_LINENO | DIFF_HTML);
280
+ @ <div class="udiff">
281
+ @ %s(blob_str(&out))
282
+ @ </div>
283
+ }
275284
blob_reset(&from);
276285
blob_reset(&to);
277286
blob_reset(&out);
278287
}
279288
280
-
281
-/*
282
-** Write the difference between two RIDs to the output
283
-*/
284
-static void generate_sbsdiff(const char *zFrom, const char *zTo){
285
- int fromid;
286
- int toid;
287
- Blob from, to;
288
- if( zFrom ){
289
- fromid = uuid_to_rid(zFrom, 0);
290
- content_get(fromid, &from);
291
- }else{
292
- blob_zero(&from);
293
- }
294
- if( zTo ){
295
- toid = uuid_to_rid(zTo, 0);
296
- content_get(toid, &to);
297
- }else{
298
- blob_zero(&to);
299
- }
300
- @ <table class="sbsdiff">
301
- @ <tr><th colspan="2" class="diffhdr">Old (%S(zFrom))</th><th/>
302
- @ <th colspan="2" class="diffhdr">New (%S(zTo))</th></tr>
303
- html_sbsdiff(&from, &to, 5, 1);
304
- @ </table>
305
- blob_reset(&from);
306
- blob_reset(&to);
307
-}
308
-
309289
310290
/*
311291
** Write a line of web-page output that shows changes that have occurred
312292
** to a file between two check-ins.
313293
*/
@@ -314,12 +294,11 @@
314294
static void append_file_change_line(
315295
const char *zName, /* Name of the file that has changed */
316296
const char *zOld, /* blob.uuid before change. NULL for added files */
317297
const char *zNew, /* blob.uuid after change. NULL for deletes */
318298
const char *zOldName, /* Prior name. NULL if no name change. */
319
- int showDiff, /* Show edit diffs if true */
320
- int sideBySide, /* Show diffs side-by-side */
299
+ int diffFlags, /* Flags for text_diff(). Zero to omit diffs */
321300
int mperm /* executable or symlink permission for zNew */
322301
){
323302
if( !g.perm.History ){
324303
if( zNew==0 ){
325304
@ <p>Deleted %h(zName)</p>
@@ -331,18 +310,14 @@
331310
@ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
332311
@ for %h(zName)</p>
333312
}else{
334313
@ <p>Changes to %h(zName)</p>
335314
}
336
- if( showDiff ){
337
- if( sideBySide ){
338
- generate_sbsdiff(zOld, zNew);
339
- }else{
340
- @ <blockquote><pre>
341
- append_diff(zOld, zNew);
342
- @ </pre></blockquote>
343
- }
315
+ if( diffFlags ){
316
+ @ <pre style="white-space:pre;">
317
+ append_diff(zOld, zNew, diffFlags);
318
+ @ </pre>
344319
}
345320
}else{
346321
if( zOld && zNew ){
347322
if( fossil_strcmp(zOld, zNew)!=0 ){
348323
@ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
@@ -361,25 +336,50 @@
361336
@ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
362337
}else{
363338
@ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
364339
@ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
365340
}
366
- if( showDiff ){
367
- if( sideBySide ){
368
- generate_sbsdiff(zOld, zNew);
369
- }else{
370
- @ <blockquote><pre>
371
- append_diff(zOld, zNew);
372
- @ </pre></blockquote>
373
- }
341
+ if( diffFlags ){
342
+ @ <pre style="white-space:pre;">
343
+ append_diff(zOld, zNew, diffFlags);
344
+ @ </pre>
374345
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
375346
@ &nbsp;&nbsp;
376347
@ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
377348
}
378349
@ </p>
379350
}
380351
}
352
+
353
+/*
354
+** Construct an appropriate diffFlag for text_diff() based on query
355
+** parameters and the to boolean arguments.
356
+*/
357
+static int construct_diff_flags(int showDiff, int sideBySide){
358
+ int diffFlags;
359
+ if( showDiff==0 ){
360
+ diffFlags = 0; /* Zero means do not show any diff */
361
+ }else{
362
+ int x;
363
+ if( sideBySide ){
364
+ diffFlags = DIFF_SIDEBYSIDE | DIFF_IGNORE_EOLWS;
365
+
366
+ /* "dw" query parameter determines width of each column */
367
+ x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1);
368
+ if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK;
369
+ diffFlags += x;
370
+ }else{
371
+ diffFlags = DIFF_INLINE | DIFF_IGNORE_EOLWS;
372
+ }
373
+
374
+ /* "dc" query parameter determines lines of context */
375
+ x = atoi(PD("dc","7"));
376
+ if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK;
377
+ diffFlags += x;
378
+ }
379
+ return diffFlags;
380
+}
381381
382382
383383
/*
384384
** WEBPAGE: vinfo
385385
** WEBPAGE: ci
@@ -397,12 +397,13 @@
397397
*/
398398
void ci_page(void){
399399
Stmt q;
400400
int rid;
401401
int isLeaf;
402
- int showDiff;
403
- int sideBySide;
402
+ int showDiff; /* True to show diffs */
403
+ int sideBySide; /* True for side-by-side diffs */
404
+ int diffFlags; /* Flag parameter for text_diff() */
404405
const char *zName; /* Name of the checkin to be displayed */
405406
const char *zUuid; /* UUID of zName */
406407
const char *zParent; /* UUID of the parent checkin (if any) */
407408
408409
login_check_credentials();
@@ -595,18 +596,18 @@
595596
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
596597
" WHERE mlink.mid=%d"
597598
" ORDER BY name /*sort*/",
598599
rid
599600
);
601
+ diffFlags = construct_diff_flags(showDiff, sideBySide);
600602
while( db_step(&q)==SQLITE_ROW ){
601603
const char *zName = db_column_text(&q,0);
602604
int mperm = db_column_int(&q, 1);
603605
const char *zOld = db_column_text(&q,2);
604606
const char *zNew = db_column_text(&q,3);
605607
const char *zOldName = db_column_text(&q, 4);
606
- append_file_change_line(zName, zOld, zNew, zOldName, showDiff,
607
- sideBySide, mperm);
608
+ append_file_change_line(zName, zOld, zNew, zOldName, diffFlags, mperm);
608609
}
609610
db_finalize(&q);
610611
}
611612
style_footer();
612613
}
@@ -760,10 +761,11 @@
760761
*/
761762
void vdiff_page(void){
762763
int ridFrom, ridTo;
763764
int showDetail = 0;
764765
int sideBySide = 0;
766
+ int diffFlags = 0;
765767
Manifest *pFrom, *pTo;
766768
ManifestFile *pFileFrom, *pFileTo;
767769
768770
login_check_credentials();
769771
if( !g.perm.Read ){ login_needed(); return; }
@@ -771,12 +773,13 @@
771773
772774
pFrom = vdiff_parse_manifest("from", &ridFrom);
773775
if( pFrom==0 ) return;
774776
pTo = vdiff_parse_manifest("to", &ridTo);
775777
if( pTo==0 ) return;
776
- showDetail = atoi(PD("detail","0"));
777778
sideBySide = atoi(PD("sbs","1"));
779
+ showDetail = atoi(PD("detail","0"));
780
+ if( !showDetail && sideBySide ) showDetail = 1;
778781
if( !sideBySide ){
779782
style_submenu_element("Side-by-side Diff", "sbsdiff",
780783
"%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
781784
g.zTop, P("from"), P("to"), showDetail);
782785
}else{
@@ -793,10 +796,11 @@
793796
794797
manifest_file_rewind(pFrom);
795798
pFileFrom = manifest_file_next(pFrom, 0);
796799
manifest_file_rewind(pTo);
797800
pFileTo = manifest_file_next(pTo, 0);
801
+ diffFlags = construct_diff_flags(showDetail, sideBySide);
798802
while( pFileFrom || pFileTo ){
799803
int cmp;
800804
if( pFileFrom==0 ){
801805
cmp = +1;
802806
}else if( pFileTo==0 ){
@@ -804,25 +808,25 @@
804808
}else{
805809
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
806810
}
807811
if( cmp<0 ){
808812
append_file_change_line(pFileFrom->zName,
809
- pFileFrom->zUuid, 0, 0, 0, 0, 0);
813
+ pFileFrom->zUuid, 0, 0, 0, 0);
810814
pFileFrom = manifest_file_next(pFrom, 0);
811815
}else if( cmp>0 ){
812816
append_file_change_line(pFileTo->zName,
813
- 0, pFileTo->zUuid, 0, 0, 0,
817
+ 0, pFileTo->zUuid, 0, 0,
814818
manifest_file_mperm(pFileTo));
815819
pFileTo = manifest_file_next(pTo, 0);
816820
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
817821
/* No changes */
818822
pFileFrom = manifest_file_next(pFrom, 0);
819823
pFileTo = manifest_file_next(pTo, 0);
820824
}else{
821825
append_file_change_line(pFileFrom->zName,
822826
pFileFrom->zUuid,
823
- pFileTo->zUuid, 0, showDetail, sideBySide,
827
+ pFileTo->zUuid, 0, diffFlags,
824828
manifest_file_mperm(pFileTo));
825829
pFileFrom = manifest_file_next(pFrom, 0);
826830
pFileTo = manifest_file_next(pTo, 0);
827831
}
828832
}
@@ -1069,10 +1073,11 @@
10691073
int isPatch;
10701074
int sideBySide;
10711075
Blob c1, c2, diff, *pOut;
10721076
char *zV1;
10731077
char *zV2;
1078
+ int diffFlags;
10741079
10751080
login_check_credentials();
10761081
if( !g.perm.Read ){ login_needed(); return; }
10771082
v1 = name_to_rid_www("v1");
10781083
v2 = name_to_rid_www("v2");
@@ -1082,21 +1087,25 @@
10821087
zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
10831088
isPatch = P("patch")!=0;
10841089
if( isPatch ){
10851090
pOut = cgi_output_blob();
10861091
cgi_set_content_type("text/plain");
1092
+ diffFlags = 4;
10871093
}else{
10881094
blob_zero(&diff);
10891095
pOut = &diff;
1090
- }
1091
- if( !sideBySide || isPatch ){
1092
- content_get(v1, &c1);
1093
- content_get(v2, &c2);
1094
- text_diff(&c1, &c2, pOut, 4 | 0);
1095
- blob_reset(&c1);
1096
- blob_reset(&c2);
1097
- }
1096
+ if( sideBySide ){
1097
+ diffFlags = DIFF_IGNORE_EOLWS | DIFF_SIDEBYSIDE | 7;
1098
+ }else{
1099
+ diffFlags = DIFF_IGNORE_EOLWS | 7;
1100
+ }
1101
+ }
1102
+ content_get(v1, &c1);
1103
+ content_get(v2, &c2);
1104
+ text_diff(&c1, &c2, pOut, diffFlags);
1105
+ blob_reset(&c1);
1106
+ blob_reset(&c2);
10981107
if( !isPatch ){
10991108
style_header("Diff");
11001109
style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
11011110
g.zTop, P("v1"), P("v2"));
11021111
if( !sideBySide ){
@@ -1113,17 +1122,13 @@
11131122
@ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
11141123
object_description(v1, 0, 0);
11151124
@ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
11161125
object_description(v2, 0, 0);
11171126
@ <hr />
1118
- if( sideBySide ){
1119
- generate_sbsdiff(zV1, zV2);
1120
- }else{
1121
- @ <blockquote><pre>
1122
- @ %h(blob_str(&diff))
1123
- @ </pre></blockquote>
1124
- }
1127
+ @ <pre style="while-space:pre;">
1128
+ @ %h(blob_str(&diff))
1129
+ @ </pre>
11251130
blob_reset(&diff);
11261131
style_footer();
11271132
}
11281133
}
11291134
11301135
--- src/info.c
+++ src/info.c
@@ -251,11 +251,11 @@
251
252
253 /*
254 ** Append the difference between two RIDs to the output
255 */
256 static void append_diff(const char *zFrom, const char *zTo){
257 int fromid;
258 int toid;
259 Blob from, to, out;
260 if( zFrom ){
261 fromid = uuid_to_rid(zFrom, 0);
@@ -268,46 +268,26 @@
268 content_get(toid, &to);
269 }else{
270 blob_zero(&to);
271 }
272 blob_zero(&out);
273 text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5);
274 @ %h(blob_str(&out))
 
 
 
 
 
 
 
 
 
275 blob_reset(&from);
276 blob_reset(&to);
277 blob_reset(&out);
278 }
279
280
281 /*
282 ** Write the difference between two RIDs to the output
283 */
284 static void generate_sbsdiff(const char *zFrom, const char *zTo){
285 int fromid;
286 int toid;
287 Blob from, to;
288 if( zFrom ){
289 fromid = uuid_to_rid(zFrom, 0);
290 content_get(fromid, &from);
291 }else{
292 blob_zero(&from);
293 }
294 if( zTo ){
295 toid = uuid_to_rid(zTo, 0);
296 content_get(toid, &to);
297 }else{
298 blob_zero(&to);
299 }
300 @ <table class="sbsdiff">
301 @ <tr><th colspan="2" class="diffhdr">Old (%S(zFrom))</th><th/>
302 @ <th colspan="2" class="diffhdr">New (%S(zTo))</th></tr>
303 html_sbsdiff(&from, &to, 5, 1);
304 @ </table>
305 blob_reset(&from);
306 blob_reset(&to);
307 }
308
309
310 /*
311 ** Write a line of web-page output that shows changes that have occurred
312 ** to a file between two check-ins.
313 */
@@ -314,12 +294,11 @@
314 static void append_file_change_line(
315 const char *zName, /* Name of the file that has changed */
316 const char *zOld, /* blob.uuid before change. NULL for added files */
317 const char *zNew, /* blob.uuid after change. NULL for deletes */
318 const char *zOldName, /* Prior name. NULL if no name change. */
319 int showDiff, /* Show edit diffs if true */
320 int sideBySide, /* Show diffs side-by-side */
321 int mperm /* executable or symlink permission for zNew */
322 ){
323 if( !g.perm.History ){
324 if( zNew==0 ){
325 @ <p>Deleted %h(zName)</p>
@@ -331,18 +310,14 @@
331 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
332 @ for %h(zName)</p>
333 }else{
334 @ <p>Changes to %h(zName)</p>
335 }
336 if( showDiff ){
337 if( sideBySide ){
338 generate_sbsdiff(zOld, zNew);
339 }else{
340 @ <blockquote><pre>
341 append_diff(zOld, zNew);
342 @ </pre></blockquote>
343 }
344 }
345 }else{
346 if( zOld && zNew ){
347 if( fossil_strcmp(zOld, zNew)!=0 ){
348 @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
@@ -361,25 +336,50 @@
361 @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
362 }else{
363 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
364 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
365 }
366 if( showDiff ){
367 if( sideBySide ){
368 generate_sbsdiff(zOld, zNew);
369 }else{
370 @ <blockquote><pre>
371 append_diff(zOld, zNew);
372 @ </pre></blockquote>
373 }
374 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
375 @ &nbsp;&nbsp;
376 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
377 }
378 @ </p>
379 }
380 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
382
383 /*
384 ** WEBPAGE: vinfo
385 ** WEBPAGE: ci
@@ -397,12 +397,13 @@
397 */
398 void ci_page(void){
399 Stmt q;
400 int rid;
401 int isLeaf;
402 int showDiff;
403 int sideBySide;
 
404 const char *zName; /* Name of the checkin to be displayed */
405 const char *zUuid; /* UUID of zName */
406 const char *zParent; /* UUID of the parent checkin (if any) */
407
408 login_check_credentials();
@@ -595,18 +596,18 @@
595 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
596 " WHERE mlink.mid=%d"
597 " ORDER BY name /*sort*/",
598 rid
599 );
 
600 while( db_step(&q)==SQLITE_ROW ){
601 const char *zName = db_column_text(&q,0);
602 int mperm = db_column_int(&q, 1);
603 const char *zOld = db_column_text(&q,2);
604 const char *zNew = db_column_text(&q,3);
605 const char *zOldName = db_column_text(&q, 4);
606 append_file_change_line(zName, zOld, zNew, zOldName, showDiff,
607 sideBySide, mperm);
608 }
609 db_finalize(&q);
610 }
611 style_footer();
612 }
@@ -760,10 +761,11 @@
760 */
761 void vdiff_page(void){
762 int ridFrom, ridTo;
763 int showDetail = 0;
764 int sideBySide = 0;
 
765 Manifest *pFrom, *pTo;
766 ManifestFile *pFileFrom, *pFileTo;
767
768 login_check_credentials();
769 if( !g.perm.Read ){ login_needed(); return; }
@@ -771,12 +773,13 @@
771
772 pFrom = vdiff_parse_manifest("from", &ridFrom);
773 if( pFrom==0 ) return;
774 pTo = vdiff_parse_manifest("to", &ridTo);
775 if( pTo==0 ) return;
776 showDetail = atoi(PD("detail","0"));
777 sideBySide = atoi(PD("sbs","1"));
 
 
778 if( !sideBySide ){
779 style_submenu_element("Side-by-side Diff", "sbsdiff",
780 "%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
781 g.zTop, P("from"), P("to"), showDetail);
782 }else{
@@ -793,10 +796,11 @@
793
794 manifest_file_rewind(pFrom);
795 pFileFrom = manifest_file_next(pFrom, 0);
796 manifest_file_rewind(pTo);
797 pFileTo = manifest_file_next(pTo, 0);
 
798 while( pFileFrom || pFileTo ){
799 int cmp;
800 if( pFileFrom==0 ){
801 cmp = +1;
802 }else if( pFileTo==0 ){
@@ -804,25 +808,25 @@
804 }else{
805 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
806 }
807 if( cmp<0 ){
808 append_file_change_line(pFileFrom->zName,
809 pFileFrom->zUuid, 0, 0, 0, 0, 0);
810 pFileFrom = manifest_file_next(pFrom, 0);
811 }else if( cmp>0 ){
812 append_file_change_line(pFileTo->zName,
813 0, pFileTo->zUuid, 0, 0, 0,
814 manifest_file_mperm(pFileTo));
815 pFileTo = manifest_file_next(pTo, 0);
816 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
817 /* No changes */
818 pFileFrom = manifest_file_next(pFrom, 0);
819 pFileTo = manifest_file_next(pTo, 0);
820 }else{
821 append_file_change_line(pFileFrom->zName,
822 pFileFrom->zUuid,
823 pFileTo->zUuid, 0, showDetail, sideBySide,
824 manifest_file_mperm(pFileTo));
825 pFileFrom = manifest_file_next(pFrom, 0);
826 pFileTo = manifest_file_next(pTo, 0);
827 }
828 }
@@ -1069,10 +1073,11 @@
1069 int isPatch;
1070 int sideBySide;
1071 Blob c1, c2, diff, *pOut;
1072 char *zV1;
1073 char *zV2;
 
1074
1075 login_check_credentials();
1076 if( !g.perm.Read ){ login_needed(); return; }
1077 v1 = name_to_rid_www("v1");
1078 v2 = name_to_rid_www("v2");
@@ -1082,21 +1087,25 @@
1082 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1083 isPatch = P("patch")!=0;
1084 if( isPatch ){
1085 pOut = cgi_output_blob();
1086 cgi_set_content_type("text/plain");
 
1087 }else{
1088 blob_zero(&diff);
1089 pOut = &diff;
1090 }
1091 if( !sideBySide || isPatch ){
1092 content_get(v1, &c1);
1093 content_get(v2, &c2);
1094 text_diff(&c1, &c2, pOut, 4 | 0);
1095 blob_reset(&c1);
1096 blob_reset(&c2);
1097 }
 
 
 
1098 if( !isPatch ){
1099 style_header("Diff");
1100 style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1101 g.zTop, P("v1"), P("v2"));
1102 if( !sideBySide ){
@@ -1113,17 +1122,13 @@
1113 @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
1114 object_description(v1, 0, 0);
1115 @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
1116 object_description(v2, 0, 0);
1117 @ <hr />
1118 if( sideBySide ){
1119 generate_sbsdiff(zV1, zV2);
1120 }else{
1121 @ <blockquote><pre>
1122 @ %h(blob_str(&diff))
1123 @ </pre></blockquote>
1124 }
1125 blob_reset(&diff);
1126 style_footer();
1127 }
1128 }
1129
1130
--- src/info.c
+++ src/info.c
@@ -251,11 +251,11 @@
251
252
253 /*
254 ** Append the difference between two RIDs to the output
255 */
256 static void append_diff(const char *zFrom, const char *zTo, int diffFlags){
257 int fromid;
258 int toid;
259 Blob from, to, out;
260 if( zFrom ){
261 fromid = uuid_to_rid(zFrom, 0);
@@ -268,46 +268,26 @@
268 content_get(toid, &to);
269 }else{
270 blob_zero(&to);
271 }
272 blob_zero(&out);
273 if( diffFlags & DIFF_SIDEBYSIDE ){
274 text_diff(&from, &to, &out, diffFlags | DIFF_HTML);
275 @ <div class="sbsdiff">
276 @ %s(blob_str(&out))
277 @ </div>
278 }else{
279 text_diff(&from, &to, &out, diffFlags | DIFF_LINENO | DIFF_HTML);
280 @ <div class="udiff">
281 @ %s(blob_str(&out))
282 @ </div>
283 }
284 blob_reset(&from);
285 blob_reset(&to);
286 blob_reset(&out);
287 }
288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
290 /*
291 ** Write a line of web-page output that shows changes that have occurred
292 ** to a file between two check-ins.
293 */
@@ -314,12 +294,11 @@
294 static void append_file_change_line(
295 const char *zName, /* Name of the file that has changed */
296 const char *zOld, /* blob.uuid before change. NULL for added files */
297 const char *zNew, /* blob.uuid after change. NULL for deletes */
298 const char *zOldName, /* Prior name. NULL if no name change. */
299 int diffFlags, /* Flags for text_diff(). Zero to omit diffs */
 
300 int mperm /* executable or symlink permission for zNew */
301 ){
302 if( !g.perm.History ){
303 if( zNew==0 ){
304 @ <p>Deleted %h(zName)</p>
@@ -331,18 +310,14 @@
310 @ <p>Execute permission %s(( mperm==PERM_EXE )?"set":"cleared")
311 @ for %h(zName)</p>
312 }else{
313 @ <p>Changes to %h(zName)</p>
314 }
315 if( diffFlags ){
316 @ <pre style="white-space:pre;">
317 append_diff(zOld, zNew, diffFlags);
318 @ </pre>
 
 
 
 
319 }
320 }else{
321 if( zOld && zNew ){
322 if( fossil_strcmp(zOld, zNew)!=0 ){
323 @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
@@ -361,25 +336,50 @@
336 @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
337 }else{
338 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
339 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
340 }
341 if( diffFlags ){
342 @ <pre style="white-space:pre;">
343 append_diff(zOld, zNew, diffFlags);
344 @ </pre>
 
 
 
 
345 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
346 @ &nbsp;&nbsp;
347 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
348 }
349 @ </p>
350 }
351 }
352
353 /*
354 ** Construct an appropriate diffFlag for text_diff() based on query
355 ** parameters and the to boolean arguments.
356 */
357 static int construct_diff_flags(int showDiff, int sideBySide){
358 int diffFlags;
359 if( showDiff==0 ){
360 diffFlags = 0; /* Zero means do not show any diff */
361 }else{
362 int x;
363 if( sideBySide ){
364 diffFlags = DIFF_SIDEBYSIDE | DIFF_IGNORE_EOLWS;
365
366 /* "dw" query parameter determines width of each column */
367 x = atoi(PD("dw","80"))*(DIFF_CONTEXT_MASK+1);
368 if( x<0 || x>DIFF_WIDTH_MASK ) x = DIFF_WIDTH_MASK;
369 diffFlags += x;
370 }else{
371 diffFlags = DIFF_INLINE | DIFF_IGNORE_EOLWS;
372 }
373
374 /* "dc" query parameter determines lines of context */
375 x = atoi(PD("dc","7"));
376 if( x<0 || x>DIFF_CONTEXT_MASK ) x = DIFF_CONTEXT_MASK;
377 diffFlags += x;
378 }
379 return diffFlags;
380 }
381
382
383 /*
384 ** WEBPAGE: vinfo
385 ** WEBPAGE: ci
@@ -397,12 +397,13 @@
397 */
398 void ci_page(void){
399 Stmt q;
400 int rid;
401 int isLeaf;
402 int showDiff; /* True to show diffs */
403 int sideBySide; /* True for side-by-side diffs */
404 int diffFlags; /* Flag parameter for text_diff() */
405 const char *zName; /* Name of the checkin to be displayed */
406 const char *zUuid; /* UUID of zName */
407 const char *zParent; /* UUID of the parent checkin (if any) */
408
409 login_check_credentials();
@@ -595,18 +596,18 @@
596 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
597 " WHERE mlink.mid=%d"
598 " ORDER BY name /*sort*/",
599 rid
600 );
601 diffFlags = construct_diff_flags(showDiff, sideBySide);
602 while( db_step(&q)==SQLITE_ROW ){
603 const char *zName = db_column_text(&q,0);
604 int mperm = db_column_int(&q, 1);
605 const char *zOld = db_column_text(&q,2);
606 const char *zNew = db_column_text(&q,3);
607 const char *zOldName = db_column_text(&q, 4);
608 append_file_change_line(zName, zOld, zNew, zOldName, diffFlags, mperm);
 
609 }
610 db_finalize(&q);
611 }
612 style_footer();
613 }
@@ -760,10 +761,11 @@
761 */
762 void vdiff_page(void){
763 int ridFrom, ridTo;
764 int showDetail = 0;
765 int sideBySide = 0;
766 int diffFlags = 0;
767 Manifest *pFrom, *pTo;
768 ManifestFile *pFileFrom, *pFileTo;
769
770 login_check_credentials();
771 if( !g.perm.Read ){ login_needed(); return; }
@@ -771,12 +773,13 @@
773
774 pFrom = vdiff_parse_manifest("from", &ridFrom);
775 if( pFrom==0 ) return;
776 pTo = vdiff_parse_manifest("to", &ridTo);
777 if( pTo==0 ) return;
 
778 sideBySide = atoi(PD("sbs","1"));
779 showDetail = atoi(PD("detail","0"));
780 if( !showDetail && sideBySide ) showDetail = 1;
781 if( !sideBySide ){
782 style_submenu_element("Side-by-side Diff", "sbsdiff",
783 "%s/vdiff?from=%T&to=%T&detail=%d&sbs=1",
784 g.zTop, P("from"), P("to"), showDetail);
785 }else{
@@ -793,10 +796,11 @@
796
797 manifest_file_rewind(pFrom);
798 pFileFrom = manifest_file_next(pFrom, 0);
799 manifest_file_rewind(pTo);
800 pFileTo = manifest_file_next(pTo, 0);
801 diffFlags = construct_diff_flags(showDetail, sideBySide);
802 while( pFileFrom || pFileTo ){
803 int cmp;
804 if( pFileFrom==0 ){
805 cmp = +1;
806 }else if( pFileTo==0 ){
@@ -804,25 +808,25 @@
808 }else{
809 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
810 }
811 if( cmp<0 ){
812 append_file_change_line(pFileFrom->zName,
813 pFileFrom->zUuid, 0, 0, 0, 0);
814 pFileFrom = manifest_file_next(pFrom, 0);
815 }else if( cmp>0 ){
816 append_file_change_line(pFileTo->zName,
817 0, pFileTo->zUuid, 0, 0,
818 manifest_file_mperm(pFileTo));
819 pFileTo = manifest_file_next(pTo, 0);
820 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
821 /* No changes */
822 pFileFrom = manifest_file_next(pFrom, 0);
823 pFileTo = manifest_file_next(pTo, 0);
824 }else{
825 append_file_change_line(pFileFrom->zName,
826 pFileFrom->zUuid,
827 pFileTo->zUuid, 0, diffFlags,
828 manifest_file_mperm(pFileTo));
829 pFileFrom = manifest_file_next(pFrom, 0);
830 pFileTo = manifest_file_next(pTo, 0);
831 }
832 }
@@ -1069,10 +1073,11 @@
1073 int isPatch;
1074 int sideBySide;
1075 Blob c1, c2, diff, *pOut;
1076 char *zV1;
1077 char *zV2;
1078 int diffFlags;
1079
1080 login_check_credentials();
1081 if( !g.perm.Read ){ login_needed(); return; }
1082 v1 = name_to_rid_www("v1");
1083 v2 = name_to_rid_www("v2");
@@ -1082,21 +1087,25 @@
1087 zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2);
1088 isPatch = P("patch")!=0;
1089 if( isPatch ){
1090 pOut = cgi_output_blob();
1091 cgi_set_content_type("text/plain");
1092 diffFlags = 4;
1093 }else{
1094 blob_zero(&diff);
1095 pOut = &diff;
1096 if( sideBySide ){
1097 diffFlags = DIFF_IGNORE_EOLWS | DIFF_SIDEBYSIDE | 7;
1098 }else{
1099 diffFlags = DIFF_IGNORE_EOLWS | 7;
1100 }
1101 }
1102 content_get(v1, &c1);
1103 content_get(v2, &c2);
1104 text_diff(&c1, &c2, pOut, diffFlags);
1105 blob_reset(&c1);
1106 blob_reset(&c2);
1107 if( !isPatch ){
1108 style_header("Diff");
1109 style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch",
1110 g.zTop, P("v1"), P("v2"));
1111 if( !sideBySide ){
@@ -1113,17 +1122,13 @@
1122 @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2>
1123 object_description(v1, 0, 0);
1124 @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2>
1125 object_description(v2, 0, 0);
1126 @ <hr />
1127 @ <pre style="while-space:pre;">
1128 @ %h(blob_str(&diff))
1129 @ </pre>
 
 
 
 
1130 blob_reset(&diff);
1131 style_footer();
1132 }
1133 }
1134
1135
+2 -2
--- src/manifest.c
+++ src/manifest.c
@@ -1245,12 +1245,12 @@
12451245
if( p->zBaseline==0 ) return 0;
12461246
fetch_baseline(p, 1);
12471247
pBase = p->pBaseline;
12481248
if( pBase==0 ) return 0;
12491249
for(i=0; i<pBase->nFile; i++){
1250
- if( fossil_stricmp(zName, p->aFile[i].zName)==0 ){
1251
- return &p->aFile[i];
1250
+ if( fossil_stricmp(zName, pBase->aFile[i].zName)==0 ){
1251
+ return &pBase->aFile[i];
12521252
}
12531253
}
12541254
return 0;
12551255
}
12561256
12571257
--- src/manifest.c
+++ src/manifest.c
@@ -1245,12 +1245,12 @@
1245 if( p->zBaseline==0 ) return 0;
1246 fetch_baseline(p, 1);
1247 pBase = p->pBaseline;
1248 if( pBase==0 ) return 0;
1249 for(i=0; i<pBase->nFile; i++){
1250 if( fossil_stricmp(zName, p->aFile[i].zName)==0 ){
1251 return &p->aFile[i];
1252 }
1253 }
1254 return 0;
1255 }
1256
1257
--- src/manifest.c
+++ src/manifest.c
@@ -1245,12 +1245,12 @@
1245 if( p->zBaseline==0 ) return 0;
1246 fetch_baseline(p, 1);
1247 pBase = p->pBaseline;
1248 if( pBase==0 ) return 0;
1249 for(i=0; i<pBase->nFile; i++){
1250 if( fossil_stricmp(zName, pBase->aFile[i].zName)==0 ){
1251 return &pBase->aFile[i];
1252 }
1253 }
1254 return 0;
1255 }
1256
1257
-202
--- src/skins.c
+++ src/skins.c
@@ -153,55 +153,10 @@
153153
@ /* The label/value pairs on (for example) the vinfo page */
154154
@ table.label-value th {
155155
@ vertical-align: top;
156156
@ text-align: right;
157157
@ padding: 0.2ex 2ex;
158
-@ }
159
-@
160
-@ /* Side-by-side diff */
161
-@ table.sbsdiff {
162
-@ background-color: white;
163
-@ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
164
-@ font-size: 8pt;
165
-@ border-collapse:collapse;
166
-@ white-space: pre;
167
-@ width: 98%;
168
-@ border: 1px #000 dashed;
169
-@ }
170
-@
171
-@ table.sbsdiff th.diffhdr {
172
-@ border-bottom: dotted;
173
-@ border-width: 1px;
174
-@ }
175
-@
176
-@ table.sbsdiff tr td {
177
-@ white-space: pre;
178
-@ padding-left: 3px;
179
-@ padding-right: 3px;
180
-@ margin: 0px;
181
-@ }
182
-@
183
-@ table.sbsdiff tr td.lineno {
184
-@ text-align: right;
185
-@ }
186
-@
187
-@ table.sbsdiff tr td.meta {
188
-@ color: white;
189
-@ background-color: rgb(20, 20, 20);
190
-@ text-align: center;
191
-@ }
192
-@
193
-@ table.sbsdiff tr td.added {
194
-@ background-color: rgb(230, 230, 230);
195
-@ }
196
-@
197
-@ table.sbsdiff tr td.removed {
198
-@ background-color: rgb(200, 200, 200);
199
-@ }
200
-@
201
-@ table.sbsdiff tr td.changed {
202
-@ background-color: rgb(220, 220, 220);
203158
@ }');
204159
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
205160
@ <head>
206161
@ <title>$<project_name>: $<title></title>
207162
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -400,54 +355,10 @@
400355
@ /* The label/value pairs on (for example) the ci page */
401356
@ table.label-value th {
402357
@ vertical-align: top;
403358
@ text-align: right;
404359
@ padding: 0.2ex 2ex;
405
-@ }
406
-@
407
-@ /* Side-by-side diff */
408
-@ table.sbsdiff {
409
-@ background-color: #ffffc5;
410
-@ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
411
-@ font-size: 8pt;
412
-@ border-collapse:collapse;
413
-@ white-space: pre;
414
-@ width: 98%;
415
-@ border: 1px #000 dashed;
416
-@ }
417
-@
418
-@ table.sbsdiff th.diffhdr {
419
-@ border-bottom: dotted;
420
-@ border-width: 1px;
421
-@ }
422
-@
423
-@ table.sbsdiff tr td {
424
-@ white-space: pre;
425
-@ padding-left: 3px;
426
-@ padding-right: 3px;
427
-@ margin: 0px;
428
-@ }
429
-@
430
-@ table.sbsdiff tr td.lineno {
431
-@ text-align: right;
432
-@ }
433
-@
434
-@ table.sbsdiff tr td.meta {
435
-@ background-color: #a09048;
436
-@ text-align: center;
437
-@ }
438
-@
439
-@ table.sbsdiff tr td.added {
440
-@ background-color: rgb(210, 210, 100);
441
-@ }
442
-@
443
-@ table.sbsdiff tr td.removed {
444
-@ background-color: rgb(190, 200, 110);
445
-@ }
446
-@
447
-@ table.sbsdiff tr td.changed {
448
-@ background-color: rgb(200, 210, 120);
449360
@ }');
450361
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
451362
@ <head>
452363
@ <title>$<project_name>: $<title></title>
453364
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -680,56 +591,10 @@
680591
@ /* The label/value pairs on (for example) the ci page */
681592
@ table.label-value th {
682593
@ vertical-align: top;
683594
@ text-align: right;
684595
@ padding: 0.2ex 2ex;
685
-@ }
686
-@
687
-@ /* Side-by-side diff */
688
-@ table.sbsdiff {
689
-@ background-color: white;
690
-@ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
691
-@ font-size: 6pt;
692
-@ border-collapse:collapse;
693
-@ white-space: pre;
694
-@ width: 98%;
695
-@ border: 1px #000 dashed;
696
-@ }
697
-@
698
-@ table.sbsdiff th.diffhdr {
699
-@ border-bottom: dotted;
700
-@ border-width: 1px;
701
-@ }
702
-@
703
-@ table.sbsdiff tr td {
704
-@ white-space: pre;
705
-@ padding-left: 3px;
706
-@ padding-right: 3px;
707
-@ margin: 0px;
708
-@ }
709
-@
710
-@ table.sbsdiff tr td.lineno {
711
-@ text-align: right;
712
-@ }
713
-@
714
-@ table.sbsdiff tr td.meta {
715
-@ color: white;
716
-@ background-color: black;
717
-@ text-align: center;
718
-@ }
719
-@
720
-@ table.sbsdiff tr td.added {
721
-@ background-color: white;
722
-@ }
723
-@
724
-@ table.sbsdiff tr td.removed {
725
-@ background-color: white;
726
-@ text-decoration: line-through;
727
-@ }
728
-@
729
-@ table.sbsdiff tr td.changed {
730
-@ background-color: white;
731596
@ }');
732597
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
733598
@ <head>
734599
@ <title>$<project_name>: $<title></title>
735600
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -1024,77 +889,10 @@
1024889
@ padding: 3px 5px;
1025890
@ }
1026891
@
1027892
@ textarea {
1028893
@ font-size: 1em;
1029
-@ }
1030
-@
1031
-@ /* Side-by-side diff */
1032
-@ table.sbsdiff {
1033
-@ background-color: white;
1034
-@ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
1035
-@ font-size: 6pt;
1036
-@ border-collapse:collapse;
1037
-@ width: 98%;
1038
-@ border: 1px #000 dashed;
1039
-@ margin-left: auto;
1040
-@ margin-right: auto;
1041
-@ }
1042
-@
1043
-@ table.sbsdiff th.diffhdr {
1044
-@ border-bottom: dotted;
1045
-@ border-width: 1px;
1046
-@ }
1047
-@
1048
-@ table.sbsdiff tr td {
1049
-@ padding-left: 3px;
1050
-@ padding-right: 3px;
1051
-@ margin: 0px;
1052
-@ vertical-align: top;
1053
-@ white-space: pre-wrap;
1054
-@ }
1055
-@
1056
-@ table.sbsdiff tr td.lineno {
1057
-@ text-align: right;
1058
-@ /* border-bottom: 1px solid rgb(220, 220, 220); */
1059
-@ }
1060
-@
1061
-@ table.sbsdiff tr td.srcline {
1062
-@ /* max-width: 400px; */
1063
-@ /* Note: May partially hide long lines without whitespaces */
1064
-@ /* overflow: hidden; */
1065
-@ /* border-bottom: 1px solid rgb(220, 220, 220); */
1066
-@ }
1067
-@
1068
-@ table.sbsdiff tr td.meta {
1069
-@ background-color: rgb(170, 160, 255);
1070
-@ padding-top: 0.25em;
1071
-@ padding-bottom: 0.25em;
1072
-@ text-align: center;
1073
-@ -moz-border-radius: 5px;
1074
-@ -moz-border-radius: 5px;
1075
-@ -webkit-border-radius: 5px;
1076
-@ -webkit-border-radius: 5px;
1077
-@ -border-radius: 5px;
1078
-@ -border-radius: 5px;
1079
-@ border-radius: 5px;
1080
-@ border-radius: 5px;
1081
-@ }
1082
-@
1083
-@ table.sbsdiff tr td.added {
1084
-@ background-color: rgb(180, 250, 180);
1085
-@ /* border-bottom: 1px solid rgb(160, 230, 160); */
1086
-@ }
1087
-@
1088
-@ table.sbsdiff tr td.removed {
1089
-@ background-color: rgb(250, 130, 130);
1090
-@ /* border-bottom: 1px solid rgb(230, 110, 110); */
1091
-@ }
1092
-@
1093
-@ table.sbsdiff tr td.changed {
1094
-@ background-color: rgb(210, 210, 200);
1095
-@ /* border-bottom: 1px solid rgb(190, 190, 180); */
1096894
@ }');
1097895
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
1098896
@ <head>
1099897
@ <title>$<project_name>: $<title></title>
1100898
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
1101899
--- src/skins.c
+++ src/skins.c
@@ -153,55 +153,10 @@
153 @ /* The label/value pairs on (for example) the vinfo page */
154 @ table.label-value th {
155 @ vertical-align: top;
156 @ text-align: right;
157 @ padding: 0.2ex 2ex;
158 @ }
159 @
160 @ /* Side-by-side diff */
161 @ table.sbsdiff {
162 @ background-color: white;
163 @ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
164 @ font-size: 8pt;
165 @ border-collapse:collapse;
166 @ white-space: pre;
167 @ width: 98%;
168 @ border: 1px #000 dashed;
169 @ }
170 @
171 @ table.sbsdiff th.diffhdr {
172 @ border-bottom: dotted;
173 @ border-width: 1px;
174 @ }
175 @
176 @ table.sbsdiff tr td {
177 @ white-space: pre;
178 @ padding-left: 3px;
179 @ padding-right: 3px;
180 @ margin: 0px;
181 @ }
182 @
183 @ table.sbsdiff tr td.lineno {
184 @ text-align: right;
185 @ }
186 @
187 @ table.sbsdiff tr td.meta {
188 @ color: white;
189 @ background-color: rgb(20, 20, 20);
190 @ text-align: center;
191 @ }
192 @
193 @ table.sbsdiff tr td.added {
194 @ background-color: rgb(230, 230, 230);
195 @ }
196 @
197 @ table.sbsdiff tr td.removed {
198 @ background-color: rgb(200, 200, 200);
199 @ }
200 @
201 @ table.sbsdiff tr td.changed {
202 @ background-color: rgb(220, 220, 220);
203 @ }');
204 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
205 @ <head>
206 @ <title>$<project_name>: $<title></title>
207 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -400,54 +355,10 @@
400 @ /* The label/value pairs on (for example) the ci page */
401 @ table.label-value th {
402 @ vertical-align: top;
403 @ text-align: right;
404 @ padding: 0.2ex 2ex;
405 @ }
406 @
407 @ /* Side-by-side diff */
408 @ table.sbsdiff {
409 @ background-color: #ffffc5;
410 @ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
411 @ font-size: 8pt;
412 @ border-collapse:collapse;
413 @ white-space: pre;
414 @ width: 98%;
415 @ border: 1px #000 dashed;
416 @ }
417 @
418 @ table.sbsdiff th.diffhdr {
419 @ border-bottom: dotted;
420 @ border-width: 1px;
421 @ }
422 @
423 @ table.sbsdiff tr td {
424 @ white-space: pre;
425 @ padding-left: 3px;
426 @ padding-right: 3px;
427 @ margin: 0px;
428 @ }
429 @
430 @ table.sbsdiff tr td.lineno {
431 @ text-align: right;
432 @ }
433 @
434 @ table.sbsdiff tr td.meta {
435 @ background-color: #a09048;
436 @ text-align: center;
437 @ }
438 @
439 @ table.sbsdiff tr td.added {
440 @ background-color: rgb(210, 210, 100);
441 @ }
442 @
443 @ table.sbsdiff tr td.removed {
444 @ background-color: rgb(190, 200, 110);
445 @ }
446 @
447 @ table.sbsdiff tr td.changed {
448 @ background-color: rgb(200, 210, 120);
449 @ }');
450 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
451 @ <head>
452 @ <title>$<project_name>: $<title></title>
453 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -680,56 +591,10 @@
680 @ /* The label/value pairs on (for example) the ci page */
681 @ table.label-value th {
682 @ vertical-align: top;
683 @ text-align: right;
684 @ padding: 0.2ex 2ex;
685 @ }
686 @
687 @ /* Side-by-side diff */
688 @ table.sbsdiff {
689 @ background-color: white;
690 @ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
691 @ font-size: 6pt;
692 @ border-collapse:collapse;
693 @ white-space: pre;
694 @ width: 98%;
695 @ border: 1px #000 dashed;
696 @ }
697 @
698 @ table.sbsdiff th.diffhdr {
699 @ border-bottom: dotted;
700 @ border-width: 1px;
701 @ }
702 @
703 @ table.sbsdiff tr td {
704 @ white-space: pre;
705 @ padding-left: 3px;
706 @ padding-right: 3px;
707 @ margin: 0px;
708 @ }
709 @
710 @ table.sbsdiff tr td.lineno {
711 @ text-align: right;
712 @ }
713 @
714 @ table.sbsdiff tr td.meta {
715 @ color: white;
716 @ background-color: black;
717 @ text-align: center;
718 @ }
719 @
720 @ table.sbsdiff tr td.added {
721 @ background-color: white;
722 @ }
723 @
724 @ table.sbsdiff tr td.removed {
725 @ background-color: white;
726 @ text-decoration: line-through;
727 @ }
728 @
729 @ table.sbsdiff tr td.changed {
730 @ background-color: white;
731 @ }');
732 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
733 @ <head>
734 @ <title>$<project_name>: $<title></title>
735 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -1024,77 +889,10 @@
1024 @ padding: 3px 5px;
1025 @ }
1026 @
1027 @ textarea {
1028 @ font-size: 1em;
1029 @ }
1030 @
1031 @ /* Side-by-side diff */
1032 @ table.sbsdiff {
1033 @ background-color: white;
1034 @ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
1035 @ font-size: 6pt;
1036 @ border-collapse:collapse;
1037 @ width: 98%;
1038 @ border: 1px #000 dashed;
1039 @ margin-left: auto;
1040 @ margin-right: auto;
1041 @ }
1042 @
1043 @ table.sbsdiff th.diffhdr {
1044 @ border-bottom: dotted;
1045 @ border-width: 1px;
1046 @ }
1047 @
1048 @ table.sbsdiff tr td {
1049 @ padding-left: 3px;
1050 @ padding-right: 3px;
1051 @ margin: 0px;
1052 @ vertical-align: top;
1053 @ white-space: pre-wrap;
1054 @ }
1055 @
1056 @ table.sbsdiff tr td.lineno {
1057 @ text-align: right;
1058 @ /* border-bottom: 1px solid rgb(220, 220, 220); */
1059 @ }
1060 @
1061 @ table.sbsdiff tr td.srcline {
1062 @ /* max-width: 400px; */
1063 @ /* Note: May partially hide long lines without whitespaces */
1064 @ /* overflow: hidden; */
1065 @ /* border-bottom: 1px solid rgb(220, 220, 220); */
1066 @ }
1067 @
1068 @ table.sbsdiff tr td.meta {
1069 @ background-color: rgb(170, 160, 255);
1070 @ padding-top: 0.25em;
1071 @ padding-bottom: 0.25em;
1072 @ text-align: center;
1073 @ -moz-border-radius: 5px;
1074 @ -moz-border-radius: 5px;
1075 @ -webkit-border-radius: 5px;
1076 @ -webkit-border-radius: 5px;
1077 @ -border-radius: 5px;
1078 @ -border-radius: 5px;
1079 @ border-radius: 5px;
1080 @ border-radius: 5px;
1081 @ }
1082 @
1083 @ table.sbsdiff tr td.added {
1084 @ background-color: rgb(180, 250, 180);
1085 @ /* border-bottom: 1px solid rgb(160, 230, 160); */
1086 @ }
1087 @
1088 @ table.sbsdiff tr td.removed {
1089 @ background-color: rgb(250, 130, 130);
1090 @ /* border-bottom: 1px solid rgb(230, 110, 110); */
1091 @ }
1092 @
1093 @ table.sbsdiff tr td.changed {
1094 @ background-color: rgb(210, 210, 200);
1095 @ /* border-bottom: 1px solid rgb(190, 190, 180); */
1096 @ }');
1097 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
1098 @ <head>
1099 @ <title>$<project_name>: $<title></title>
1100 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
1101
--- src/skins.c
+++ src/skins.c
@@ -153,55 +153,10 @@
153 @ /* The label/value pairs on (for example) the vinfo page */
154 @ table.label-value th {
155 @ vertical-align: top;
156 @ text-align: right;
157 @ padding: 0.2ex 2ex;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158 @ }');
159 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
160 @ <head>
161 @ <title>$<project_name>: $<title></title>
162 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -400,54 +355,10 @@
355 @ /* The label/value pairs on (for example) the ci page */
356 @ table.label-value th {
357 @ vertical-align: top;
358 @ text-align: right;
359 @ padding: 0.2ex 2ex;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
360 @ }');
361 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
362 @ <head>
363 @ <title>$<project_name>: $<title></title>
364 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -680,56 +591,10 @@
591 @ /* The label/value pairs on (for example) the ci page */
592 @ table.label-value th {
593 @ vertical-align: top;
594 @ text-align: right;
595 @ padding: 0.2ex 2ex;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
596 @ }');
597 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
598 @ <head>
599 @ <title>$<project_name>: $<title></title>
600 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
@@ -1024,77 +889,10 @@
889 @ padding: 3px 5px;
890 @ }
891 @
892 @ textarea {
893 @ font-size: 1em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
894 @ }');
895 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
896 @ <head>
897 @ <title>$<project_name>: $<title></title>
898 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
899
+31 -60
--- src/style.c
+++ src/style.c
@@ -398,70 +398,10 @@
398398
@ table.label-value th {
399399
@ vertical-align: top;
400400
@ text-align: right;
401401
@ padding: 0.2ex 2ex;
402402
@ }
403
-@
404
-@ /* Side-by-side diff */
405
-@ table.sbsdiff {
406
-@ background-color: white;
407
-@ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
408
-@ font-size: 8pt;
409
-@ border-collapse:collapse;
410
-@ white-space: pre;
411
-@ width: 98%;
412
-@ border: 1px #000 dashed;
413
-@ margin-left: auto;
414
-@ margin-right: auto;
415
-@ }
416
-@
417
-@ table.sbsdiff th.diffhdr {
418
-@ border-bottom: dotted;
419
-@ border-width: 1px;
420
-@ }
421
-@
422
-@ table.sbsdiff tr td {
423
-@ white-space: pre;
424
-@ padding-left: 3px;
425
-@ padding-right: 3px;
426
-@ margin: 0px;
427
-@ vertical-align: top;
428
-@ }
429
-@
430
-@ table.sbsdiff tr td.lineno {
431
-@ text-align: right;
432
-@ }
433
-@
434
-@ table.sbsdiff tr td.srcline {
435
-@ }
436
-@
437
-@ table.sbsdiff tr td.meta {
438
-@ background-color: rgb(170, 160, 255);
439
-@ text-align: center;
440
-@ }
441
-@
442
-@ table.sbsdiff tr td.added {
443
-@ background-color: rgb(180, 250, 180);
444
-@ }
445
-@ table.sbsdiff tr td.addedvoid {
446
-@ background-color: rgb(190, 190, 180);
447
-@ }
448
-@
449
-@ table.sbsdiff tr td.removed {
450
-@ background-color: rgb(250, 130, 130);
451
-@ }
452
-@ table.sbsdiff tr td.removedvoid {
453
-@ background-color: rgb(190, 190, 180);
454
-@ }
455
-@
456
-@ table.sbsdiff tr td.changed {
457
-@ background-color: rgb(210, 210, 200);
458
-@ }
459
-@ table.sbsdiff tr td.changedvoid {
460
-@ background-color: rgb(190, 190, 180);
461
-@ }
462
-@
463403
;
464404
465405
466406
/* The following table contains bits of default CSS that must
467407
** be included if they are not found in the application-defined
@@ -811,10 +751,41 @@
811751
{ "ul.filelist",
812752
"List of files in a timeline",
813753
@ margin-top: 3px;
814754
@ line-height: 100%;
815755
},
756
+ { "div.sbsdiff",
757
+ "side-by-side diff display",
758
+ @ font-family: monospace;
759
+ @ font-size: smaller;
760
+ @ white-space: pre;
761
+ },
762
+ { "div.udiff",
763
+ "context diff display",
764
+ @ font-family: monospace;
765
+ @ white-space: pre;
766
+ },
767
+ { "span.diffchng",
768
+ "changes in a diff",
769
+ @ background-color: #ffffc8;
770
+ },
771
+ { "span.diffadd",
772
+ "added code in a diff",
773
+ @ background-color: #e0ffe0;
774
+ },
775
+ { "span.diffrm",
776
+ "deleted in a diff",
777
+ @ background-color: #ffe0e0;
778
+ },
779
+ { "span.diffhr",
780
+ "suppressed lines in a diff",
781
+ @ color: #0000ff;
782
+ },
783
+ { "span.diffln",
784
+ "line nubmers in a diff",
785
+ @ color: #a0a0a0;
786
+ },
816787
{ 0,
817788
0,
818789
0
819790
}
820791
};
821792
--- src/style.c
+++ src/style.c
@@ -398,70 +398,10 @@
398 @ table.label-value th {
399 @ vertical-align: top;
400 @ text-align: right;
401 @ padding: 0.2ex 2ex;
402 @ }
403 @
404 @ /* Side-by-side diff */
405 @ table.sbsdiff {
406 @ background-color: white;
407 @ font-family: fixed, Dejavu Sans Mono, Monaco, Lucida Console, monospace;
408 @ font-size: 8pt;
409 @ border-collapse:collapse;
410 @ white-space: pre;
411 @ width: 98%;
412 @ border: 1px #000 dashed;
413 @ margin-left: auto;
414 @ margin-right: auto;
415 @ }
416 @
417 @ table.sbsdiff th.diffhdr {
418 @ border-bottom: dotted;
419 @ border-width: 1px;
420 @ }
421 @
422 @ table.sbsdiff tr td {
423 @ white-space: pre;
424 @ padding-left: 3px;
425 @ padding-right: 3px;
426 @ margin: 0px;
427 @ vertical-align: top;
428 @ }
429 @
430 @ table.sbsdiff tr td.lineno {
431 @ text-align: right;
432 @ }
433 @
434 @ table.sbsdiff tr td.srcline {
435 @ }
436 @
437 @ table.sbsdiff tr td.meta {
438 @ background-color: rgb(170, 160, 255);
439 @ text-align: center;
440 @ }
441 @
442 @ table.sbsdiff tr td.added {
443 @ background-color: rgb(180, 250, 180);
444 @ }
445 @ table.sbsdiff tr td.addedvoid {
446 @ background-color: rgb(190, 190, 180);
447 @ }
448 @
449 @ table.sbsdiff tr td.removed {
450 @ background-color: rgb(250, 130, 130);
451 @ }
452 @ table.sbsdiff tr td.removedvoid {
453 @ background-color: rgb(190, 190, 180);
454 @ }
455 @
456 @ table.sbsdiff tr td.changed {
457 @ background-color: rgb(210, 210, 200);
458 @ }
459 @ table.sbsdiff tr td.changedvoid {
460 @ background-color: rgb(190, 190, 180);
461 @ }
462 @
463 ;
464
465
466 /* The following table contains bits of default CSS that must
467 ** be included if they are not found in the application-defined
@@ -811,10 +751,41 @@
811 { "ul.filelist",
812 "List of files in a timeline",
813 @ margin-top: 3px;
814 @ line-height: 100%;
815 },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
816 { 0,
817 0,
818 0
819 }
820 };
821
--- src/style.c
+++ src/style.c
@@ -398,70 +398,10 @@
398 @ table.label-value th {
399 @ vertical-align: top;
400 @ text-align: right;
401 @ padding: 0.2ex 2ex;
402 @ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
403 ;
404
405
406 /* The following table contains bits of default CSS that must
407 ** be included if they are not found in the application-defined
@@ -811,10 +751,41 @@
751 { "ul.filelist",
752 "List of files in a timeline",
753 @ margin-top: 3px;
754 @ line-height: 100%;
755 },
756 { "div.sbsdiff",
757 "side-by-side diff display",
758 @ font-family: monospace;
759 @ font-size: smaller;
760 @ white-space: pre;
761 },
762 { "div.udiff",
763 "context diff display",
764 @ font-family: monospace;
765 @ white-space: pre;
766 },
767 { "span.diffchng",
768 "changes in a diff",
769 @ background-color: #ffffc8;
770 },
771 { "span.diffadd",
772 "added code in a diff",
773 @ background-color: #e0ffe0;
774 },
775 { "span.diffrm",
776 "deleted in a diff",
777 @ background-color: #ffe0e0;
778 },
779 { "span.diffhr",
780 "suppressed lines in a diff",
781 @ color: #0000ff;
782 },
783 { "span.diffln",
784 "line nubmers in a diff",
785 @ color: #a0a0a0;
786 },
787 { 0,
788 0,
789 0
790 }
791 };
792

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button