Fossil SCM

Clean up the data structures associated with adding color to diffs in preparation for attempts to improve the coloration.

drh 2021-08-27 14:01 UTC trunk
Commit 8c619bf2782e955b19ea2feb6c8b9293ada57d1bac41206e12e056e0bfc67eda
1 file changed +110 -94
+110 -94
--- src/diff.c
+++ src/diff.c
@@ -120,10 +120,16 @@
120120
DLine *aTo; /* File on right side of the diff */
121121
int nTo; /* Number of lines in aTo[] */
122122
int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
123123
};
124124
125
+/* <span> text for change coloration
126
+*/
127
+static const char zClassRm[] = "<span class=\"diffrm\">";
128
+static const char zClassAdd[] = "<span class=\"diffadd\">";
129
+static const char zClassChng[] = "<span class=\"diffchng\">";
130
+
125131
/*
126132
** Count the number of lines in the input string. Include the last line
127133
** in the count even if it lacks the \n terminator. If an empty string
128134
** is specified, the number of lines is zero. For the purposes of this
129135
** function, a string is considered empty if it contains no characters
@@ -301,13 +307,13 @@
301307
blob_append(pOut, &cPrefix, 1);
302308
if( html ){
303309
if( pRe && re_dline_match(pRe, pLine, 1)==0 ){
304310
cPrefix = ' ';
305311
}else if( cPrefix=='+' ){
306
- blob_append(pOut, "<span class=\"diffadd\">", -1);
312
+ blob_append(pOut, zClassAdd, -1);
307313
}else if( cPrefix=='-' ){
308
- blob_append(pOut, "<span class=\"diffrm\">", -1);
314
+ blob_append(pOut, zClassRm, -1);
309315
}
310316
htmlize_to_blob(pOut, pLine->z, pLine->n);
311317
if( cPrefix!=' ' ){
312318
blob_append(pOut, "</span>", -1);
313319
}
@@ -506,26 +512,32 @@
506512
}
507513
}
508514
if( html ) blob_append(pOut, "</pre>\n", -1);
509515
}
510516
517
+/*
518
+** Maximum number of change regions per line
519
+*/
520
+#define SBS_MXN 4
521
+
511522
/*
512523
** Status of a single output line
513524
*/
514525
typedef struct SbsLine SbsLine;
515526
struct SbsLine {
516527
Blob *apCols[5]; /* Array of pointers to output columns */
517528
int width; /* Maximum width of a column in the output */
518529
unsigned char escHtml; /* True to escape html characters */
519
- int iStart; /* Write zStart prior to character iStart */
520
- const char *zStart; /* A <span> tag */
521
- int iEnd; /* Write </span> prior to character iEnd */
522
- int iStart2; /* Write zStart2 prior to character iStart2 */
523
- const char *zStart2; /* A <span> tag */
524
- int iEnd2; /* Write </span> prior to character iEnd2 */
530
+ struct SbsMark {
531
+ int iStart; /* Write zTag prior to character iStart */
532
+ const char *zTag; /* A <span> tag for coloration */
533
+ int iEnd; /* Write </span> prior to character iEnd */
534
+ } a[SBS_MXN]; /* Change regions */
535
+ int n; /* Number of change regions used */
525536
ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
526537
};
538
+
527539
528540
/*
529541
** Column indices for SbsLine.apCols[]
530542
*/
531543
#define SBS_LNA 0 /* Left line number */
@@ -575,25 +587,23 @@
575587
colorize = 0;
576588
}
577589
for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
578590
char c = zIn[i];
579591
if( colorize ){
580
- if( i==p->iStart ){
581
- int x = strlen(p->zStart);
582
- blob_append(pCol, p->zStart, x);
592
+ if( i==p->a[0].iStart ){
593
+ int x = strlen(p->a[0].zTag);
594
+ blob_append(pCol, p->a[0].zTag, x);
583595
needEndSpan = 1;
584
- if( p->iStart2 ){
585
- p->iStart = p->iStart2;
586
- p->zStart = p->zStart2;
587
- p->iStart2 = 0;
588
- }
589
- }else if( i==p->iEnd ){
596
+ }else if( i==p->a[0].iEnd ){
590597
blob_append(pCol, "</span>", 7);
591598
needEndSpan = 0;
592
- if( p->iEnd2 ){
593
- p->iEnd = p->iEnd2;
594
- p->iEnd2 = 0;
599
+ if( p->n>1 ){
600
+ p->n--;
601
+ memmove(p->a, p->a+1, sizeof(p->a[0])*p->n);
602
+ }else{
603
+ p->a[0].iStart = -1;
604
+ p->a[0].iEnd = -1;
595605
}
596606
}
597607
}
598608
if( c=='\t' && !p->escHtml ){
599609
blob_append(pCol, " ", 1);
@@ -739,19 +749,19 @@
739749
}
740750
return rc;
741751
}
742752
743753
/*
744
-** Try to shift iStart as far as possible to the left.
754
+** Try to shift a[0].iStart as far as possible to the left.
745755
*/
746756
static void sbsShiftLeft(SbsLine *p, const char *z){
747757
int i, j;
748
- while( (i=p->iStart)>0 && z[i-1]==z[i] ){
749
- for(j=i+1; j<p->iEnd && z[j-1]==z[j]; j++){}
750
- if( j<p->iEnd ) break;
751
- p->iStart--;
752
- p->iEnd--;
758
+ while( (i=p->a[0].iStart)>0 && z[i-1]==z[i] ){
759
+ for(j=i+1; j<p->a[0].iEnd && z[j-1]==z[j]; j++){}
760
+ if( j<p->a[0].iEnd ) break;
761
+ p->a[0].iStart--;
762
+ p->a[0].iEnd--;
753763
}
754764
}
755765
756766
/*
757767
** Simplify iStart and iStart2:
@@ -760,28 +770,26 @@
760770
** * Make sure any null-changes are in canonoical form.
761771
** * Make sure all changes are at character boundaries for
762772
** multi-byte characters.
763773
*/
764774
static void sbsSimplifyLine(SbsLine *p, const char *z){
765
- if( p->iStart2==p->iEnd2 ){
766
- p->iStart2 = p->iEnd2 = 0;
767
- }else if( p->iStart2 ){
768
- while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
769
- while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
770
- }
771
- if( p->iStart==p->iEnd ){
772
- p->iStart = p->iStart2;
773
- p->iEnd = p->iEnd2;
774
- p->zStart = p->zStart2;
775
- p->iStart2 = 0;
776
- p->iEnd2 = 0;
777
- }
778
- if( p->iStart==p->iEnd ){
779
- p->iStart = p->iEnd = -1;
780
- }else if( p->iStart>0 ){
781
- while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
782
- while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
775
+ int i, j;
776
+
777
+ /* Remove zero-length spans */
778
+ for(i=j=0; i<p->n; i++){
779
+ if( p->a[i].iStart<p->a[i].iEnd ){
780
+ if( j<i ) memcpy(p->a+j, p->a+i, sizeof(p->a[0]));
781
+ j++;
782
+ }
783
+ }
784
+ p->n = j;
785
+
786
+ /* Align all spans to a character boundary */
787
+ for(i=0; i<p->n; i++){
788
+ struct SbsMark *a = p->a+i;
789
+ while( a->iStart>0 && (z[a->iStart]&0xc0)==0x80 ) a->iStart--;
790
+ while( (z[a->iEnd]&0xc0)==0x80 ) a->iEnd++;
783791
}
784792
}
785793
786794
/*
787795
** Write out lines that have been edited. Adjust the highlight to cover
@@ -802,13 +810,10 @@
802810
const char *zLeft; /* Text of the left line */
803811
const char *zRight; /* Text of the right line */
804812
int nLeftDiff; /* nLeft - nPrefix - nSuffix */
805813
int nRightDiff; /* nRight - nPrefix - nSuffix */
806814
int aLCS[4]; /* Bounds of common middle segment */
807
- static const char zClassRm[] = "<span class=\"diffrm\">";
808
- static const char zClassAdd[] = "<span class=\"diffadd\">";
809
- static const char zClassChng[] = "<span class=\"diffchng\">";
810815
811816
nLeft = pLeft->n;
812817
zLeft = pLeft->z;
813818
nRight = pRight->n;
814819
zRight = pRight->z;
@@ -867,38 +872,40 @@
867872
}
868873
869874
/* A single chunk of text inserted on the right */
870875
if( nPrefix+nSuffix==nLeft ){
871876
sbsWriteLineno(p, lnLeft, SBS_LNA);
872
- p->iStart2 = p->iEnd2 = 0;
873
- p->iStart = p->iEnd = -1;
877
+ p->a[0].iStart = p->a[0].iEnd = -1;
878
+ p->n = 0;
874879
sbsWriteText(p, pLeft, SBS_TXTA);
875880
if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
876881
sbsWriteMarker(p, " ", "");
877882
}else{
878883
sbsWriteMarker(p, " | ", "|");
879884
}
880885
sbsWriteLineno(p, lnRight, SBS_LNB);
881
- p->iStart = nPrefix;
882
- p->iEnd = nRight - nSuffix;
883
- p->zStart = zClassAdd;
886
+ p->a[0].iStart = nPrefix;
887
+ p->a[0].iEnd = nRight - nSuffix;
888
+ p->n = 1;
889
+ p->a[0].zTag = zClassAdd;
884890
sbsWriteText(p, pRight, SBS_TXTB);
885891
return;
886892
}
887893
888894
/* A single chunk of text deleted from the left */
889895
if( nPrefix+nSuffix==nRight ){
890896
/* Text deleted from the left */
891897
sbsWriteLineno(p, lnLeft, SBS_LNA);
892
- p->iStart2 = p->iEnd2 = 0;
893
- p->iStart = nPrefix;
894
- p->iEnd = nLeft - nSuffix;
895
- p->zStart = zClassRm;
898
+ p->a[0].iStart = nPrefix;
899
+ p->a[0].iEnd = nLeft - nSuffix;
900
+ p->a[0].zTag = zClassRm;
901
+ p->n = 1;
896902
sbsWriteText(p, pLeft, SBS_TXTA);
897903
sbsWriteMarker(p, " | ", "|");
898904
sbsWriteLineno(p, lnRight, SBS_LNB);
899
- p->iStart = p->iEnd = -1;
905
+ p->a[0].iStart = p->a[0].iEnd = -1;
906
+ p->n = 0;
900907
sbsWriteText(p, pRight, SBS_TXTB);
901908
return;
902909
}
903910
904911
/* At this point we know that there is a chunk of text that has
@@ -911,51 +918,53 @@
911918
&& nLeftDiff >= 6
912919
&& nRightDiff >= 6
913920
&& textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
914921
){
915922
sbsWriteLineno(p, lnLeft, SBS_LNA);
916
- p->iStart = nPrefix;
917
- p->iEnd = nPrefix + aLCS[0];
923
+ p->a[0].iStart = nPrefix;
924
+ p->a[0].iEnd = nPrefix + aLCS[0];
918925
if( aLCS[2]==0 ){
919926
sbsShiftLeft(p, pLeft->z);
920
- p->zStart = zClassRm;
927
+ p->a[0].zTag = zClassRm;
921928
}else{
922
- p->zStart = zClassChng;
929
+ p->a[0].zTag = zClassChng;
923930
}
924
- p->iStart2 = nPrefix + aLCS[1];
925
- p->iEnd2 = nLeft - nSuffix;
926
- p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
931
+ p->a[1].iStart = nPrefix + aLCS[1];
932
+ p->a[1].iEnd = nLeft - nSuffix;
933
+ p->a[1].zTag = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
934
+ p->n = 2;
927935
sbsSimplifyLine(p, zLeft);
928936
sbsWriteText(p, pLeft, SBS_TXTA);
929937
sbsWriteMarker(p, " | ", "|");
930938
sbsWriteLineno(p, lnRight, SBS_LNB);
931
- p->iStart = nPrefix;
932
- p->iEnd = nPrefix + aLCS[2];
939
+ p->a[0].iStart = nPrefix;
940
+ p->a[0].iEnd = nPrefix + aLCS[2];
933941
if( aLCS[0]==0 ){
934942
sbsShiftLeft(p, pRight->z);
935
- p->zStart = zClassAdd;
943
+ p->a[0].zTag = zClassAdd;
936944
}else{
937
- p->zStart = zClassChng;
945
+ p->a[0].zTag = zClassChng;
938946
}
939
- p->iStart2 = nPrefix + aLCS[3];
940
- p->iEnd2 = nRight - nSuffix;
941
- p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
947
+ p->a[1].iStart = nPrefix + aLCS[3];
948
+ p->a[1].iEnd = nRight - nSuffix;
949
+ p->a[1].zTag = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
950
+ p->n = 2;
942951
sbsSimplifyLine(p, zRight);
943952
sbsWriteText(p, pRight, SBS_TXTB);
944953
return;
945954
}
946955
947956
/* If all else fails, show a single big change between left and right */
948957
sbsWriteLineno(p, lnLeft, SBS_LNA);
949
- p->iStart2 = p->iEnd2 = 0;
950
- p->iStart = nPrefix;
951
- p->iEnd = nLeft - nSuffix;
952
- p->zStart = zClassChng;
958
+ p->a[0].iStart = nPrefix;
959
+ p->a[0].iEnd = nLeft - nSuffix;
960
+ p->a[0].zTag = zClassChng;
961
+ p->n = 1;
953962
sbsWriteText(p, pLeft, SBS_TXTA);
954963
sbsWriteMarker(p, " | ", "|");
955964
sbsWriteLineno(p, lnRight, SBS_LNB);
956
- p->iEnd = nRight - nSuffix;
965
+ p->a[0].iEnd = nRight - nSuffix;
957966
sbsWriteText(p, pRight, SBS_TXTB);
958967
}
959968
960969
/*
961970
** Minimum of two values
@@ -1224,13 +1233,13 @@
12241233
for(i=SBS_LNA; i<=SBS_TXTB; i++){
12251234
s.apCols[i] = pOut;
12261235
}
12271236
}
12281237
s.pRe = pRe;
1229
- s.iStart = -1;
1230
- s.iStart2 = 0;
1231
- s.iEnd = -1;
1238
+ s.a[0].iStart = -1;
1239
+ s.a[1].iStart = 0;
1240
+ s.a[0].iEnd = -1;
12321241
A = p->aFrom;
12331242
B = p->aTo;
12341243
R = p->aEdit;
12351244
mxr = p->nEdit;
12361245
while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1316,11 +1325,12 @@
13161325
a += skip;
13171326
b += skip;
13181327
m = R[r] - skip;
13191328
for(j=0; j<m; j++){
13201329
sbsWriteLineno(&s, a+j, SBS_LNA);
1321
- s.iStart = s.iEnd = -1;
1330
+ s.a[0].iStart = s.a[0].iEnd = -1;
1331
+ s.n = 1;
13221332
sbsWriteText(&s, &A[a+j], SBS_TXTA);
13231333
sbsWriteMarker(&s, " ", "");
13241334
sbsWriteLineno(&s, b+j, SBS_LNB);
13251335
sbsWriteText(&s, &B[b+j], SBS_TXTB);
13261336
}
@@ -1346,13 +1356,14 @@
13461356
alignment = sbsAlignment(&A[a], ma, &B[b], mb, diffFlags);
13471357
for(j=0; ma+mb>0; j++){
13481358
if( alignment[j]==1 ){
13491359
/* Delete one line from the left */
13501360
sbsWriteLineno(&s, a, SBS_LNA);
1351
- s.iStart = 0;
1352
- s.zStart = "<span class=\"diffrm\">";
1353
- s.iEnd = LENGTH(&A[a]);
1361
+ s.a[0].iStart = 0;
1362
+ s.a[0].zTag = zClassRm;
1363
+ s.a[0].iEnd = LENGTH(&A[a]);
1364
+ s.n = 1;
13541365
sbsWriteText(&s, &A[a], SBS_TXTA);
13551366
sbsWriteMarker(&s, " <", "&lt;");
13561367
sbsWriteNewlines(&s);
13571368
assert( ma>0 );
13581369
ma--;
@@ -1370,29 +1381,32 @@
13701381
if( !s.escHtml ){
13711382
sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
13721383
}
13731384
sbsWriteMarker(&s, " > ", "&gt;");
13741385
sbsWriteLineno(&s, b, SBS_LNB);
1375
- s.iStart = 0;
1376
- s.zStart = "<span class=\"diffadd\">";
1377
- s.iEnd = LENGTH(&B[b]);
1386
+ s.a[0].iStart = 0;
1387
+ s.a[0].zTag = zClassAdd;
1388
+ s.a[0].iEnd = LENGTH(&B[b]);
1389
+ s.n = 1;
13781390
sbsWriteText(&s, &B[b], SBS_TXTB);
13791391
assert( mb>0 );
13801392
mb--;
13811393
b++;
13821394
}else{
13831395
/* Delete from the left and insert on the right */
13841396
sbsWriteLineno(&s, a, SBS_LNA);
1385
- s.iStart = 0;
1386
- s.zStart = "<span class=\"diffrm\">";
1387
- s.iEnd = LENGTH(&A[a]);
1397
+ s.a[0].iStart = 0;
1398
+ s.a[0].zTag = zClassRm;
1399
+ s.a[0].iEnd = LENGTH(&A[a]);
1400
+ s.n = 1;
13881401
sbsWriteText(&s, &A[a], SBS_TXTA);
13891402
sbsWriteMarker(&s, " | ", "|");
13901403
sbsWriteLineno(&s, b, SBS_LNB);
1391
- s.iStart = 0;
1392
- s.zStart = "<span class=\"diffadd\">";
1393
- s.iEnd = LENGTH(&B[b]);
1404
+ s.a[0].iStart = 0;
1405
+ s.a[0].zTag = zClassAdd;
1406
+ s.a[0].iEnd = LENGTH(&B[b]);
1407
+ s.n = 1;
13941408
sbsWriteText(&s, &B[b], SBS_TXTB);
13951409
ma--;
13961410
mb--;
13971411
a++;
13981412
b++;
@@ -1401,11 +1415,12 @@
14011415
fossil_free(alignment);
14021416
if( i<nr-1 ){
14031417
m = R[r+i*3+3];
14041418
for(j=0; j<m; j++){
14051419
sbsWriteLineno(&s, a+j, SBS_LNA);
1406
- s.iStart = s.iEnd = -1;
1420
+ s.a[0].iStart = s.a[0].iEnd = -1;
1421
+ s.n = 0;
14071422
sbsWriteText(&s, &A[a+j], SBS_TXTA);
14081423
sbsWriteMarker(&s, " ", "");
14091424
sbsWriteLineno(&s, b+j, SBS_LNB);
14101425
sbsWriteText(&s, &B[b+j], SBS_TXTB);
14111426
}
@@ -1418,11 +1433,12 @@
14181433
assert( nr==i );
14191434
m = R[r+nr*3];
14201435
if( m>nContext ) m = nContext;
14211436
for(j=0; j<m; j++){
14221437
sbsWriteLineno(&s, a+j, SBS_LNA);
1423
- s.iStart = s.iEnd = -1;
1438
+ s.a[0].iStart = s.a[0].iEnd = -1;
1439
+ s.n = 0;
14241440
sbsWriteText(&s, &A[a+j], SBS_TXTA);
14251441
sbsWriteMarker(&s, " ", "");
14261442
sbsWriteLineno(&s, b+j, SBS_LNB);
14271443
sbsWriteText(&s, &B[b+j], SBS_TXTB);
14281444
}
14291445
--- src/diff.c
+++ src/diff.c
@@ -120,10 +120,16 @@
120 DLine *aTo; /* File on right side of the diff */
121 int nTo; /* Number of lines in aTo[] */
122 int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
123 };
124
 
 
 
 
 
 
125 /*
126 ** Count the number of lines in the input string. Include the last line
127 ** in the count even if it lacks the \n terminator. If an empty string
128 ** is specified, the number of lines is zero. For the purposes of this
129 ** function, a string is considered empty if it contains no characters
@@ -301,13 +307,13 @@
301 blob_append(pOut, &cPrefix, 1);
302 if( html ){
303 if( pRe && re_dline_match(pRe, pLine, 1)==0 ){
304 cPrefix = ' ';
305 }else if( cPrefix=='+' ){
306 blob_append(pOut, "<span class=\"diffadd\">", -1);
307 }else if( cPrefix=='-' ){
308 blob_append(pOut, "<span class=\"diffrm\">", -1);
309 }
310 htmlize_to_blob(pOut, pLine->z, pLine->n);
311 if( cPrefix!=' ' ){
312 blob_append(pOut, "</span>", -1);
313 }
@@ -506,26 +512,32 @@
506 }
507 }
508 if( html ) blob_append(pOut, "</pre>\n", -1);
509 }
510
 
 
 
 
 
511 /*
512 ** Status of a single output line
513 */
514 typedef struct SbsLine SbsLine;
515 struct SbsLine {
516 Blob *apCols[5]; /* Array of pointers to output columns */
517 int width; /* Maximum width of a column in the output */
518 unsigned char escHtml; /* True to escape html characters */
519 int iStart; /* Write zStart prior to character iStart */
520 const char *zStart; /* A <span> tag */
521 int iEnd; /* Write </span> prior to character iEnd */
522 int iStart2; /* Write zStart2 prior to character iStart2 */
523 const char *zStart2; /* A <span> tag */
524 int iEnd2; /* Write </span> prior to character iEnd2 */
525 ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
526 };
 
527
528 /*
529 ** Column indices for SbsLine.apCols[]
530 */
531 #define SBS_LNA 0 /* Left line number */
@@ -575,25 +587,23 @@
575 colorize = 0;
576 }
577 for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
578 char c = zIn[i];
579 if( colorize ){
580 if( i==p->iStart ){
581 int x = strlen(p->zStart);
582 blob_append(pCol, p->zStart, x);
583 needEndSpan = 1;
584 if( p->iStart2 ){
585 p->iStart = p->iStart2;
586 p->zStart = p->zStart2;
587 p->iStart2 = 0;
588 }
589 }else if( i==p->iEnd ){
590 blob_append(pCol, "</span>", 7);
591 needEndSpan = 0;
592 if( p->iEnd2 ){
593 p->iEnd = p->iEnd2;
594 p->iEnd2 = 0;
 
 
 
595 }
596 }
597 }
598 if( c=='\t' && !p->escHtml ){
599 blob_append(pCol, " ", 1);
@@ -739,19 +749,19 @@
739 }
740 return rc;
741 }
742
743 /*
744 ** Try to shift iStart as far as possible to the left.
745 */
746 static void sbsShiftLeft(SbsLine *p, const char *z){
747 int i, j;
748 while( (i=p->iStart)>0 && z[i-1]==z[i] ){
749 for(j=i+1; j<p->iEnd && z[j-1]==z[j]; j++){}
750 if( j<p->iEnd ) break;
751 p->iStart--;
752 p->iEnd--;
753 }
754 }
755
756 /*
757 ** Simplify iStart and iStart2:
@@ -760,28 +770,26 @@
760 ** * Make sure any null-changes are in canonoical form.
761 ** * Make sure all changes are at character boundaries for
762 ** multi-byte characters.
763 */
764 static void sbsSimplifyLine(SbsLine *p, const char *z){
765 if( p->iStart2==p->iEnd2 ){
766 p->iStart2 = p->iEnd2 = 0;
767 }else if( p->iStart2 ){
768 while( p->iStart2>0 && (z[p->iStart2]&0xc0)==0x80 ) p->iStart2--;
769 while( (z[p->iEnd2]&0xc0)==0x80 ) p->iEnd2++;
770 }
771 if( p->iStart==p->iEnd ){
772 p->iStart = p->iStart2;
773 p->iEnd = p->iEnd2;
774 p->zStart = p->zStart2;
775 p->iStart2 = 0;
776 p->iEnd2 = 0;
777 }
778 if( p->iStart==p->iEnd ){
779 p->iStart = p->iEnd = -1;
780 }else if( p->iStart>0 ){
781 while( p->iStart>0 && (z[p->iStart]&0xc0)==0x80 ) p->iStart--;
782 while( (z[p->iEnd]&0xc0)==0x80 ) p->iEnd++;
783 }
784 }
785
786 /*
787 ** Write out lines that have been edited. Adjust the highlight to cover
@@ -802,13 +810,10 @@
802 const char *zLeft; /* Text of the left line */
803 const char *zRight; /* Text of the right line */
804 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
805 int nRightDiff; /* nRight - nPrefix - nSuffix */
806 int aLCS[4]; /* Bounds of common middle segment */
807 static const char zClassRm[] = "<span class=\"diffrm\">";
808 static const char zClassAdd[] = "<span class=\"diffadd\">";
809 static const char zClassChng[] = "<span class=\"diffchng\">";
810
811 nLeft = pLeft->n;
812 zLeft = pLeft->z;
813 nRight = pRight->n;
814 zRight = pRight->z;
@@ -867,38 +872,40 @@
867 }
868
869 /* A single chunk of text inserted on the right */
870 if( nPrefix+nSuffix==nLeft ){
871 sbsWriteLineno(p, lnLeft, SBS_LNA);
872 p->iStart2 = p->iEnd2 = 0;
873 p->iStart = p->iEnd = -1;
874 sbsWriteText(p, pLeft, SBS_TXTA);
875 if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
876 sbsWriteMarker(p, " ", "");
877 }else{
878 sbsWriteMarker(p, " | ", "|");
879 }
880 sbsWriteLineno(p, lnRight, SBS_LNB);
881 p->iStart = nPrefix;
882 p->iEnd = nRight - nSuffix;
883 p->zStart = zClassAdd;
 
