Fossil SCM
In the "diff --debug" output show the regions of change.
Commit
4b8f203f5dece0e7452569869d2fa6f8eb8eba86f8747cfaaa52281fbb3a2736
Parent
16a2364f3670205…
1 file changed
+162
-7
+162
-7
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -744,11 +744,11 @@ | ||
| 744 | 744 | } |
| 745 | 745 | return lenBest>0; |
| 746 | 746 | } |
| 747 | 747 | |
| 748 | 748 | /* |
| 749 | -** Find the smallest spans that different between two text strings that | |
| 749 | +** Find the smallest spans that are different between two text strings that | |
| 750 | 750 | ** are known to be different on both ends. |
| 751 | 751 | */ |
| 752 | 752 | static int textChangeSpans( |
| 753 | 753 | const char *zLeft, int nA, /* String on the left */ |
| 754 | 754 | const char *zRight, int nB, /* String on the right */ |
| @@ -1018,10 +1018,140 @@ | ||
| 1018 | 1018 | p->a[0].iEnd = nRight - nSuffix; |
| 1019 | 1019 | p->a[0].zTag = zClassChng; |
| 1020 | 1020 | p->n = 1; |
| 1021 | 1021 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1022 | 1022 | } |
| 1023 | + | |
| 1024 | +/* | |
| 1025 | +** Given two lines of text, pFrom and pTo, compute a set of changes | |
| 1026 | +** between those two lines, for enhanced display purposes. | |
| 1027 | +** | |
| 1028 | +** The result is written into the ChangeSpan object given by the | |
| 1029 | +** third parameter. | |
| 1030 | +*/ | |
| 1031 | +static void oneLineChange( | |
| 1032 | + const DLine *pLeft, /* Left line of the change */ | |
| 1033 | + const DLine *pRight, /* Right line of the change */ | |
| 1034 | + ChangeSpan *p /* OUTPUT: Write the results here */ | |
| 1035 | +){ | |
| 1036 | + int nLeft; /* Length of left line in bytes */ | |
| 1037 | + int nRight; /* Length of right line in bytes */ | |
| 1038 | + int nShort; /* Shortest of left and right */ | |
| 1039 | + int nPrefix; /* Length of common prefix */ | |
| 1040 | + int nSuffix; /* Length of common suffix */ | |
| 1041 | + int nCommon; /* Total byte length of suffix and prefix */ | |
| 1042 | + const char *zLeft; /* Text of the left line */ | |
| 1043 | + const char *zRight; /* Text of the right line */ | |
| 1044 | + int nLeftDiff; /* nLeft - nPrefix - nSuffix */ | |
| 1045 | + int nRightDiff; /* nRight - nPrefix - nSuffix */ | |
| 1046 | + | |
| 1047 | + nLeft = pLeft->n; | |
| 1048 | + zLeft = pLeft->z; | |
| 1049 | + nRight = pRight->n; | |
| 1050 | + zRight = pRight->z; | |
| 1051 | + nShort = nLeft<nRight ? nLeft : nRight; | |
| 1052 | + | |
| 1053 | + nPrefix = 0; | |
| 1054 | + while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 1055 | + nPrefix++; | |
| 1056 | + } | |
| 1057 | + if( nPrefix<nShort ){ | |
| 1058 | + while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; | |
| 1059 | + } | |
| 1060 | + nSuffix = 0; | |
| 1061 | + if( nPrefix<nShort ){ | |
| 1062 | + while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ | |
| 1063 | + nSuffix++; | |
| 1064 | + } | |
| 1065 | + if( nSuffix<nShort ){ | |
| 1066 | + while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; | |
| 1067 | + } | |
| 1068 | + if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; | |
| 1069 | + } | |
| 1070 | + nCommon = nPrefix + nSuffix; | |
| 1071 | + | |
| 1072 | + /* If the prefix and suffix overlap, that means that we are dealing with | |
| 1073 | + ** a pure insertion or deletion of text that can have multiple alignments. | |
| 1074 | + ** Try to find an alignment to begins and ends on whitespace, or on | |
| 1075 | + ** punctuation, rather than in the middle of a name or number. | |
| 1076 | + */ | |
| 1077 | + if( nCommon > nShort ){ | |
| 1078 | + int iBest = -1; | |
| 1079 | + int iBestVal = -1; | |
| 1080 | + int i; | |
| 1081 | + int nLong = nLeft<nRight ? nRight : nLeft; | |
| 1082 | + int nGap = nLong - nShort; | |
| 1083 | + for(i=nShort-nSuffix; i<=nPrefix; i++){ | |
| 1084 | + int iVal = 0; | |
| 1085 | + char c = zLeft[i]; | |
| 1086 | + if( fossil_isspace(c) ){ | |
| 1087 | + iVal += 5; | |
| 1088 | + }else if( !fossil_isalnum(c) ){ | |
| 1089 | + iVal += 2; | |
| 1090 | + } | |
| 1091 | + c = zLeft[i+nGap-1]; | |
| 1092 | + if( fossil_isspace(c) ){ | |
| 1093 | + iVal += 5; | |
| 1094 | + }else if( !fossil_isalnum(c) ){ | |
| 1095 | + iVal += 2; | |
| 1096 | + } | |
| 1097 | + if( iVal>iBestVal ){ | |
| 1098 | + iBestVal = iVal; | |
| 1099 | + iBest = i; | |
| 1100 | + } | |
| 1101 | + } | |
| 1102 | + nPrefix = iBest; | |
| 1103 | + nSuffix = nShort - nPrefix; | |
| 1104 | + nCommon = nPrefix + nSuffix; | |
| 1105 | + } | |
| 1106 | + | |
| 1107 | + /* A single chunk of text inserted */ | |
| 1108 | + if( nCommon==nLeft ){ | |
| 1109 | + p->n = 1; | |
| 1110 | + p->a[0].iStart1 = 0; | |
| 1111 | + p->a[0].iLen1 = 0; | |
| 1112 | + p->a[0].iStart2 = nPrefix; | |
| 1113 | + p->a[0].iLen2 = nRight - nCommon; | |
| 1114 | + return; | |
| 1115 | + } | |
| 1116 | + | |
| 1117 | + /* A single chunk of text deleted */ | |
| 1118 | + if( nCommon==nRight ){ | |
| 1119 | + p->n = 1; | |
| 1120 | + p->a[0].iStart1 = nPrefix; | |
| 1121 | + p->a[0].iLen1 = nLeft - nCommon; | |
| 1122 | + p->a[0].iStart2 = 0; | |
| 1123 | + p->a[0].iLen2 = 0; | |
| 1124 | + return; | |
| 1125 | + } | |
| 1126 | + | |
| 1127 | + /* At this point we know that there is a chunk of text that has | |
| 1128 | + ** changed between the left and the right. Check to see if there | |
| 1129 | + ** is a large unchanged section in the middle of that changed block. | |
| 1130 | + */ | |
| 1131 | + nLeftDiff = nLeft - nCommon; | |
| 1132 | + nRightDiff = nRight - nCommon; | |
| 1133 | + if( nLeftDiff >= 4 | |
| 1134 | + && nRightDiff >= 4 | |
| 1135 | + && textChangeSpans(&zLeft[nPrefix], nLeftDiff, | |
| 1136 | + &zRight[nPrefix], nRightDiff, p)>1 | |
| 1137 | + ){ | |
| 1138 | + int i; | |
| 1139 | + for(i=0; i<p->n; i++){ | |
| 1140 | + p->a[i].iStart1 += nPrefix; | |
| 1141 | + p->a[i].iStart2 += nPrefix; | |
| 1142 | + } | |
| 1143 | + return; | |
| 1144 | + } | |
| 1145 | + | |
| 1146 | + /* If all else fails, show a single big change between left and right */ | |
| 1147 | + p->n = 1; | |
| 1148 | + p->a[0].iStart1 = nPrefix; | |
| 1149 | + p->a[0].iLen1 = nLeft - nCommon; | |
| 1150 | + p->a[0].iStart2 = nPrefix; | |
| 1151 | + p->a[0].iLen2 = nRight - nCommon; | |
| 1152 | +} | |
| 1023 | 1153 | |
| 1024 | 1154 | /* |
| 1025 | 1155 | ** Minimum of two values |
| 1026 | 1156 | */ |
| 1027 | 1157 | static int minInt(int a, int b){ return a<b ? a : b; } |
| @@ -1500,14 +1630,13 @@ | ||
| 1500 | 1630 | void (*xCommon)(DiffBuilder*,const DLine*); |
| 1501 | 1631 | void (*xInsert)(DiffBuilder*,const DLine*); |
| 1502 | 1632 | void (*xDelete)(DiffBuilder*,const DLine*); |
| 1503 | 1633 | void (*xEdit)(DiffBuilder*,const DLine*,const DLine*); |
| 1504 | 1634 | void (*xEnd)(DiffBuilder*); |
| 1505 | - unsigned int lnLeft; /* Lines seen on the left (delete) side */ | |
| 1506 | - unsigned int lnRight; /* Lines seen on the right (insert) side */ | |
| 1507 | - Blob *pOut; /* Output blob */ | |
| 1508 | - /* Subclass add additional fields */ | |
| 1635 | + unsigned int lnLeft; /* Lines seen on the left (delete) side */ | |
| 1636 | + unsigned int lnRight; /* Lines seen on the right (insert) side */ | |
| 1637 | + Blob *pOut; /* Output blob */ | |
| 1509 | 1638 | }; |
| 1510 | 1639 | |
| 1511 | 1640 | /************************* DiffBuilderDebug ********************************/ |
| 1512 | 1641 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1513 | 1642 | blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)\n", |
| @@ -1530,14 +1659,40 @@ | ||
| 1530 | 1659 | p->lnLeft++; |
| 1531 | 1660 | blob_appendf(p->pOut, "LEFT %8u %.*s\n", |
| 1532 | 1661 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1533 | 1662 | } |
| 1534 | 1663 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1664 | + int i, j; | |
| 1665 | + int x; | |
| 1666 | + ChangeSpan span; | |
| 1535 | 1667 | p->lnLeft++; |
| 1536 | 1668 | p->lnRight++; |
| 1537 | - blob_appendf(p->pOut, "EDIT %8u %.*s\n %8u %.*s\n", | |
| 1538 | - p->lnLeft, (int)pX->n, pX->z, p->lnRight, (int)pY->n, pY->z); | |
| 1669 | + blob_appendf(p->pOut, "EDIT %8u %.*s\n", | |
| 1670 | + p->lnLeft, (int)pX->n, pX->z); | |
| 1671 | + oneLineChange(pX, pY, &span); | |
| 1672 | + for(i=x=0; i<span.n; i++){ | |
| 1673 | + int ofst = span.a[i].iStart1; | |
| 1674 | + int len = span.a[i].iLen1; | |
| 1675 | + if( len ){ | |
| 1676 | + blob_appendf(p->pOut, "%*s", ofst+25 - x, ""); | |
| 1677 | + for(j=0; j<len; j++) blob_append_char(p->pOut, '^'); | |
| 1678 | + x = ofst+len+25; | |
| 1679 | + } | |
| 1680 | + } | |
| 1681 | + if( x ) blob_append_char(p->pOut, '\n'); | |
| 1682 | + blob_appendf(p->pOut, " %8u %.*s\n", | |
| 1683 | + p->lnRight, (int)pY->n, pY->z); | |
| 1684 | + for(i=x=0; i<span.n; i++){ | |
| 1685 | + int ofst = span.a[i].iStart2; | |
| 1686 | + int len = span.a[i].iLen2; | |
| 1687 | + if( len ){ | |
| 1688 | + blob_appendf(p->pOut, "%*s", ofst+25 - x, ""); | |
| 1689 | + for(j=0; j<len; j++) blob_append_char(p->pOut, '^'); | |
| 1690 | + x = ofst+len+25; | |
| 1691 | + } | |
| 1692 | + } | |
| 1693 | + if( x ) blob_append_char(p->pOut, '\n'); | |
| 1539 | 1694 | } |
| 1540 | 1695 | static void dfdebugEnd(DiffBuilder *p){ |
| 1541 | 1696 | blob_appendf(p->pOut, "END with %u lines left and %u lines right\n", |
| 1542 | 1697 | p->lnLeft, p->lnRight); |
| 1543 | 1698 | fossil_free(p); |
| 1544 | 1699 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -744,11 +744,11 @@ | |
| 744 | } |
| 745 | return lenBest>0; |
| 746 | } |
| 747 | |
| 748 | /* |
| 749 | ** Find the smallest spans that different between two text strings that |
| 750 | ** are known to be different on both ends. |
| 751 | */ |
| 752 | static int textChangeSpans( |
| 753 | const char *zLeft, int nA, /* String on the left */ |
| 754 | const char *zRight, int nB, /* String on the right */ |
| @@ -1018,10 +1018,140 @@ | |
| 1018 | p->a[0].iEnd = nRight - nSuffix; |
| 1019 | p->a[0].zTag = zClassChng; |
| 1020 | p->n = 1; |
| 1021 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1022 | } |
| 1023 | |
| 1024 | /* |
| 1025 | ** Minimum of two values |
| 1026 | */ |
| 1027 | static int minInt(int a, int b){ return a<b ? a : b; } |
| @@ -1500,14 +1630,13 @@ | |
| 1500 | void (*xCommon)(DiffBuilder*,const DLine*); |
| 1501 | void (*xInsert)(DiffBuilder*,const DLine*); |
| 1502 | void (*xDelete)(DiffBuilder*,const DLine*); |
| 1503 | void (*xEdit)(DiffBuilder*,const DLine*,const DLine*); |
| 1504 | void (*xEnd)(DiffBuilder*); |
| 1505 | unsigned int lnLeft; /* Lines seen on the left (delete) side */ |
| 1506 | unsigned int lnRight; /* Lines seen on the right (insert) side */ |
| 1507 | Blob *pOut; /* Output blob */ |
| 1508 | /* Subclass add additional fields */ |
| 1509 | }; |
| 1510 | |
| 1511 | /************************* DiffBuilderDebug ********************************/ |
| 1512 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1513 | blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)\n", |
| @@ -1530,14 +1659,40 @@ | |
| 1530 | p->lnLeft++; |
| 1531 | blob_appendf(p->pOut, "LEFT %8u %.*s\n", |
| 1532 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1533 | } |
| 1534 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1535 | p->lnLeft++; |
| 1536 | p->lnRight++; |
| 1537 | blob_appendf(p->pOut, "EDIT %8u %.*s\n %8u %.*s\n", |
| 1538 | p->lnLeft, (int)pX->n, pX->z, p->lnRight, (int)pY->n, pY->z); |
| 1539 | } |
| 1540 | static void dfdebugEnd(DiffBuilder *p){ |
| 1541 | blob_appendf(p->pOut, "END with %u lines left and %u lines right\n", |
| 1542 | p->lnLeft, p->lnRight); |
| 1543 | fossil_free(p); |
| 1544 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -744,11 +744,11 @@ | |
| 744 | } |
| 745 | return lenBest>0; |
| 746 | } |
| 747 | |
| 748 | /* |
| 749 | ** Find the smallest spans that are different between two text strings that |
| 750 | ** are known to be different on both ends. |
| 751 | */ |
| 752 | static int textChangeSpans( |
| 753 | const char *zLeft, int nA, /* String on the left */ |
| 754 | const char *zRight, int nB, /* String on the right */ |
| @@ -1018,10 +1018,140 @@ | |
| 1018 | p->a[0].iEnd = nRight - nSuffix; |
| 1019 | p->a[0].zTag = zClassChng; |
| 1020 | p->n = 1; |
| 1021 | sbsWriteText(p, pRight, SBS_TXTB); |
| 1022 | } |
| 1023 | |
| 1024 | /* |
| 1025 | ** Given two lines of text, pFrom and pTo, compute a set of changes |
| 1026 | ** between those two lines, for enhanced display purposes. |
| 1027 | ** |
| 1028 | ** The result is written into the ChangeSpan object given by the |
| 1029 | ** third parameter. |
| 1030 | */ |
| 1031 | static void oneLineChange( |
| 1032 | const DLine *pLeft, /* Left line of the change */ |
| 1033 | const DLine *pRight, /* Right line of the change */ |
| 1034 | ChangeSpan *p /* OUTPUT: Write the results here */ |
| 1035 | ){ |
| 1036 | int nLeft; /* Length of left line in bytes */ |
| 1037 | int nRight; /* Length of right line in bytes */ |
| 1038 | int nShort; /* Shortest of left and right */ |
| 1039 | int nPrefix; /* Length of common prefix */ |
| 1040 | int nSuffix; /* Length of common suffix */ |
| 1041 | int nCommon; /* Total byte length of suffix and prefix */ |
| 1042 | const char *zLeft; /* Text of the left line */ |
| 1043 | const char *zRight; /* Text of the right line */ |
| 1044 | int nLeftDiff; /* nLeft - nPrefix - nSuffix */ |
| 1045 | int nRightDiff; /* nRight - nPrefix - nSuffix */ |
| 1046 | |
| 1047 | nLeft = pLeft->n; |
| 1048 | zLeft = pLeft->z; |
| 1049 | nRight = pRight->n; |
| 1050 | zRight = pRight->z; |
| 1051 | nShort = nLeft<nRight ? nLeft : nRight; |
| 1052 | |
| 1053 | nPrefix = 0; |
| 1054 | while( nPrefix<nShort && zLeft[nPrefix]==zRight[nPrefix] ){ |
| 1055 | nPrefix++; |
| 1056 | } |
| 1057 | if( nPrefix<nShort ){ |
| 1058 | while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; |
| 1059 | } |
| 1060 | nSuffix = 0; |
| 1061 | if( nPrefix<nShort ){ |
| 1062 | while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ |
| 1063 | nSuffix++; |
| 1064 | } |
| 1065 | if( nSuffix<nShort ){ |
| 1066 | while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; |
| 1067 | } |
| 1068 | if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; |
| 1069 | } |
| 1070 | nCommon = nPrefix + nSuffix; |
| 1071 | |
| 1072 | /* If the prefix and suffix overlap, that means that we are dealing with |
| 1073 | ** a pure insertion or deletion of text that can have multiple alignments. |
| 1074 | ** Try to find an alignment to begins and ends on whitespace, or on |
| 1075 | ** punctuation, rather than in the middle of a name or number. |
| 1076 | */ |
| 1077 | if( nCommon > nShort ){ |
| 1078 | int iBest = -1; |
| 1079 | int iBestVal = -1; |
| 1080 | int i; |
| 1081 | int nLong = nLeft<nRight ? nRight : nLeft; |
| 1082 | int nGap = nLong - nShort; |
| 1083 | for(i=nShort-nSuffix; i<=nPrefix; i++){ |
| 1084 | int iVal = 0; |
| 1085 | char c = zLeft[i]; |
| 1086 | if( fossil_isspace(c) ){ |
| 1087 | iVal += 5; |
| 1088 | }else if( !fossil_isalnum(c) ){ |
| 1089 | iVal += 2; |
| 1090 | } |
| 1091 | c = zLeft[i+nGap-1]; |
| 1092 | if( fossil_isspace(c) ){ |
| 1093 | iVal += 5; |
| 1094 | }else if( !fossil_isalnum(c) ){ |
| 1095 | iVal += 2; |
| 1096 | } |
| 1097 | if( iVal>iBestVal ){ |
| 1098 | iBestVal = iVal; |
| 1099 | iBest = i; |
| 1100 | } |
| 1101 | } |
| 1102 | nPrefix = iBest; |
| 1103 | nSuffix = nShort - nPrefix; |
| 1104 | nCommon = nPrefix + nSuffix; |
| 1105 | } |
| 1106 | |
| 1107 | /* A single chunk of text inserted */ |
| 1108 | if( nCommon==nLeft ){ |
| 1109 | p->n = 1; |
| 1110 | p->a[0].iStart1 = 0; |
| 1111 | p->a[0].iLen1 = 0; |
| 1112 | p->a[0].iStart2 = nPrefix; |
| 1113 | p->a[0].iLen2 = nRight - nCommon; |
| 1114 | return; |
| 1115 | } |
| 1116 | |
| 1117 | /* A single chunk of text deleted */ |
| 1118 | if( nCommon==nRight ){ |
| 1119 | p->n = 1; |
| 1120 | p->a[0].iStart1 = nPrefix; |
| 1121 | p->a[0].iLen1 = nLeft - nCommon; |
| 1122 | p->a[0].iStart2 = 0; |
| 1123 | p->a[0].iLen2 = 0; |
| 1124 | return; |
| 1125 | } |
| 1126 | |
| 1127 | /* At this point we know that there is a chunk of text that has |
| 1128 | ** changed between the left and the right. Check to see if there |
| 1129 | ** is a large unchanged section in the middle of that changed block. |
| 1130 | */ |
| 1131 | nLeftDiff = nLeft - nCommon; |
| 1132 | nRightDiff = nRight - nCommon; |
| 1133 | if( nLeftDiff >= 4 |
| 1134 | && nRightDiff >= 4 |
| 1135 | && textChangeSpans(&zLeft[nPrefix], nLeftDiff, |
| 1136 | &zRight[nPrefix], nRightDiff, p)>1 |
| 1137 | ){ |
| 1138 | int i; |
| 1139 | for(i=0; i<p->n; i++){ |
| 1140 | p->a[i].iStart1 += nPrefix; |
| 1141 | p->a[i].iStart2 += nPrefix; |
| 1142 | } |
| 1143 | return; |
| 1144 | } |
| 1145 | |
| 1146 | /* If all else fails, show a single big change between left and right */ |
| 1147 | p->n = 1; |
| 1148 | p->a[0].iStart1 = nPrefix; |
| 1149 | p->a[0].iLen1 = nLeft - nCommon; |
| 1150 | p->a[0].iStart2 = nPrefix; |
| 1151 | p->a[0].iLen2 = nRight - nCommon; |
| 1152 | } |
| 1153 | |
| 1154 | /* |
| 1155 | ** Minimum of two values |
| 1156 | */ |
| 1157 | static int minInt(int a, int b){ return a<b ? a : b; } |
| @@ -1500,14 +1630,13 @@ | |
| 1630 | void (*xCommon)(DiffBuilder*,const DLine*); |
| 1631 | void (*xInsert)(DiffBuilder*,const DLine*); |
| 1632 | void (*xDelete)(DiffBuilder*,const DLine*); |
| 1633 | void (*xEdit)(DiffBuilder*,const DLine*,const DLine*); |
| 1634 | void (*xEnd)(DiffBuilder*); |
| 1635 | unsigned int lnLeft; /* Lines seen on the left (delete) side */ |
| 1636 | unsigned int lnRight; /* Lines seen on the right (insert) side */ |
| 1637 | Blob *pOut; /* Output blob */ |
| 1638 | }; |
| 1639 | |
| 1640 | /************************* DiffBuilderDebug ********************************/ |
| 1641 | static void dfdebugSkip(DiffBuilder *p, unsigned int n){ |
| 1642 | blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)\n", |
| @@ -1530,14 +1659,40 @@ | |
| 1659 | p->lnLeft++; |
| 1660 | blob_appendf(p->pOut, "LEFT %8u %.*s\n", |
| 1661 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1662 | } |
| 1663 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1664 | int i, j; |
| 1665 | int x; |
| 1666 | ChangeSpan span; |
| 1667 | p->lnLeft++; |
| 1668 | p->lnRight++; |
| 1669 | blob_appendf(p->pOut, "EDIT %8u %.*s\n", |
| 1670 | p->lnLeft, (int)pX->n, pX->z); |
| 1671 | oneLineChange(pX, pY, &span); |
| 1672 | for(i=x=0; i<span.n; i++){ |
| 1673 | int ofst = span.a[i].iStart1; |
| 1674 | int len = span.a[i].iLen1; |
| 1675 | if( len ){ |
| 1676 | blob_appendf(p->pOut, "%*s", ofst+25 - x, ""); |
| 1677 | for(j=0; j<len; j++) blob_append_char(p->pOut, '^'); |
| 1678 | x = ofst+len+25; |
| 1679 | } |
| 1680 | } |
| 1681 | if( x ) blob_append_char(p->pOut, '\n'); |
| 1682 | blob_appendf(p->pOut, " %8u %.*s\n", |
| 1683 | p->lnRight, (int)pY->n, pY->z); |
| 1684 | for(i=x=0; i<span.n; i++){ |
| 1685 | int ofst = span.a[i].iStart2; |
| 1686 | int len = span.a[i].iLen2; |
| 1687 | if( len ){ |
| 1688 | blob_appendf(p->pOut, "%*s", ofst+25 - x, ""); |
| 1689 | for(j=0; j<len; j++) blob_append_char(p->pOut, '^'); |
| 1690 | x = ofst+len+25; |
| 1691 | } |
| 1692 | } |
| 1693 | if( x ) blob_append_char(p->pOut, '\n'); |
| 1694 | } |
| 1695 | static void dfdebugEnd(DiffBuilder *p){ |
| 1696 | blob_appendf(p->pOut, "END with %u lines left and %u lines right\n", |
| 1697 | p->lnLeft, p->lnRight); |
| 1698 | fossil_free(p); |
| 1699 |