| | @@ -1061,11 +1061,12 @@ |
| 1061 | 1061 | if( nPrefix<nShort ){ |
| 1062 | 1062 | while( nPrefix>0 && (zLeft[nPrefix]&0xc0)==0x80 ) nPrefix--; |
| 1063 | 1063 | } |
| 1064 | 1064 | nSuffix = 0; |
| 1065 | 1065 | if( nPrefix<nShort ){ |
| 1066 | | - while( nSuffix<nShort && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ |
| 1066 | + while( nSuffix<nShort |
| 1067 | + && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ |
| 1067 | 1068 | nSuffix++; |
| 1068 | 1069 | } |
| 1069 | 1070 | if( nSuffix<nShort ){ |
| 1070 | 1071 | while( nSuffix>0 && (zLeft[nLeft-nSuffix]&0xc0)==0x80 ) nSuffix--; |
| 1071 | 1072 | } |
| | @@ -1109,11 +1110,11 @@ |
| 1109 | 1110 | } |
| 1110 | 1111 | |
| 1111 | 1112 | /* A single chunk of text inserted */ |
| 1112 | 1113 | if( nCommon==nLeft ){ |
| 1113 | 1114 | p->n = 1; |
| 1114 | | - p->a[0].iStart1 = 0; |
| 1115 | + p->a[0].iStart1 = nPrefix; |
| 1115 | 1116 | p->a[0].iLen1 = 0; |
| 1116 | 1117 | p->a[0].iStart2 = nPrefix; |
| 1117 | 1118 | p->a[0].iLen2 = nRight - nCommon; |
| 1118 | 1119 | return; |
| 1119 | 1120 | } |
| | @@ -1121,11 +1122,11 @@ |
| 1121 | 1122 | /* A single chunk of text deleted */ |
| 1122 | 1123 | if( nCommon==nRight ){ |
| 1123 | 1124 | p->n = 1; |
| 1124 | 1125 | p->a[0].iStart1 = nPrefix; |
| 1125 | 1126 | p->a[0].iLen1 = nLeft - nCommon; |
| 1126 | | - p->a[0].iStart2 = 0; |
| 1127 | + p->a[0].iStart2 = nPrefix; |
| 1127 | 1128 | p->a[0].iLen2 = 0; |
| 1128 | 1129 | return; |
| 1129 | 1130 | } |
| 1130 | 1131 | |
| 1131 | 1132 | /* At this point we know that there is a chunk of text that has |
| | @@ -1632,10 +1633,11 @@ |
| 1632 | 1633 | struct DiffBuilder { |
| 1633 | 1634 | void (*xSkip)(DiffBuilder*, unsigned int, int); |
| 1634 | 1635 | void (*xCommon)(DiffBuilder*,const DLine*); |
| 1635 | 1636 | void (*xInsert)(DiffBuilder*,const DLine*); |
| 1636 | 1637 | void (*xDelete)(DiffBuilder*,const DLine*); |
| 1638 | + void (*xReplace)(DiffBuilder*,const DLine*, const DLine*); |
| 1637 | 1639 | void (*xEdit)(DiffBuilder*,const DLine*,const DLine*); |
| 1638 | 1640 | void (*xEnd)(DiffBuilder*); |
| 1639 | 1641 | unsigned int lnLeft; /* Lines seen on the left (delete) side */ |
| 1640 | 1642 | unsigned int lnRight; /* Lines seen on the right (insert) side */ |
| 1641 | 1643 | unsigned int nPending; /* Number of pending lines */ |
| | @@ -1653,30 +1655,38 @@ |
| 1653 | 1655 | p->lnRight += n; |
| 1654 | 1656 | } |
| 1655 | 1657 | static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){ |
| 1656 | 1658 | p->lnLeft++; |
| 1657 | 1659 | p->lnRight++; |
| 1658 | | - blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n", |
| 1660 | + blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n", |
| 1659 | 1661 | p->lnLeft, p->lnRight, (int)pLine->n, pLine->z); |
| 1660 | 1662 | } |
| 1661 | 1663 | static void dfdebugInsert(DiffBuilder *p, const DLine *pLine){ |
| 1662 | 1664 | p->lnRight++; |
| 1663 | | - blob_appendf(p->pOut, "RIGHT %8d %.*s\n", |
| 1665 | + blob_appendf(p->pOut, "INSERT %8d %.*s\n", |
| 1664 | 1666 | p->lnRight, (int)pLine->n, pLine->z); |
| 1665 | 1667 | } |
| 1666 | 1668 | static void dfdebugDelete(DiffBuilder *p, const DLine *pLine){ |
| 1667 | 1669 | p->lnLeft++; |
| 1668 | | - blob_appendf(p->pOut, "LEFT %8u %.*s\n", |
| 1670 | + blob_appendf(p->pOut, "DELETE %8u %.*s\n", |
| 1669 | 1671 | p->lnLeft, (int)pLine->n, pLine->z); |
| 1672 | +} |
| 1673 | +static void dfdebugReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1674 | + p->lnLeft++; |
| 1675 | + p->lnRight++; |
| 1676 | + blob_appendf(p->pOut, "REPLACE %8u %.*s\n", |
| 1677 | + p->lnLeft, (int)pX->n, pX->z); |
| 1678 | + blob_appendf(p->pOut, " %8u %.*s\n", |
| 1679 | + p->lnRight, (int)pY->n, pY->z); |
| 1670 | 1680 | } |
| 1671 | 1681 | static void dfdebugEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1672 | 1682 | int i, j; |
| 1673 | 1683 | int x; |
| 1674 | 1684 | ChangeSpan span; |
| 1675 | 1685 | p->lnLeft++; |
| 1676 | 1686 | p->lnRight++; |
| 1677 | | - blob_appendf(p->pOut, "EDIT %8u %.*s\n", |
| 1687 | + blob_appendf(p->pOut, "EDIT %8u %.*s\n", |
| 1678 | 1688 | p->lnLeft, (int)pX->n, pX->z); |
| 1679 | 1689 | oneLineChange(pX, pY, &span); |
| 1680 | 1690 | for(i=x=0; i<span.n; i++){ |
| 1681 | 1691 | int ofst = span.a[i].iStart1; |
| 1682 | 1692 | int len = span.a[i].iLen1; |
| | @@ -1719,10 +1729,11 @@ |
| 1719 | 1729 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1720 | 1730 | p->xSkip = dfdebugSkip; |
| 1721 | 1731 | p->xCommon = dfdebugCommon; |
| 1722 | 1732 | p->xInsert = dfdebugInsert; |
| 1723 | 1733 | p->xDelete = dfdebugDelete; |
| 1734 | + p->xReplace = dfdebugReplace; |
| 1724 | 1735 | p->xEdit = dfdebugEdit; |
| 1725 | 1736 | p->xEnd = dfdebugEnd; |
| 1726 | 1737 | p->lnLeft = p->lnRight = 0; |
| 1727 | 1738 | p->pOut = pOut; |
| 1728 | 1739 | return p; |
| | @@ -1768,10 +1779,17 @@ |
| 1768 | 1779 | } |
| 1769 | 1780 | static void dftclDelete(DiffBuilder *p, const DLine *pLine){ |
| 1770 | 1781 | blob_append(p->pOut, "DEL ", -1); |
| 1771 | 1782 | blob_append_tcl_string(p->pOut, pLine->z, pLine->n); |
| 1772 | 1783 | blob_append_char(p->pOut, '\n'); |
| 1784 | +} |
| 1785 | +static void dftclReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1786 | + blob_append(p->pOut, "EDIT ", -1); |
| 1787 | + blob_append_tcl_string(p->pOut, pX->z, pX->n); |
| 1788 | + blob_append_char(p->pOut, ' '); |
| 1789 | + blob_append_tcl_string(p->pOut, pY->z, pY->n); |
| 1790 | + blob_append_char(p->pOut, '\n'); |
| 1773 | 1791 | } |
| 1774 | 1792 | static void dftclEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1775 | 1793 | int i, x; |
| 1776 | 1794 | ChangeSpan span; |
| 1777 | 1795 | blob_append(p->pOut, "EDIT", 4); |
| | @@ -1799,10 +1817,11 @@ |
| 1799 | 1817 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1800 | 1818 | p->xSkip = dftclSkip; |
| 1801 | 1819 | p->xCommon = dftclCommon; |
| 1802 | 1820 | p->xInsert = dftclInsert; |
| 1803 | 1821 | p->xDelete = dftclDelete; |
| 1822 | + p->xReplace = dftclReplace; |
| 1804 | 1823 | p->xEdit = dftclEdit; |
| 1805 | 1824 | p->xEnd = dftclEnd; |
| 1806 | 1825 | p->pOut = pOut; |
| 1807 | 1826 | return p; |
| 1808 | 1827 | } |
| | @@ -1886,10 +1905,18 @@ |
| 1886 | 1905 | static void dfjsonDelete(DiffBuilder *p, const DLine *pLine){ |
| 1887 | 1906 | int iCol = 0; |
| 1888 | 1907 | blob_append(p->pOut, "4,\"",3); |
| 1889 | 1908 | jsonize_to_blob(p->pOut, pLine->z, (int)pLine->n, &iCol); |
| 1890 | 1909 | blob_append(p->pOut, "\",\n",3); |
| 1910 | +} |
| 1911 | +static void dfjsonReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1912 | + int iCol = 0; |
| 1913 | + blob_append(p->pOut, "5,\"",3); |
| 1914 | + jsonize_to_blob(p->pOut, pX->z, (int)pX->n, &iCol); |
| 1915 | + blob_append(p->pOut, "\",\"",3); |
| 1916 | + jsonize_to_blob(p->pOut, pY->z, (int)pY->n, &iCol); |
| 1917 | + blob_append(p->pOut, "\",\n",3); |
| 1891 | 1918 | } |
| 1892 | 1919 | static void dfjsonEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1893 | 1920 | int i; |
| 1894 | 1921 | int x; |
| 1895 | 1922 | int iCol; |
| | @@ -1933,10 +1960,11 @@ |
| 1933 | 1960 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 1934 | 1961 | p->xSkip = dfjsonSkip; |
| 1935 | 1962 | p->xCommon = dfjsonCommon; |
| 1936 | 1963 | p->xInsert = dfjsonInsert; |
| 1937 | 1964 | p->xDelete = dfjsonDelete; |
| 1965 | + p->xReplace = dfjsonReplace; |
| 1938 | 1966 | p->xEdit = dfjsonEdit; |
| 1939 | 1967 | p->xEnd = dfjsonEnd; |
| 1940 | 1968 | p->lnLeft = p->lnRight = 0; |
| 1941 | 1969 | p->pOut = pOut; |
| 1942 | 1970 | blob_append_char(pOut, '['); |
| | @@ -2050,10 +2078,36 @@ |
| 2050 | 2078 | blob_append_char(&p->aCol[0],'\n'); |
| 2051 | 2079 | blob_append(&p->aCol[1],"-\n",2); |
| 2052 | 2080 | blob_append(&p->aCol[2], "<del>", 5); |
| 2053 | 2081 | jsonize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n, &iCol); |
| 2054 | 2082 | blob_append(&p->aCol[2], "</del>\n", 7); |
| 2083 | +} |
| 2084 | +static void dfunifiedReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 2085 | + int iCol; |
| 2086 | + dfunifiedStartRow(p); |
| 2087 | + if( p->eState==0 ){ |
| 2088 | + dfunifiedFinishInsert(p); |
| 2089 | + blob_append(p->pOut, "<del>", 5); |
| 2090 | + blob_append(&p->aCol[2], "<del>", 5); |
| 2091 | + p->eState = 1; |
| 2092 | + } |
| 2093 | + p->lnLeft++; |
| 2094 | + p->lnRight++; |
| 2095 | + blob_appendf(p->pOut,"%d\n", p->lnLeft); |
| 2096 | + blob_append_char(&p->aCol[0], '\n'); |
| 2097 | + blob_append(&p->aCol[1], "-\n", 2); |
| 2098 | + |
| 2099 | + iCol = 0; |
| 2100 | + jsonize_to_blob(&p->aCol[2], pX->z, pX->n, &iCol); |
| 2101 | + blob_append_char(&p->aCol[2], '\n'); |
| 2102 | + |
| 2103 | + blob_appendf(&p->aCol[3],"%d\n", p->lnRight); |
| 2104 | + |
| 2105 | + iCol = 0; |
| 2106 | + jsonize_to_blob(&p->aCol[4], pY->z, pY->n, &iCol); |
| 2107 | + blob_append_char(&p->aCol[4], '\n'); |
| 2108 | + p->nPending++; |
| 2055 | 2109 | } |
| 2056 | 2110 | static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 2057 | 2111 | int i; |
| 2058 | 2112 | int x; |
| 2059 | 2113 | int iCol; |
| | @@ -2113,10 +2167,11 @@ |
| 2113 | 2167 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 2114 | 2168 | p->xSkip = dfunifiedSkip; |
| 2115 | 2169 | p->xCommon = dfunifiedCommon; |
| 2116 | 2170 | p->xInsert = dfunifiedInsert; |
| 2117 | 2171 | p->xDelete = dfunifiedDelete; |
| 2172 | + p->xReplace = dfunifiedReplace; |
| 2118 | 2173 | p->xEdit = dfunifiedEdit; |
| 2119 | 2174 | p->xEnd = dfunifiedEnd; |
| 2120 | 2175 | p->lnLeft = p->lnRight = 0; |
| 2121 | 2176 | p->eState = 0; |
| 2122 | 2177 | p->nPending = 0; |
| | @@ -2234,10 +2289,29 @@ |
| 2234 | 2289 | jsonize_to_blob(&p->aCol[0], pLine->z, (int)pLine->n, &iCol); |
| 2235 | 2290 | blob_append(&p->aCol[0], "</del>\n", 7); |
| 2236 | 2291 | blob_append(&p->aCol[1], "<\n", -1); |
| 2237 | 2292 | blob_append_char(&p->aCol[2],'\n'); |
| 2238 | 2293 | blob_append_char(&p->aCol[3],'\n'); |
| 2294 | +} |
| 2295 | +static void dfsplitReplace(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 2296 | + int iCol; |
| 2297 | + dfsplitStartRow(p); |
| 2298 | + dfsplitChangeState(p, 3); |
| 2299 | + p->lnLeft++; |
| 2300 | + p->lnRight++; |
| 2301 | + blob_appendf(p->pOut,"%d\n", p->lnLeft); |
| 2302 | + iCol = 0; |
| 2303 | + jsonize_to_blob(&p->aCol[0], pX->z, pX->n, &iCol); |
| 2304 | + blob_append_char(&p->aCol[0], '\n'); |
| 2305 | + |
| 2306 | + blob_append(&p->aCol[1], "|\n", 2); |
| 2307 | + |
| 2308 | + blob_appendf(&p->aCol[2],"%d\n", p->lnRight); |
| 2309 | + |
| 2310 | + iCol = 0; |
| 2311 | + jsonize_to_blob(&p->aCol[3], pY->z, pY->n, &iCol); |
| 2312 | + blob_append_char(&p->aCol[3], '\n'); |
| 2239 | 2313 | } |
| 2240 | 2314 | static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 2241 | 2315 | int i; |
| 2242 | 2316 | int x; |
| 2243 | 2317 | int iCol; |
| | @@ -2290,10 +2364,11 @@ |
| 2290 | 2364 | DiffBuilder *p = fossil_malloc(sizeof(*p)); |
| 2291 | 2365 | p->xSkip = dfsplitSkip; |
| 2292 | 2366 | p->xCommon = dfsplitCommon; |
| 2293 | 2367 | p->xInsert = dfsplitInsert; |
| 2294 | 2368 | p->xDelete = dfsplitDelete; |
| 2369 | + p->xReplace = dfsplitReplace; |
| 2295 | 2370 | p->xEdit = dfsplitEdit; |
| 2296 | 2371 | p->xEnd = dfsplitEnd; |
| 2297 | 2372 | p->lnLeft = p->lnRight = 0; |
| 2298 | 2373 | p->eState = 0; |
| 2299 | 2374 | p->pOut = pOut; |
| | @@ -2440,15 +2515,13 @@ |
| 2440 | 2515 | b++; |
| 2441 | 2516 | break; |
| 2442 | 2517 | } |
| 2443 | 2518 | case 4: { |
| 2444 | 2519 | /* Delete from left then separately insert on the right */ |
| 2445 | | - pBuilder->xDelete(pBuilder, &A[a]); |
| 2520 | + pBuilder->xReplace(pBuilder, &A[a], &B[b]); |
| 2446 | 2521 | ma--; |
| 2447 | 2522 | a++; |
| 2448 | | - pBuilder->xInsert(pBuilder, &B[b]); |
| 2449 | | - assert( mb>0 ); |
| 2450 | 2523 | mb--; |
| 2451 | 2524 | b++; |
| 2452 | 2525 | break; |
| 2453 | 2526 | } |
| 2454 | 2527 | } |
| 2455 | 2528 | |