884 sbsWriteText(p, pRight, SBS_TXTB);
885 return;
886 }
887
888 /* A single chunk of text deleted from the left */
889 if( nPrefix+nSuffix==nRight ){
890 /* Text deleted from the left */
891 sbsWriteLineno(p, lnLeft, SBS_LNA);
892 p->iStart2 = p->iEnd2 = 0;
893 p->iStart = nPrefix;
894 p->iEnd = nLeft - nSuffix;
895 p->zStart = zClassRm;
896 sbsWriteText(p, pLeft, SBS_TXTA);
897 sbsWriteMarker(p, " | ", "|");
898 sbsWriteLineno(p, lnRight, SBS_LNB);
899 p->iStart = p->iEnd = -1;
 
900 sbsWriteText(p, pRight, SBS_TXTB);
901 return;
902 }
903
904 /* At this point we know that there is a chunk of text that has
@@ -911,51 +918,53 @@
911 && nLeftDiff >= 6
912 && nRightDiff >= 6
913 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
914 ){
915 sbsWriteLineno(p, lnLeft, SBS_LNA);
916 p->iStart = nPrefix;
917 p->iEnd = nPrefix + aLCS[0];
918 if( aLCS[2]==0 ){
919 sbsShiftLeft(p, pLeft->z);
920 p->zStart = zClassRm;
921 }else{
922 p->zStart = zClassChng;
923 }
924 p->iStart2 = nPrefix + aLCS[1];
925 p->iEnd2 = nLeft - nSuffix;
926 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
 
927 sbsSimplifyLine(p, zLeft);
928 sbsWriteText(p, pLeft, SBS_TXTA);
929 sbsWriteMarker(p, " | ", "|");
930 sbsWriteLineno(p, lnRight, SBS_LNB);
931 p->iStart = nPrefix;
932 p->iEnd = nPrefix + aLCS[2];
933 if( aLCS[0]==0 ){
934 sbsShiftLeft(p, pRight->z);
935 p->zStart = zClassAdd;
936 }else{
937 p->zStart = zClassChng;
938 }
939 p->iStart2 = nPrefix + aLCS[3];
940 p->iEnd2 = nRight - nSuffix;
941 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
 
942 sbsSimplifyLine(p, zRight);
943 sbsWriteText(p, pRight, SBS_TXTB);
944 return;
945 }
946
947 /* If all else fails, show a single big change between left and right */
948 sbsWriteLineno(p, lnLeft, SBS_LNA);
949 p->iStart2 = p->iEnd2 = 0;
950 p->iStart = nPrefix;
951 p->iEnd = nLeft - nSuffix;
952 p->zStart = zClassChng;
953 sbsWriteText(p, pLeft, SBS_TXTA);
954 sbsWriteMarker(p, " | ", "|");
955 sbsWriteLineno(p, lnRight, SBS_LNB);
956 p->iEnd = nRight - nSuffix;
957 sbsWriteText(p, pRight, SBS_TXTB);
958 }
959
960 /*
961 ** Minimum of two values
@@ -1224,13 +1233,13 @@
1224 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1225 s.apCols[i] = pOut;
1226 }
1227 }
1228 s.pRe = pRe;
1229 s.iStart = -1;
1230 s.iStart2 = 0;
1231 s.iEnd = -1;
1232 A = p->aFrom;
1233 B = p->aTo;
1234 R = p->aEdit;
1235 mxr = p->nEdit;
1236 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1316,11 +1325,12 @@
1316 a += skip;
1317 b += skip;
1318 m = R[r] - skip;
1319 for(j=0; j<m; j++){
1320 sbsWriteLineno(&s, a+j, SBS_LNA);
1321 s.iStart = s.iEnd = -1;
 
1322 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1323 sbsWriteMarker(&s, " ", "");
1324 sbsWriteLineno(&s, b+j, SBS_LNB);
1325 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1326 }
@@ -1346,13 +1356,14 @@
1346 alignment = sbsAlignment(&A[a], ma, &B[b], mb, diffFlags);
1347 for(j=0; ma+mb>0; j++){
1348 if( alignment[j]==1 ){
1349 /* Delete one line from the left */
1350 sbsWriteLineno(&s, a, SBS_LNA);
1351 s.iStart = 0;
1352 s.zStart = "<span class=\"diffrm\">";
1353 s.iEnd = LENGTH(&A[a]);
 
