Fossil SCM
Coloring on side-by-side diffs allows up to 8 separate segments of change. Incremental check-in - not everything is working correctly.
Commit
925399da07045aa4bdd29f764150af55c841ef94dc6fc6e42243c79a5073ae0d
Parent
8c619bf2782e955…
2 files changed
+105
-32
+4
-1
+105
-32
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -513,13 +513,14 @@ | ||
| 513 | 513 | } |
| 514 | 514 | if( html ) blob_append(pOut, "</pre>\n", -1); |
| 515 | 515 | } |
| 516 | 516 | |
| 517 | 517 | /* |
| 518 | -** Maximum number of change regions per line | |
| 518 | +** Limits for the intra-line diffing. | |
| 519 | 519 | */ |
| 520 | -#define SBS_MXN 4 | |
| 520 | +#define SBS_MXN 8 /* Maximum number of change regions per line of text */ | |
| 521 | +#define SBS_CSN 8 /* Maximum number of change spans across a change region */ | |
| 521 | 522 | |
| 522 | 523 | /* |
| 523 | 524 | ** Status of a single output line |
| 524 | 525 | */ |
| 525 | 526 | typedef struct SbsLine SbsLine; |
| @@ -527,17 +528,32 @@ | ||
| 527 | 528 | Blob *apCols[5]; /* Array of pointers to output columns */ |
| 528 | 529 | int width; /* Maximum width of a column in the output */ |
| 529 | 530 | unsigned char escHtml; /* True to escape html characters */ |
| 530 | 531 | struct SbsMark { |
| 531 | 532 | int iStart; /* Write zTag prior to character iStart */ |
| 532 | - const char *zTag; /* A <span> tag for coloration */ | |
| 533 | 533 | int iEnd; /* Write </span> prior to character iEnd */ |
| 534 | + const char *zTag; /* A <span> tag for coloration */ | |
| 534 | 535 | } a[SBS_MXN]; /* Change regions */ |
| 535 | 536 | int n; /* Number of change regions used */ |
| 536 | 537 | ReCompiled *pRe; /* Only colorize matching lines, if not NULL */ |
| 537 | 538 | }; |
| 538 | 539 | |
| 540 | +/* | |
| 541 | +** A description of zero or more (up to SBS_CSN) areas of commonality | |
| 542 | +** between two lines of text. | |
| 543 | +*/ | |
| 544 | +typedef struct ChangeSpan ChangeSpan; | |
| 545 | +struct ChangeSpan { | |
| 546 | + int n; /* Number of change spans */ | |
| 547 | + struct Span { | |
| 548 | + int iStart1; /* Byte offset to start of change on the left */ | |
| 549 | + int iLen1; /* Length of left change span in bytes */ | |
| 550 | + int iStart2; /* Byte offset to start of change span on the right */ | |
| 551 | + int iLen2; /* Length of right change span in bytes */ | |
| 552 | + int isMin; /* True if this span is known to have no useful subdivs */ | |
| 553 | + } a[SBS_CSN]; /* Array of change spans, sorted order */ | |
| 554 | +}; | |
| 539 | 555 | |
| 540 | 556 | /* |
| 541 | 557 | ** Column indices for SbsLine.apCols[] |
| 542 | 558 | */ |
| 543 | 559 | #define SBS_LNA 0 /* Left line number */ |
| @@ -747,10 +763,64 @@ | ||
| 747 | 763 | } |
| 748 | 764 | } |
| 749 | 765 | } |
| 750 | 766 | return rc; |
| 751 | 767 | } |
| 768 | + | |
| 769 | +/* | |
| 770 | +** Find the smallest spans that different between two text strings that | |
| 771 | +** are known to be different on both ends. | |
| 772 | +*/ | |
| 773 | +static int textChangeSpans( | |
| 774 | + const char *zLeft, int nA, /* String on the left */ | |
| 775 | + const char *zRight, int nB, /* String on the right */ | |
| 776 | + ChangeSpan *p /* Write results here */ | |
| 777 | +){ | |
| 778 | + p->n = 1; | |
| 779 | + p->a[0].iStart1 = 0; | |
| 780 | + p->a[0].iLen1 = nA; | |
| 781 | + p->a[0].iStart2 = 0; | |
| 782 | + p->a[0].iLen2 = nB; | |
| 783 | + p->a[0].isMin = 0; | |
| 784 | + while( p->n<SBS_CSN ){ | |
| 785 | + int mxi = -1; | |
| 786 | + int mxLen = -1; | |
| 787 | + int x, i; | |
| 788 | + int aLCS[4]; | |
| 789 | + struct Span *a, *b; | |
| 790 | + for(i=0; i<p->n; i++){ | |
| 791 | + if( p->a[i].isMin ) continue; | |
| 792 | + x = p->a[i].iLen1; | |
| 793 | + if( p->a[i].iLen2<x ) x = p->a[i].iLen2; | |
| 794 | + if( x>mxLen ){ | |
| 795 | + mxLen = x; | |
| 796 | + mxi = i; | |
| 797 | + } | |
| 798 | + } | |
| 799 | + if( mxLen<6 ) break; | |
| 800 | + x = textLCS(zLeft + p->a[mxi].iStart1, p->a[mxi].iLen1, | |
| 801 | + zRight + p->a[mxi].iStart2, p->a[mxi].iLen2, aLCS); | |
| 802 | + if( x==0 ){ | |
| 803 | + p->a[mxi].isMin = 1; | |
| 804 | + continue; | |
| 805 | + } | |
| 806 | + a = p->a+mxi; | |
| 807 | + b = a+1; | |
| 808 | + if( mxi<p->n-1 ){ | |
| 809 | + memmove(b+1, b, sizeof(*b)*(p->n-mxi-1)); | |
| 810 | + } | |
| 811 | + p->n++; | |
| 812 | + b->iStart1 = a->iStart1 + aLCS[1]; | |
| 813 | + b->iLen1 = a->iLen1 - aLCS[1]; | |
| 814 | + a->iLen1 = aLCS[0]; | |
| 815 | + b->iStart2 = a->iStart2 + aLCS[3]; | |
| 816 | + b->iLen2 = a->iLen2 - aLCS[3]; | |
| 817 | + a->iLen2 = aLCS[2]; | |
| 818 | + b->isMin = 0; | |
| 819 | + } | |
| 820 | + return p->n; | |
| 821 | +} | |
| 752 | 822 | |
| 753 | 823 | /* |
| 754 | 824 | ** Try to shift a[0].iStart as far as possible to the left. |
| 755 | 825 | */ |
| 756 | 826 | static void sbsShiftLeft(SbsLine *p, const char *z){ |
| @@ -762,14 +832,13 @@ | ||
| 762 | 832 | p->a[0].iEnd--; |
| 763 | 833 | } |
| 764 | 834 | } |
| 765 | 835 | |
| 766 | 836 | /* |
| 767 | -** Simplify iStart and iStart2: | |
| 837 | +** Simplify the diff-marks in a single line. | |
| 768 | 838 | ** |
| 769 | -** * If iStart is a null-change then move iStart2 into iStart | |
| 770 | -** * Make sure any null-changes are in canonoical form. | |
| 839 | +** * Remove any null (zero-length) diff marks. | |
| 771 | 840 | ** * Make sure all changes are at character boundaries for |
| 772 | 841 | ** multi-byte characters. |
| 773 | 842 | */ |
| 774 | 843 | static void sbsSimplifyLine(SbsLine *p, const char *z){ |
| 775 | 844 | int i, j; |
| @@ -809,11 +878,11 @@ | ||
| 809 | 878 | int nSuffix; /* Length of common suffix */ |
| 810 | 879 | const char *zLeft; /* Text of the left line */ |
| 811 | 880 | const char *zRight; /* Text of the right line */ |
| 812 | 881 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ |
| 813 | 882 | int nRightDiff; /* nRight - nPrefix - nSuffix */ |
| 814 | - int aLCS[4]; /* Bounds of common middle segment */ | |
| 883 | + ChangeSpan CSpan; /* Set of changes on a line */ | |
| 815 | 884 | |
| 816 | 885 | nLeft = pLeft->n; |
| 817 | 886 | zLeft = pLeft->z; |
| 818 | 887 | nRight = pRight->n; |
| 819 | 888 | zRight = pRight->z; |
| @@ -915,41 +984,45 @@ | ||
| 915 | 984 | nLeftDiff = nLeft - nSuffix - nPrefix; |
| 916 | 985 | nRightDiff = nRight - nSuffix - nPrefix; |
| 917 | 986 | if( p->escHtml |
| 918 | 987 | && nLeftDiff >= 6 |
| 919 | 988 | && nRightDiff >= 6 |
| 920 | - && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS) | |
| 989 | + && textChangeSpans(&zLeft[nPrefix], nLeftDiff, | |
| 990 | + &zRight[nPrefix], nRightDiff, &CSpan)>1 | |
| 921 | 991 | ){ |
| 992 | + int i, j; | |
| 922 | 993 | 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; | |
| 994 | + for(i=j=0; i<CSpan.n; i++){ | |
| 995 | + if( CSpan.a[i].iLen1==0 ) continue; | |
| 996 | + p->a[j].iStart = nPrefix + CSpan.a[i].iStart1; | |
| 997 | + p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen1; | |
| 998 | + if( CSpan.a[i].iLen2==0 ){ | |
| 999 | + if( i==0 ) sbsShiftLeft(p, zLeft); | |
| 1000 | + p->a[j].zTag = zClassRm; | |
| 1001 | + }else{ | |
| 1002 | + p->a[j].zTag = zClassChng; | |
| 1003 | + } | |
| 1004 | + j++; | |
| 1005 | + } | |
| 1006 | + p->n = j; | |
| 935 | 1007 | sbsSimplifyLine(p, zLeft); |
| 936 | 1008 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 937 | 1009 | sbsWriteMarker(p, " | ", "|"); |
| 938 | 1010 | 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; | |
| 1011 | + for(i=j=0; i<CSpan.n; i++){ | |
| 1012 | + if( CSpan.a[i].iLen2==0 ) continue; | |
| 1013 | + p->a[j].iStart = nPrefix + CSpan.a[i].iStart2; | |
| 1014 | + p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen2; | |
| 1015 | + if( CSpan.a[i].iLen1==0 ){ | |
| 1016 | + if( i==0 ) sbsShiftLeft(p, zRight); | |
| 1017 | + p->a[j].zTag = zClassAdd; | |
| 1018 | + }else{ | |
| 1019 | + p->a[j].zTag = zClassChng; | |
| 1020 | + } | |
| 1021 | + j++; | |
| 1022 | + } | |
| 1023 | + p->n = j; | |
| 951 | 1024 | sbsSimplifyLine(p, zRight); |
| 952 | 1025 | sbsWriteText(p, pRight, SBS_TXTB); |
| 953 | 1026 | return; |
| 954 | 1027 | } |
| 955 | 1028 | |
| 956 | 1029 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -513,13 +513,14 @@ | |
| 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; |
| @@ -527,17 +528,32 @@ | |
| 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 */ |
| @@ -747,10 +763,64 @@ | |
| 747 | } |
| 748 | } |
| 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){ |
| @@ -762,14 +832,13 @@ | |
| 762 | p->a[0].iEnd--; |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | /* |
| 767 | ** Simplify iStart and iStart2: |
| 768 | ** |
| 769 | ** * If iStart is a null-change then move iStart2 into iStart |
| 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; |
| @@ -809,11 +878,11 @@ | |
| 809 | int nSuffix; /* Length of common suffix */ |
| 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; |
| @@ -915,41 +984,45 @@ | |
| 915 | nLeftDiff = nLeft - nSuffix - nPrefix; |
| 916 | nRightDiff = nRight - nSuffix - nPrefix; |
| 917 | if( p->escHtml |
| 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 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -513,13 +513,14 @@ | |
| 513 | } |
| 514 | if( html ) blob_append(pOut, "</pre>\n", -1); |
| 515 | } |
| 516 | |
| 517 | /* |
| 518 | ** Limits for the intra-line diffing. |
| 519 | */ |
| 520 | #define SBS_MXN 8 /* Maximum number of change regions per line of text */ |
| 521 | #define SBS_CSN 8 /* Maximum number of change spans across a change region */ |
| 522 | |
| 523 | /* |
| 524 | ** Status of a single output line |
| 525 | */ |
| 526 | typedef struct SbsLine SbsLine; |
| @@ -527,17 +528,32 @@ | |
| 528 | Blob *apCols[5]; /* Array of pointers to output columns */ |
| 529 | int width; /* Maximum width of a column in the output */ |
| 530 | unsigned char escHtml; /* True to escape html characters */ |
| 531 | struct SbsMark { |
| 532 | int iStart; /* Write zTag prior to character iStart */ |
| 533 | int iEnd; /* Write </span> prior to character iEnd */ |
| 534 | const char *zTag; /* A <span> tag for coloration */ |
| 535 | } a[SBS_MXN]; /* Change regions */ |
| 536 | int n; /* Number of change regions used */ |
| 537 | ReCompiled *pRe; /* Only colorize matching lines, if not NULL */ |
| 538 | }; |
| 539 | |
| 540 | /* |
| 541 | ** A description of zero or more (up to SBS_CSN) areas of commonality |
| 542 | ** between two lines of text. |
| 543 | */ |
| 544 | typedef struct ChangeSpan ChangeSpan; |
| 545 | struct ChangeSpan { |
| 546 | int n; /* Number of change spans */ |
| 547 | struct Span { |
| 548 | int iStart1; /* Byte offset to start of change on the left */ |
| 549 | int iLen1; /* Length of left change span in bytes */ |
| 550 | int iStart2; /* Byte offset to start of change span on the right */ |
| 551 | int iLen2; /* Length of right change span in bytes */ |
| 552 | int isMin; /* True if this span is known to have no useful subdivs */ |
| 553 | } a[SBS_CSN]; /* Array of change spans, sorted order */ |
| 554 | }; |
| 555 | |
| 556 | /* |
| 557 | ** Column indices for SbsLine.apCols[] |
| 558 | */ |
| 559 | #define SBS_LNA 0 /* Left line number */ |
| @@ -747,10 +763,64 @@ | |
| 763 | } |
| 764 | } |
| 765 | } |
| 766 | return rc; |
| 767 | } |
| 768 | |
| 769 | /* |
| 770 | ** Find the smallest spans that different between two text strings that |
| 771 | ** are known to be different on both ends. |
| 772 | */ |
| 773 | static int textChangeSpans( |
| 774 | const char *zLeft, int nA, /* String on the left */ |
| 775 | const char *zRight, int nB, /* String on the right */ |
| 776 | ChangeSpan *p /* Write results here */ |
| 777 | ){ |
| 778 | p->n = 1; |
| 779 | p->a[0].iStart1 = 0; |
| 780 | p->a[0].iLen1 = nA; |
| 781 | p->a[0].iStart2 = 0; |
| 782 | p->a[0].iLen2 = nB; |
| 783 | p->a[0].isMin = 0; |
| 784 | while( p->n<SBS_CSN ){ |
| 785 | int mxi = -1; |
| 786 | int mxLen = -1; |
| 787 | int x, i; |
| 788 | int aLCS[4]; |
| 789 | struct Span *a, *b; |
| 790 | for(i=0; i<p->n; i++){ |
| 791 | if( p->a[i].isMin ) continue; |
| 792 | x = p->a[i].iLen1; |
| 793 | if( p->a[i].iLen2<x ) x = p->a[i].iLen2; |
| 794 | if( x>mxLen ){ |
| 795 | mxLen = x; |
| 796 | mxi = i; |
| 797 | } |
| 798 | } |
| 799 | if( mxLen<6 ) break; |
| 800 | x = textLCS(zLeft + p->a[mxi].iStart1, p->a[mxi].iLen1, |
| 801 | zRight + p->a[mxi].iStart2, p->a[mxi].iLen2, aLCS); |
| 802 | if( x==0 ){ |
| 803 | p->a[mxi].isMin = 1; |
| 804 | continue; |
| 805 | } |
| 806 | a = p->a+mxi; |
| 807 | b = a+1; |
| 808 | if( mxi<p->n-1 ){ |
| 809 | memmove(b+1, b, sizeof(*b)*(p->n-mxi-1)); |
| 810 | } |
| 811 | p->n++; |
| 812 | b->iStart1 = a->iStart1 + aLCS[1]; |
| 813 | b->iLen1 = a->iLen1 - aLCS[1]; |
| 814 | a->iLen1 = aLCS[0]; |
| 815 | b->iStart2 = a->iStart2 + aLCS[3]; |
| 816 | b->iLen2 = a->iLen2 - aLCS[3]; |
| 817 | a->iLen2 = aLCS[2]; |
| 818 | b->isMin = 0; |
| 819 | } |
| 820 | return p->n; |
| 821 | } |
| 822 | |
| 823 | /* |
| 824 | ** Try to shift a[0].iStart as far as possible to the left. |
| 825 | */ |
| 826 | static void sbsShiftLeft(SbsLine *p, const char *z){ |
| @@ -762,14 +832,13 @@ | |
| 832 | p->a[0].iEnd--; |
| 833 | } |
| 834 | } |
| 835 | |
| 836 | /* |
| 837 | ** Simplify the diff-marks in a single line. |
| 838 | ** |
| 839 | ** * Remove any null (zero-length) diff marks. |
| 840 | ** * Make sure all changes are at character boundaries for |
| 841 | ** multi-byte characters. |
| 842 | */ |
| 843 | static void sbsSimplifyLine(SbsLine *p, const char *z){ |
| 844 | int i, j; |
| @@ -809,11 +878,11 @@ | |
| 878 | int nSuffix; /* Length of common suffix */ |
| 879 | const char *zLeft; /* Text of the left line */ |
| 880 | const char *zRight; /* Text of the right line */ |
| 881 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ |
| 882 | int nRightDiff; /* nRight - nPrefix - nSuffix */ |
| 883 | ChangeSpan CSpan; /* Set of changes on a line */ |
| 884 | |
| 885 | nLeft = pLeft->n; |
| 886 | zLeft = pLeft->z; |
| 887 | nRight = pRight->n; |
| 888 | zRight = pRight->z; |
| @@ -915,41 +984,45 @@ | |
| 984 | nLeftDiff = nLeft - nSuffix - nPrefix; |
| 985 | nRightDiff = nRight - nSuffix - nPrefix; |
| 986 | if( p->escHtml |
| 987 | && nLeftDiff >= 6 |
| 988 | && nRightDiff >= 6 |
| 989 | && textChangeSpans(&zLeft[nPrefix], nLeftDiff, |
| 990 | &zRight[nPrefix], nRightDiff, &CSpan)>1 |
| 991 | ){ |
| 992 | int i, j; |
| 993 | sbsWriteLineno(p, lnLeft, SBS_LNA); |
| 994 | for(i=j=0; i<CSpan.n; i++){ |
| 995 | if( CSpan.a[i].iLen1==0 ) continue; |
| 996 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart1; |
| 997 | p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen1; |
| 998 | if( CSpan.a[i].iLen2==0 ){ |
| 999 | if( i==0 ) sbsShiftLeft(p, zLeft); |
| 1000 | p->a[j].zTag = zClassRm; |
| 1001 | }else{ |
| 1002 | p->a[j].zTag = zClassChng; |
| 1003 | } |
| 1004 | j++; |
| 1005 | } |
| 1006 | p->n = j; |
| 1007 | sbsSimplifyLine(p, zLeft); |
| 1008 | sbsWriteText(p, pLeft, SBS_TXTA); |
| 1009 | sbsWriteMarker(p, " | ", "|"); |
| 1010 | sbsWriteLineno(p, lnRight, SBS_LNB); |
| 1011 | for(i=j=0; i<CSpan.n; i++){ |
| 1012 | if( CSpan.a[i].iLen2==0 ) continue; |
| 1013 | p->a[j].iStart = nPrefix + CSpan.a[i].iStart2; |
| 1014 | p->a[j].iEnd = p->a[i].iStart + CSpan.a[i].iLen2; |
| 1015 | if( CSpan.a[i].iLen1==0 ){ |
| 1016 | if( i==0 ) sbsShiftLeft(p, zRight); |
| 1017 | p->a[j].zTag = zClassAdd; |
| 1018 | }else{ |
| 1019 | p->a[j].zTag = zClassChng; |
| 1020 | } |
| 1021 | j++; |
| 1022 | } |
| 1023 | p->n = j; |
| 1024 | sbsSimplifyLine(p, zRight); |
| 1025 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1026 | return; |
| 1027 | } |
| 1028 | |
| 1029 |
+4
-1
| --- test/diff-test-1.wiki | ||
| +++ test/diff-test-1.wiki | ||
| @@ -20,11 +20,14 @@ | ||
| 20 | 20 | The edit of a line with multibyte characters is the first chunk. |
| 21 | 21 | * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6" |
| 22 | 22 | target="testwindow">Large diff of sqlite3.c</a>. This diff was very |
| 23 | 23 | slow prior to the performance enhancement change [9e15437e97]. |
| 24 | 24 | * <a href="../../../info/bda00cbada#chunk49" target="testwindow"> |
| 25 | - A difficult indentation change.</a> | |
| 25 | + A difficult indentation change.</a> UPDATE: Notice also the improved | |
| 26 | + multi-segment update marks on lines 122648 and 122763 on the new side. | |
| 27 | + * <a href="../../../fdiff?v1=bc8100c9ee01b8c2&v2=1d2acc1a2a65c2bf#chunk42" | |
| 28 | + target="testwindow">Inverse of the previous.</a> | |
| 26 | 29 | * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13" |
| 27 | 30 | target="testwindow">Another tricky indentation.</a> Notice especially |
| 28 | 31 | lines 59398 and 59407 on the left. |
| 29 | 32 | * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13" |
| 30 | 33 | target="testwindow">Inverse of the previous.</a> |
| 31 | 34 |
| --- test/diff-test-1.wiki | |
| +++ test/diff-test-1.wiki | |
| @@ -20,11 +20,14 @@ | |
| 20 | The edit of a line with multibyte characters is the first chunk. |
| 21 | * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6" |
| 22 | target="testwindow">Large diff of sqlite3.c</a>. This diff was very |
| 23 | slow prior to the performance enhancement change [9e15437e97]. |
| 24 | * <a href="../../../info/bda00cbada#chunk49" target="testwindow"> |
| 25 | A difficult indentation change.</a> |
| 26 | * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13" |
| 27 | target="testwindow">Another tricky indentation.</a> Notice especially |
| 28 | lines 59398 and 59407 on the left. |
| 29 | * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13" |
| 30 | target="testwindow">Inverse of the previous.</a> |
| 31 |
| --- test/diff-test-1.wiki | |
| +++ test/diff-test-1.wiki | |
| @@ -20,11 +20,14 @@ | |
| 20 | The edit of a line with multibyte characters is the first chunk. |
| 21 | * <a href="../../../fdiff?v1=57b0d8183cab0e3d&v2=37b3ef49d73cdfe6" |
| 22 | target="testwindow">Large diff of sqlite3.c</a>. This diff was very |
| 23 | slow prior to the performance enhancement change [9e15437e97]. |
| 24 | * <a href="../../../info/bda00cbada#chunk49" target="testwindow"> |
| 25 | A difficult indentation change.</a> UPDATE: Notice also the improved |
| 26 | multi-segment update marks on lines 122648 and 122763 on the new side. |
| 27 | * <a href="../../../fdiff?v1=bc8100c9ee01b8c2&v2=1d2acc1a2a65c2bf#chunk42" |
| 28 | target="testwindow">Inverse of the previous.</a> |
| 29 | * <a href="../../../fdiff?v1=955cc67ace8fb622&v2=e2e1c87b86664b45#chunk13" |
| 30 | target="testwindow">Another tricky indentation.</a> Notice especially |
| 31 | lines 59398 and 59407 on the left. |
| 32 | * <a href="../../../fdiff?v2=955cc67ace8fb622&v1=e2e1c87b86664b45#chunk13" |
| 33 | target="testwindow">Inverse of the previous.</a> |
| 34 |