Fossil SCM
Side-by-side diff coloration now appears to be technically correct, though further improves are needed to optimize for human perception, and for performance.
Commit
6ed7541472c4052c5df6894f51e1fc00825fd9cea2368224b6935e9e95386a1f
Parent
4fea7cc0cab8d3d…
1 file changed
+9
-24
+9
-24
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -596,11 +596,11 @@ | ||
| 596 | 596 | int i; /* Number of input characters consumed */ |
| 597 | 597 | int k; /* Cursor position */ |
| 598 | 598 | int needEndSpan = 0; |
| 599 | 599 | const char *zIn = pLine->z; |
| 600 | 600 | int w = p->width; |
| 601 | - int colorize = p->escHtml; | |
| 601 | + int colorize = p->escHtml && p->n>0; | |
| 602 | 602 | if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){ |
| 603 | 603 | colorize = 0; |
| 604 | 604 | } |
| 605 | 605 | for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){ |
| 606 | 606 | char c = zIn[i]; |
| @@ -614,12 +614,11 @@ | ||
| 614 | 614 | needEndSpan = 0; |
| 615 | 615 | if( p->n>1 ){ |
| 616 | 616 | p->n--; |
| 617 | 617 | memmove(p->a, p->a+1, sizeof(p->a[0])*p->n); |
| 618 | 618 | }else{ |
| 619 | - p->a[0].iStart = -1; | |
| 620 | - p->a[0].iEnd = -1; | |
| 619 | + colorize = 0; | |
| 621 | 620 | } |
| 622 | 621 | } |
| 623 | 622 | } |
| 624 | 623 | if( c=='\t' && !p->escHtml ){ |
| 625 | 624 | blob_append(pCol, " ", 1); |
| @@ -721,20 +720,15 @@ | ||
| 721 | 720 | const unsigned char *zA = (const unsigned char*)zLeft; /* left string */ |
| 722 | 721 | const unsigned char *zB = (const unsigned char*)zRight; /* right string */ |
| 723 | 722 | int i, j, k; /* Loop counters */ |
| 724 | 723 | int lenBest = 0; /* Match length to beat */ |
| 725 | 724 | |
| 726 | -#if 0 | |
| 727 | - printf("testLCS(\"%.*s\",\"%.*s\") = ", | |
| 728 | - nA, zLeft, nB, zRight); | |
| 729 | -#endif | |
| 730 | - | |
| 731 | 725 | for(i=0; i<nA-lenBest; i++){ |
| 732 | 726 | unsigned char cA = zA[i]; |
| 733 | 727 | for(j=0; j<nB-lenBest; j++ ){ |
| 734 | 728 | if( zB[j]==cA ){ |
| 735 | - for(k=1; j+k<nB && zB[j+k]==zA[i+k]; k++){} | |
| 729 | + for(k=1; j+k<nB && i+k<nA && zB[j+k]==zA[i+k]; k++){} | |
| 736 | 730 | if( k>lenBest ){ |
| 737 | 731 | lenBest = k; |
| 738 | 732 | aLCS[0] = i; |
| 739 | 733 | aLCS[1] = i+k; |
| 740 | 734 | aLCS[2] = j; |
| @@ -741,23 +735,10 @@ | ||
| 741 | 735 | aLCS[3] = j+k; |
| 742 | 736 | } |
| 743 | 737 | } |
| 744 | 738 | } |
| 745 | 739 | } |
| 746 | -#if 0 | |
| 747 | - if( lenBest<=0 ){ | |
| 748 | - printf("no-match\n"); | |
| 749 | - }else{ | |
| 750 | - printf(" %d,%d,%d,%d\n", aLCS[0], aLCS[1], aLCS[2], aLCS[3]); | |
| 751 | - printf("%*s%.*s", 9+aLCS[0], "", aLCS[1]-aLCS[0], | |
| 752 | - "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); | |
| 753 | - printf("%*s%.*s\n", nA-aLCS[1]+3+aLCS[2], "", aLCS[3]-aLCS[2], | |
| 754 | - "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); | |
| 755 | - } | |
| 756 | - fflush(stdout); | |
| 757 | -#endif | |
| 758 | - | |
| 759 | 740 | return lenBest>0; |
| 760 | 741 | } |
| 761 | 742 | |
| 762 | 743 | /* |
| 763 | 744 | ** Find the smallest spans that different between two text strings that |
| @@ -985,11 +966,11 @@ | ||
| 985 | 966 | int i, j; |
| 986 | 967 | sbsWriteLineno(p, lnLeft, SBS_LNA); |
| 987 | 968 | for(i=j=0; i<CSpan.n; i++){ |
| 988 | 969 | if( CSpan.a[i].iLen1==0 ) continue; |
| 989 | 970 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart1; |
| 990 | - p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen1; | |
| 971 | + p->a[j].iEnd = p->a[j].iStart + CSpan.a[i].iLen1; | |
| 991 | 972 | if( CSpan.a[i].iLen2==0 ){ |
| 992 | 973 | if( i==0 ) sbsShiftLeft(p, zLeft); |
| 993 | 974 | p->a[j].zTag = zClassRm; |
| 994 | 975 | }else{ |
| 995 | 976 | p->a[j].zTag = zClassChng; |
| @@ -1002,11 +983,11 @@ | ||
| 1002 | 983 | sbsWriteMarker(p, " | ", "|"); |
| 1003 | 984 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1004 | 985 | for(i=j=0; i<CSpan.n; i++){ |
| 1005 | 986 | if( CSpan.a[i].iLen2==0 ) continue; |
| 1006 | 987 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart2; |
| 1007 | - p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen2; | |
| 988 | + p->a[j].iEnd = p->a[j].iStart + CSpan.a[i].iLen2; | |
| 1008 | 989 | if( CSpan.a[i].iLen1==0 ){ |
| 1009 | 990 | if( i==0 ) sbsShiftLeft(p, zRight); |
| 1010 | 991 | p->a[j].zTag = zClassAdd; |
| 1011 | 992 | }else{ |
| 1012 | 993 | p->a[j].zTag = zClassChng; |
| @@ -1026,11 +1007,14 @@ | ||
| 1026 | 1007 | p->a[0].zTag = zClassChng; |
| 1027 | 1008 | p->n = 1; |
| 1028 | 1009 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 1029 | 1010 | sbsWriteMarker(p, " | ", "|"); |
| 1030 | 1011 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1012 | + p->a[0].iStart = nPrefix; | |
| 1031 | 1013 | p->a[0].iEnd = nRight - nSuffix; |
| 1014 | + p->a[0].zTag = zClassChng; | |
| 1015 | + p->n = 1; | |
| 1032 | 1016 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1033 | 1017 | } |
| 1034 | 1018 | |
| 1035 | 1019 | /* |
| 1036 | 1020 | ** Minimum of two values |
| @@ -1302,10 +1286,11 @@ | ||
| 1302 | 1286 | } |
| 1303 | 1287 | s.pRe = pRe; |
| 1304 | 1288 | s.a[0].iStart = -1; |
| 1305 | 1289 | s.a[1].iStart = 0; |
| 1306 | 1290 | s.a[0].iEnd = -1; |
| 1291 | + s.n = 0; | |
| 1307 | 1292 | A = p->aFrom; |
| 1308 | 1293 | B = p->aTo; |
| 1309 | 1294 | R = p->aEdit; |
| 1310 | 1295 | mxr = p->nEdit; |
| 1311 | 1296 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| 1312 | 1297 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -596,11 +596,11 @@ | |
| 596 | int i; /* Number of input characters consumed */ |
| 597 | int k; /* Cursor position */ |
| 598 | int needEndSpan = 0; |
| 599 | const char *zIn = pLine->z; |
| 600 | int w = p->width; |
| 601 | int colorize = p->escHtml; |
| 602 | if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){ |
| 603 | colorize = 0; |
| 604 | } |
| 605 | for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){ |
| 606 | char c = zIn[i]; |
| @@ -614,12 +614,11 @@ | |
| 614 | needEndSpan = 0; |
| 615 | if( p->n>1 ){ |
| 616 | p->n--; |
| 617 | memmove(p->a, p->a+1, sizeof(p->a[0])*p->n); |
| 618 | }else{ |
| 619 | p->a[0].iStart = -1; |
| 620 | p->a[0].iEnd = -1; |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | if( c=='\t' && !p->escHtml ){ |
| 625 | blob_append(pCol, " ", 1); |
| @@ -721,20 +720,15 @@ | |
| 721 | const unsigned char *zA = (const unsigned char*)zLeft; /* left string */ |
| 722 | const unsigned char *zB = (const unsigned char*)zRight; /* right string */ |
| 723 | int i, j, k; /* Loop counters */ |
| 724 | int lenBest = 0; /* Match length to beat */ |
| 725 | |
| 726 | #if 0 |
| 727 | printf("testLCS(\"%.*s\",\"%.*s\") = ", |
| 728 | nA, zLeft, nB, zRight); |
| 729 | #endif |
| 730 | |
| 731 | for(i=0; i<nA-lenBest; i++){ |
| 732 | unsigned char cA = zA[i]; |
| 733 | for(j=0; j<nB-lenBest; j++ ){ |
| 734 | if( zB[j]==cA ){ |
| 735 | for(k=1; j+k<nB && zB[j+k]==zA[i+k]; k++){} |
| 736 | if( k>lenBest ){ |
| 737 | lenBest = k; |
| 738 | aLCS[0] = i; |
| 739 | aLCS[1] = i+k; |
| 740 | aLCS[2] = j; |
| @@ -741,23 +735,10 @@ | |
| 741 | aLCS[3] = j+k; |
| 742 | } |
| 743 | } |
| 744 | } |
| 745 | } |
| 746 | #if 0 |
| 747 | if( lenBest<=0 ){ |
| 748 | printf("no-match\n"); |
| 749 | }else{ |
| 750 | printf(" %d,%d,%d,%d\n", aLCS[0], aLCS[1], aLCS[2], aLCS[3]); |
| 751 | printf("%*s%.*s", 9+aLCS[0], "", aLCS[1]-aLCS[0], |
| 752 | "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); |
| 753 | printf("%*s%.*s\n", nA-aLCS[1]+3+aLCS[2], "", aLCS[3]-aLCS[2], |
| 754 | "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"); |
| 755 | } |
| 756 | fflush(stdout); |
| 757 | #endif |
| 758 | |
| 759 | return lenBest>0; |
| 760 | } |
| 761 | |
| 762 | /* |
| 763 | ** Find the smallest spans that different between two text strings that |
| @@ -985,11 +966,11 @@ | |
| 985 | int i, j; |
| 986 | sbsWriteLineno(p, lnLeft, SBS_LNA); |
| 987 | for(i=j=0; i<CSpan.n; i++){ |
| 988 | if( CSpan.a[i].iLen1==0 ) continue; |
| 989 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart1; |
| 990 | p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen1; |
| 991 | if( CSpan.a[i].iLen2==0 ){ |
| 992 | if( i==0 ) sbsShiftLeft(p, zLeft); |
| 993 | p->a[j].zTag = zClassRm; |
| 994 | }else{ |
| 995 | p->a[j].zTag = zClassChng; |
| @@ -1002,11 +983,11 @@ | |
| 1002 | sbsWriteMarker(p, " | ", "|"); |
| 1003 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1004 | for(i=j=0; i<CSpan.n; i++){ |
| 1005 | if( CSpan.a[i].iLen2==0 ) continue; |
| 1006 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart2; |
| 1007 | p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen2; |
| 1008 | if( CSpan.a[i].iLen1==0 ){ |
| 1009 | if( i==0 ) sbsShiftLeft(p, zRight); |
| 1010 | p->a[j].zTag = zClassAdd; |
| 1011 | }else{ |
| 1012 | p->a[j].zTag = zClassChng; |
| @@ -1026,11 +1007,14 @@ | |
| 1026 | p->a[0].zTag = zClassChng; |
| 1027 | p->n = 1; |
| 1028 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 1029 | sbsWriteMarker(p, " | ", "|"); |
| 1030 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1031 | p->a[0].iEnd = nRight - nSuffix; |
| 1032 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1033 | } |
| 1034 | |
| 1035 | /* |
| 1036 | ** Minimum of two values |
| @@ -1302,10 +1286,11 @@ | |
| 1302 | } |
| 1303 | s.pRe = pRe; |
| 1304 | s.a[0].iStart = -1; |
| 1305 | s.a[1].iStart = 0; |
| 1306 | s.a[0].iEnd = -1; |
| 1307 | A = p->aFrom; |
| 1308 | B = p->aTo; |
| 1309 | R = p->aEdit; |
| 1310 | mxr = p->nEdit; |
| 1311 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| 1312 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -596,11 +596,11 @@ | |
| 596 | int i; /* Number of input characters consumed */ |
| 597 | int k; /* Cursor position */ |
| 598 | int needEndSpan = 0; |
| 599 | const char *zIn = pLine->z; |
| 600 | int w = p->width; |
| 601 | int colorize = p->escHtml && p->n>0; |
| 602 | if( colorize && p->pRe && re_dline_match(p->pRe, pLine, 1)==0 ){ |
| 603 | colorize = 0; |
| 604 | } |
| 605 | for(i=k=0; (p->escHtml || k<w) && i<n; i++, k++){ |
| 606 | char c = zIn[i]; |
| @@ -614,12 +614,11 @@ | |
| 614 | needEndSpan = 0; |
| 615 | if( p->n>1 ){ |
| 616 | p->n--; |
| 617 | memmove(p->a, p->a+1, sizeof(p->a[0])*p->n); |
| 618 | }else{ |
| 619 | colorize = 0; |
| 620 | } |
| 621 | } |
| 622 | } |
| 623 | if( c=='\t' && !p->escHtml ){ |
| 624 | blob_append(pCol, " ", 1); |
| @@ -721,20 +720,15 @@ | |
| 720 | const unsigned char *zA = (const unsigned char*)zLeft; /* left string */ |
| 721 | const unsigned char *zB = (const unsigned char*)zRight; /* right string */ |
| 722 | int i, j, k; /* Loop counters */ |
| 723 | int lenBest = 0; /* Match length to beat */ |
| 724 | |
| 725 | for(i=0; i<nA-lenBest; i++){ |
| 726 | unsigned char cA = zA[i]; |
| 727 | for(j=0; j<nB-lenBest; j++ ){ |
| 728 | if( zB[j]==cA ){ |
| 729 | for(k=1; j+k<nB && i+k<nA && zB[j+k]==zA[i+k]; k++){} |
| 730 | if( k>lenBest ){ |
| 731 | lenBest = k; |
| 732 | aLCS[0] = i; |
| 733 | aLCS[1] = i+k; |
| 734 | aLCS[2] = j; |
| @@ -741,23 +735,10 @@ | |
| 735 | aLCS[3] = j+k; |
| 736 | } |
| 737 | } |
| 738 | } |
| 739 | } |
| 740 | return lenBest>0; |
| 741 | } |
| 742 | |
| 743 | /* |
| 744 | ** Find the smallest spans that different between two text strings that |
| @@ -985,11 +966,11 @@ | |
| 966 | int i, j; |
| 967 | sbsWriteLineno(p, lnLeft, SBS_LNA); |
| 968 | for(i=j=0; i<CSpan.n; i++){ |
| 969 | if( CSpan.a[i].iLen1==0 ) continue; |
| 970 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart1; |
| 971 | p->a[j].iEnd = p->a[j].iStart + CSpan.a[i].iLen1; |
| 972 | if( CSpan.a[i].iLen2==0 ){ |
| 973 | if( i==0 ) sbsShiftLeft(p, zLeft); |
| 974 | p->a[j].zTag = zClassRm; |
| 975 | }else{ |
| 976 | p->a[j].zTag = zClassChng; |
| @@ -1002,11 +983,11 @@ | |
| 983 | sbsWriteMarker(p, " | ", "|"); |
| 984 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 985 | for(i=j=0; i<CSpan.n; i++){ |
| 986 | if( CSpan.a[i].iLen2==0 ) continue; |
| 987 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart2; |
| 988 | p->a[j].iEnd = p->a[j].iStart + CSpan.a[i].iLen2; |
| 989 | if( CSpan.a[i].iLen1==0 ){ |
| 990 | if( i==0 ) sbsShiftLeft(p, zRight); |
| 991 | p->a[j].zTag = zClassAdd; |
| 992 | }else{ |
| 993 | p->a[j].zTag = zClassChng; |
| @@ -1026,11 +1007,14 @@ | |
| 1007 | p->a[0].zTag = zClassChng; |
| 1008 | p->n = 1; |
| 1009 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 1010 | sbsWriteMarker(p, " | ", "|"); |
| 1011 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1012 | p->a[0].iStart = nPrefix; |
| 1013 | p->a[0].iEnd = nRight - nSuffix; |
| 1014 | p->a[0].zTag = zClassChng; |
| 1015 | p->n = 1; |
| 1016 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1017 | } |
| 1018 | |
| 1019 | /* |
| 1020 | ** Minimum of two values |
| @@ -1302,10 +1286,11 @@ | |
| 1286 | } |
| 1287 | s.pRe = pRe; |
| 1288 | s.a[0].iStart = -1; |
| 1289 | s.a[1].iStart = 0; |
| 1290 | s.a[0].iEnd = -1; |
| 1291 | s.n = 0; |
| 1292 | A = p->aFrom; |
| 1293 | B = p->aTo; |
| 1294 | R = p->aEdit; |
| 1295 | mxr = p->nEdit; |
| 1296 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| 1297 |