1354 sbsWriteText(&s, &A[a], SBS_TXTA);
1355 sbsWriteMarker(&s, " <", "&lt;");
1356 sbsWriteNewlines(&s);
1357 assert( ma>0 );
1358 ma--;
@@ -1370,29 +1381,32 @@
1370 if( !s.escHtml ){
1371 sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
1372 }
1373 sbsWriteMarker(&s, " > ", "&gt;");
1374 sbsWriteLineno(&s, b, SBS_LNB);
1375 s.iStart = 0;
1376 s.zStart = "<span class=\"diffadd\">";
1377 s.iEnd = LENGTH(&B[b]);
 
1378 sbsWriteText(&s, &B[b], SBS_TXTB);
1379 assert( mb>0 );
1380 mb--;
1381 b++;
1382 }else{
1383 /* Delete from the left and insert on the right */
1384 sbsWriteLineno(&s, a, SBS_LNA);
1385 s.iStart = 0;
1386 s.zStart = "<span class=\"diffrm\">";
1387 s.iEnd = LENGTH(&A[a]);
 
1388 sbsWriteText(&s, &A[a], SBS_TXTA);
1389 sbsWriteMarker(&s, " | ", "|");
1390 sbsWriteLineno(&s, b, SBS_LNB);
1391 s.iStart = 0;
1392 s.zStart = "<span class=\"diffadd\">";
1393 s.iEnd = LENGTH(&B[b]);
 
1394 sbsWriteText(&s, &B[b], SBS_TXTB);
1395 ma--;
1396 mb--;
1397 a++;
1398 b++;
@@ -1401,11 +1415,12 @@
1401 fossil_free(alignment);
1402 if( i<nr-1 ){
1403 m = R[r+i*3+3];
1404 for(j=0; j<m; j++){
1405 sbsWriteLineno(&s, a+j, SBS_LNA);
1406 s.iStart = s.iEnd = -1;
 
1407 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1408 sbsWriteMarker(&s, " ", "");
1409 sbsWriteLineno(&s, b+j, SBS_LNB);
1410 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1411 }
@@ -1418,11 +1433,12 @@
1418 assert( nr==i );
1419 m = R[r+nr*3];
1420 if( m>nContext ) m = nContext;
1421 for(j=0; j<m; j++){
1422 sbsWriteLineno(&s, a+j, SBS_LNA);
1423 s.iStart = s.iEnd = -1;
 
1424 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1425 sbsWriteMarker(&s, " ", "");
1426 sbsWriteLineno(&s, b+j, SBS_LNB);
1427 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1428 }
1429
--- src/diff.c
+++ src/diff.c
@@ -120,10 +120,16 @@
120 DLine *aTo; /* File on right side of the diff */
121 int nTo; /* Number of lines in aTo[] */
122 int (*xDiffer)(const DLine*,const DLine*); /* comparison function */
123 };
124
125 /* <span> text for change coloration
126 */
127 static const char zClassRm[] = "<span class=\"diffrm\">";
128 static const char zClassAdd[] = "<span class=\"diffadd\">";
129 static const char zClassChng[] = "<span class=\"diffchng\">";
130
131 /*
132 ** Count the number of lines in the input string. Include the last line
133 ** in the count even if it lacks the \n terminator. If an empty string
134 ** is specified, the number of lines is zero. For the purposes of this
135 ** function, a string is considered empty if it contains no characters
@@ -301,13 +307,13 @@
307 blob_append(pOut, &cPrefix, 1);
308 if( html ){
309 if( pRe && re_dline_match(pRe, pLine, 1)==0 ){
310 cPrefix = ' ';
311 }else if( cPrefix=='+' ){
312 blob_append(pOut, zClassAdd, -1);
313 }else if( cPrefix=='-' ){
314 blob_append(pOut, zClassRm, -1);
315 }
316 htmlize_to_blob(pOut, pLine->z, pLine->n);
317 if( cPrefix!=' ' ){
318 blob_append(pOut, "</span>", -1);
319 }
@@ -506,26 +512,32 @@
512 }
513 }
514 if( html ) blob_append(pOut, "</pre>\n", -1);
515 }
516
517 /*
518 ** Maximum number of change regions per line
519 */
520 #define SBS_MXN 4
521
522 /*
523 ** Status of a single output line
524 */
525 typedef struct SbsLine SbsLine;
526 struct SbsLine {
527 Blob *apCols[5]; /* Array of pointers to output columns */
528 int width; /* Maximum width of a column in the output */
529 unsigned char escHtml; /* True to escape html characters */
530 struct SbsMark {
531 int iStart; /* Write zTag prior to character iStart */
532 const char *zTag; /* A <span> tag for coloration */
533 int iEnd; /* Write </span> prior to character iEnd */
534 } a[SBS_MXN]; /* Change regions */
535 int n; /* Number of change regions used */
536 ReCompiled *pRe; /* Only colorize matching lines, if not NULL */
537 };
538
539
540 /*
541 ** Column indices for SbsLine.apCols[]
542 */
543 #define SBS_LNA 0 /* Left line number */
@@ -575,25 +587,23 @@
587 colorize = 0;
588 }
589 for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){
590 char c = zIn[i];
591 if( colorize ){
592 if( i==p->a[0].iStart ){
593 int x = strlen(p->a[0].zTag);
594 blob_append(pCol, p->a[0].zTag, x);
595 needEndSpan = 1;
596 }else if( i==p->a[0].iEnd ){
 
 
 
 
 
597 blob_append(pCol, "</span>", 7);
598 needEndSpan = 0;
599 if( p->n>1 ){
600 p->n--;
601 memmove(p->a, p->a+1, sizeof(p->a[0])*p->n);
602 }else{
603 p->a[0].iStart = -1;
604 p->a[0].iEnd = -1;
605 }
606 }
607 }
608 if( c=='\t' && !p->escHtml ){
609 blob_append(pCol, " ", 1);
@@ -739,19 +749,19 @@
749 }
750 return rc;
751 }
752
753 /*
754 ** Try to shift a[0].iStart as far as possible to the left.
755 */
756 static void sbsShiftLeft(SbsLine *p, const char *z){
757 int i, j;
758 while( (i=p->a[0].iStart)>0 && z[i-1]==z[i] ){
759 for(j=i+1; j<p->a[0].iEnd && z[j-1]==z[j]; j++){}
760 if( j<p->a[0].iEnd ) break;
761 p->a[0].iStart--;
762 p->a[0].iEnd--;
763 }
764 }
765
766 /*
767 ** Simplify iStart and iStart2:
@@ -760,28 +770,26 @@
770 ** * Make sure any null-changes are in canonoical form.
771 ** * Make sure all changes are at character boundaries for
772 ** multi-byte characters.
773 */
774 static void sbsSimplifyLine(SbsLine *p, const char *z){
775 int i, j;
776
777 /* Remove zero-length spans */
778 for(i=j=0; i<p->n; i++){
779 if( p->a[i].iStart<p->a[i].iEnd ){
780 if( j<i ) memcpy(p->a+j, p->a+i, sizeof(p->a[0]));
781 j++;
782 }
783 }
784 p->n = j;
785
786 /* Align all spans to a character boundary */
787 for(i=0; i<p->n; i++){
788 struct SbsMark *a = p->a+i;
789 while( a->iStart>0 && (z[a->iStart]&0xc0)==0x80 ) a->iStart--;
790 while( (z[a->iEnd]&0xc0)==0x80 ) a->iEnd++;
 
 
791 }
792 }
793
794 /*
795 ** Write out lines that have been edited. Adjust the highlight to cover
@@ -802,13 +810,10 @@
810 const char *zLeft; /* Text of the left line */
811 const char *zRight; /* Text of the right line */
812 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
813 int nRightDiff; /* nRight - nPrefix - nSuffix */
814 int aLCS[4]; /* Bounds of common middle segment */
 
 
 
815
816 nLeft = pLeft->n;
817 zLeft = pLeft->z;
818 nRight = pRight->n;
819 zRight = pRight->z;
@@ -867,38 +872,40 @@
872 }
873
874 /* A single chunk of text inserted on the right */
875 if( nPrefix+nSuffix==nLeft ){
876 sbsWriteLineno(p, lnLeft, SBS_LNA);
877 p->a[0].iStart = p->a[0].iEnd = -1;
878 p->n = 0;
879 sbsWriteText(p, pLeft, SBS_TXTA);
880 if( nLeft==nRight && zLeft[nLeft]==zRight[nRight] ){
881 sbsWriteMarker(p, " ", "");
882 }else{
883 sbsWriteMarker(p, " | ", "|");
884 }
885 sbsWriteLineno(p, lnRight, SBS_LNB);
886 p->a[0].iStart = nPrefix;
887 p->a[0].iEnd = nRight - nSuffix;
888 p->n = 1;
889 p->a[0].zTag = zClassAdd;
890 sbsWriteText(p, pRight, SBS_TXTB);
891 return;
892 }
893
894 /* A single chunk of text deleted from the left */
895 if( nPrefix+nSuffix==nRight ){
896 /* Text deleted from the left */
897 sbsWriteLineno(p, lnLeft, SBS_LNA);
898 p->a[0].iStart = nPrefix;
899 p->a[0].iEnd = nLeft - nSuffix;
900 p->a[0].zTag = zClassRm;
901 p->n = 1;
902 sbsWriteText(p, pLeft, SBS_TXTA);
903 sbsWriteMarker(p, " | ", "|");
904 sbsWriteLineno(p, lnRight, SBS_LNB);
905 p->a[0].iStart = p->a[0].iEnd = -1;
906 p->n = 0;
907 sbsWriteText(p, pRight, SBS_TXTB);
908 return;
909 }
910
911 /* At this point we know that there is a chunk of text that has
@@ -911,51 +918,53 @@
918 && nLeftDiff >= 6
919 && nRightDiff >= 6
920 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
921 ){
922 sbsWriteLineno(p, lnLeft, SBS_LNA);
923 p->a[0].iStart = nPrefix;
924 p->a[0].iEnd = nPrefix + aLCS[0];
925 if( aLCS[2]==0 ){
926 sbsShiftLeft(p, pLeft->z);
927 p->a[0].zTag = zClassRm;
928 }else{
929 p->a[0].zTag = zClassChng;
930 }
931 p->a[1].iStart = nPrefix + aLCS[1];
932 p->a[1].iEnd = nLeft - nSuffix;
933 p->a[1].zTag = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
934 p->n = 2;
935 sbsSimplifyLine(p, zLeft);
936 sbsWriteText(p, pLeft, SBS_TXTA);
937 sbsWriteMarker(p, " | ", "|");
938 sbsWriteLineno(p, lnRight, SBS_LNB);
939 p->a[0].iStart = nPrefix;
940 p->a[0].iEnd = nPrefix + aLCS[2];
941 if( aLCS[0]==0 ){
942 sbsShiftLeft(p, pRight->z);
943 p->a[0].zTag = zClassAdd;
944 }else{
945 p->a[0].zTag = zClassChng;
946 }
947 p->a[1].iStart = nPrefix + aLCS[3];
948 p->a[1].iEnd = nRight - nSuffix;
949 p->a[1].zTag = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
950 p->n = 2;
951 sbsSimplifyLine(p, zRight);
952 sbsWriteText(p, pRight, SBS_TXTB);
953 return;
954 }
955
956 /* If all else fails, show a single big change between left and right */
957 sbsWriteLineno(p, lnLeft, SBS_LNA);
958 p->a[0].iStart = nPrefix;
959 p->a[0].iEnd = nLeft - nSuffix;
960 p->a[0].zTag = zClassChng;
961 p->n = 1;
962 sbsWriteText(p, pLeft, SBS_TXTA);
963 sbsWriteMarker(p, " | ", "|");
964 sbsWriteLineno(p, lnRight, SBS_LNB);
965 p->a[0].iEnd = nRight - nSuffix;
966 sbsWriteText(p, pRight, SBS_TXTB);
967 }
968
969 /*
970 ** Minimum of two values
@@ -1224,13 +1233,13 @@
1233 for(i=SBS_LNA; i<=SBS_TXTB; i++){
1234 s.apCols[i] = pOut;
1235 }
1236 }
1237 s.pRe = pRe;
1238 s.a[0].iStart = -1;
1239 s.a[1].iStart = 0;
1240 s.a[0].iEnd = -1;
1241 A = p->aFrom;
1242 B = p->aTo;
1243 R = p->aEdit;
1244 mxr = p->nEdit;
1245 while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; }
@@ -1316,11 +1325,12 @@
1325 a += skip;
1326 b += skip;
1327 m = R[r] - skip;
1328 for(j=0; j<m; j++){
1329 sbsWriteLineno(&s, a+j, SBS_LNA);
1330 s.a[0].iStart = s.a[0].iEnd = -1;
1331 s.n = 1;
1332 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1333 sbsWriteMarker(&s, " ", "");
1334 sbsWriteLineno(&s, b+j, SBS_LNB);
1335 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1336 }
@@ -1346,13 +1356,14 @@
1356 alignment = sbsAlignment(&A[a], ma, &B[b], mb, diffFlags);
1357 for(j=0; ma+mb>0; j++){
1358 if( alignment[j]==1 ){
1359 /* Delete one line from the left */
1360 sbsWriteLineno(&s, a, SBS_LNA);
1361 s.a[0].iStart = 0;
1362 s.a[0].zTag = zClassRm;
1363 s.a[0].iEnd = LENGTH(&A[a]);
1364 s.n = 1;
1365 sbsWriteText(&s, &A[a], SBS_TXTA);
1366 sbsWriteMarker(&s, " <", "&lt;");
1367 sbsWriteNewlines(&s);
1368 assert( ma>0 );
1369 ma--;
@@ -1370,29 +1381,32 @@
1381 if( !s.escHtml ){
1382 sbsWriteSpace(&s, s.width + 7, SBS_TXTA);
1383 }
1384 sbsWriteMarker(&s, " > ", "&gt;");
1385 sbsWriteLineno(&s, b, SBS_LNB);
1386 s.a[0].iStart = 0;
1387 s.a[0].zTag = zClassAdd;
1388 s.a[0].iEnd = LENGTH(&B[b]);
1389 s.n = 1;
1390 sbsWriteText(&s, &B[b], SBS_TXTB);
1391 assert( mb>0 );
1392 mb--;
1393 b++;
1394 }else{
1395 /* Delete from the left and insert on the right */
1396 sbsWriteLineno(&s, a, SBS_LNA);
1397 s.a[0].iStart = 0;
1398 s.a[0].zTag = zClassRm;
1399 s.a[0].iEnd = LENGTH(&A[a]);
1400 s.n = 1;
1401 sbsWriteText(&s, &A[a], SBS_TXTA);
1402 sbsWriteMarker(&s, " | ", "|");
1403 sbsWriteLineno(&s, b, SBS_LNB);
1404 s.a[0].iStart = 0;
1405 s.a[0].zTag = zClassAdd;
1406 s.a[0].iEnd = LENGTH(&B[b]);
1407 s.n = 1;
1408 sbsWriteText(&s, &B[b], SBS_TXTB);
1409 ma--;
1410 mb--;
1411 a++;
1412 b++;
@@ -1401,11 +1415,12 @@
1415 fossil_free(alignment);
1416 if( i<nr-1 ){
1417 m = R[r+i*3+3];
1418 for(j=0; j<m; j++){
1419 sbsWriteLineno(&s, a+j, SBS_LNA);
1420 s.a[0].iStart = s.a[0].iEnd = -1;
1421 s.n = 0;
1422 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1423 sbsWriteMarker(&s, " ", "");
1424 sbsWriteLineno(&s, b+j, SBS_LNB);
1425 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1426 }
@@ -1418,11 +1433,12 @@
1433 assert( nr==i );
1434 m = R[r+nr*3];
1435 if( m>nContext ) m = nContext;
1436 for(j=0; j<m; j++){
1437 sbsWriteLineno(&s, a+j, SBS_LNA);
1438 s.a[0].iStart = s.a[0].iEnd = -1;
1439 s.n = 0;
1440 sbsWriteText(&s, &A[a+j], SBS_TXTA);
1441 sbsWriteMarker(&s, " ", "");
1442 sbsWriteLineno(&s, b+j, SBS_LNB);
1443 sbsWriteText(&s, &B[b+j], SBS_TXTB);
1444 }
1445

Keyboard Shortcuts

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