Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | An attempt to rework HTML unified diff to show partial line matches. Still needs CSS work. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | diff-color-enhancements |
| Files: | files | file ages | folders |
| SHA3-256: |
a01e46d85e8788a1109a9efbb0e425ac |
| User & Date: | drh 2021-08-31 03:00:50.831 |
Context
|
2021-08-31
| ||
| 13:33 | Improvements to the new unified diff algorithm. ... (check-in: 2a256a4cce user: drh tags: diff-color-enhancements) | |
| 03:00 | An attempt to rework HTML unified diff to show partial line matches. Still needs CSS work. ... (check-in: a01e46d85e user: drh tags: diff-color-enhancements) | |
|
2021-08-30
| ||
| 22:39 | Merge fixed from trunk into the diff-color-enhancements branch. ... (check-in: 06a4494e01 user: drh tags: diff-color-enhancements) | |
Changes
Changes to src/default.css.
| ︙ | ︙ | |||
530 531 532 533 534 535 536 |
}
ul.filelist li {
padding-top: 1px;
}
table.sbsdiffcols {
width: 90%;
border-spacing: 0;
| | | 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 |
}
ul.filelist li {
padding-top: 1px;
}
table.sbsdiffcols {
width: 90%;
border-spacing: 0;
font-size: small;
}
table.sbsdiffcols td {
padding: 0;
vertical-align: top;
}
table.sbsdiffcols pre {
margin: 0;
|
| ︙ | ︙ | |||
573 574 575 576 577 578 579 580 581 582 583 584 585 586 |
display: inline-block;
margin: .5em 0 1em;
color: #0000ff;
}
span.diffln {
color: #a0a0a0;
}
span.modpending {
color: #b03800;
font-style: italic;
}
pre.th1result {
white-space: pre-wrap;
word-wrap: break-word;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
display: inline-block;
margin: .5em 0 1em;
color: #0000ff;
}
span.diffln {
color: #a0a0a0;
}
pre.udiffln {
color: #a0a0a0;
}
pre.udiffln ins {
background-color: #a0e4b2;
text-decoration: none;
}
pre.udiffln del {
background-color: #ffc0c0;
text-decoration: none;
}
pre.udifftxt ins {
background-color: #dafbe1;
text-decoration: none;
}
pre.udifftxt del {
background-color: #ffe8e8;
text-decoration: none;
}
pre.udifftxt ins mark {
background-color: #a0e4b2;
text-decoration: none;
}
pre.udifftxt del mark {
background-color: #ffc0c0;
text-decoration: none;
}
span.modpending {
color: #b03800;
font-style: italic;
}
pre.th1result {
white-space: pre-wrap;
word-wrap: break-word;
|
| ︙ | ︙ |
Changes to src/diff.c.
| ︙ | ︙ | |||
1625 1626 1627 1628 1629 1630 1631 |
/*
** This is an abstract superclass for an object that accepts difference
** lines and formats them for display. Subclasses of this object format
** the diff output in different ways.
*/
typedef struct DiffBuilder DiffBuilder;
struct DiffBuilder {
| | > | | | > | 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 |
/*
** This is an abstract superclass for an object that accepts difference
** lines and formats them for display. Subclasses of this object format
** the diff output in different ways.
*/
typedef struct DiffBuilder DiffBuilder;
struct DiffBuilder {
void (*xSkip)(DiffBuilder*, unsigned int, int);
void (*xCommon)(DiffBuilder*,const DLine*);
void (*xInsert)(DiffBuilder*,const DLine*);
void (*xDelete)(DiffBuilder*,const DLine*);
void (*xEdit)(DiffBuilder*,const DLine*,const DLine*);
void (*xEnd)(DiffBuilder*);
unsigned int lnLeft; /* Lines seen on the left (delete) side */
unsigned int lnRight; /* Lines seen on the right (insert) side */
Blob *pOut; /* Output blob */
Blob aCol[5]; /* Holding blobs */
};
/************************* DiffBuilderDebug ********************************/
static void dfdebugSkip(DiffBuilder *p, unsigned int n, int isFinal){
blob_appendf(p->pOut, "SKIP %d (%d..%d left and %d..%d right)%s\n",
n, p->lnLeft+1, p->lnLeft+n, p->lnRight+1, p->lnRight+n,
isFinal ? " FINAL" : "");
p->lnLeft += n;
p->lnRight += n;
}
static void dfdebugCommon(DiffBuilder *p, const DLine *pLine){
p->lnLeft++;
p->lnRight++;
blob_appendf(p->pOut, "COMMON %8u %8u %.*s\n",
|
| ︙ | ︙ | |||
1780 1781 1782 1783 1784 1785 1786 |
blob_append_char(p, c);
if( (c&0xc0)!=0x80 ) iCol++;
break;
}
}
*piCol = iCol;
}
| | | 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 |
blob_append_char(p, c);
if( (c&0xc0)!=0x80 ) iCol++;
break;
}
}
*piCol = iCol;
}
static void dfjsonSkip(DiffBuilder *p, unsigned int n, int isFinal){
blob_appendf(p->pOut, "1,%u,\n", n);
}
static void dfjsonCommon(DiffBuilder *p, const DLine *pLine){
int iCol = 0;
blob_append(p->pOut, "2,\"",3);
jsonize_to_blob(p->pOut, pLine->z, (int)pLine->n, &iCol);
blob_append(p->pOut, "\",\n",3);
|
| ︙ | ︙ | |||
1813 1814 1815 1816 1817 1818 1819 |
oneLineChange(pX, pY, &span);
blob_appendf(p->pOut, "5,\"");
for(i=x=iCol=0; i<span.n; i++){
int ofst = span.a[i].iStart1;
int len = span.a[i].iLen1;
if( len ){
jsonize_to_blob(p->pOut, pX->z+x, ofst - x, &iCol);
| | | | 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 |
oneLineChange(pX, pY, &span);
blob_appendf(p->pOut, "5,\"");
for(i=x=iCol=0; i<span.n; i++){
int ofst = span.a[i].iStart1;
int len = span.a[i].iLen1;
if( len ){
jsonize_to_blob(p->pOut, pX->z+x, ofst - x, &iCol);
x = ofst;
blob_append(p->pOut, "<mark>", 6);
jsonize_to_blob(p->pOut, pX->z+x, len, &iCol);
x += len;
blob_append(p->pOut, "</mark>", 7);
}
}
if( x<pX->n ) jsonize_to_blob(p->pOut, pX->z+x, pX->n - x, &iCol);
blob_append(p->pOut, "\",\n \"", -1);
for(i=x=iCol=0; i<span.n; i++){
int ofst = span.a[i].iStart2;
int len = span.a[i].iLen2;
if( len ){
jsonize_to_blob(p->pOut, pY->z+x, ofst - x, &iCol);
x = ofst;
blob_append(p->pOut, "<mark>", 6);
jsonize_to_blob(p->pOut, pY->z+x, len, &iCol);
x += len;
blob_append(p->pOut, "</mark>", 7);
}
}
if( x<pY->n ) jsonize_to_blob(p->pOut, pY->z+x, pY->n - x, &iCol);
|
| ︙ | ︙ | |||
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 | p->xEdit = dfjsonEdit; p->xEnd = dfjsonEnd; p->lnLeft = p->lnRight = 0; p->pOut = pOut; blob_append_char(pOut, '['); return p; } /****************************************************************************/ /* ** Format a diff using a DiffBuilder object */ static void formatDiff( DContext *p, /* The computed diff */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 |
p->xEdit = dfjsonEdit;
p->xEnd = dfjsonEnd;
p->lnLeft = p->lnRight = 0;
p->pOut = pOut;
blob_append_char(pOut, '[');
return p;
}
/************************* DiffBuilderUnified********************************/
/* Accumulator strategy:
**
** * Common and Delete line numbers are output directly to p->pOut
** * Common and Delete text accumulates in p->aCol[0].
** * Pending insert lines numbers go into p->aCol[1].
** * Pending insert text goes into p->aCol[2].
*/
static void dfunifiedEmitInsert(DiffBuilder *p){
if( blob_size(&p->aCol[1])==0 ) return;
blob_append(p->pOut, blob_buffer(&p->aCol[1]), blob_size(&p->aCol[1]));
blob_reset(&p->aCol[1]);
blob_append(&p->aCol[0], blob_buffer(&p->aCol[2]), blob_size(&p->aCol[2]));
blob_reset(&p->aCol[2]);
}
static void dfunifiedSkip(DiffBuilder *p, unsigned int n, int isFinal){
dfunifiedEmitInsert(p);
if( (p->lnLeft || p->lnRight) && !isFinal ){
blob_append(p->pOut,
"<span class=\"diffhr\">"
".................."
"</span>\n",
-1);
blob_append(&p->aCol[0],
"<span class=\"diffhr\">"
"..............................................................."
"</span>\n",
-1);
}
p->lnLeft += n;
p->lnRight += n;
}
static void dfunifiedCommon(DiffBuilder *p, const DLine *pLine){
int iCol = 0;
dfunifiedEmitInsert(p);
p->lnLeft++;
p->lnRight++;
blob_appendf(p->pOut,"%6d %6d\n", p->lnLeft, p->lnRight);
jsonize_to_blob(&p->aCol[0], pLine->z, (int)pLine->n, &iCol);
blob_append_char(&p->aCol[0], '\n');
}
static void dfunifiedInsert(DiffBuilder *p, const DLine *pLine){
int iCol = 0;
p->lnRight++;
blob_appendf(&p->aCol[1]," <ins>%6d</ins>\n", p->lnRight);
blob_append(&p->aCol[2],"<ins>",-1);
jsonize_to_blob(&p->aCol[2], pLine->z, (int)pLine->n, &iCol);
blob_append(&p->aCol[2], "</ins>\n", -1);
}
static void dfunifiedDelete(DiffBuilder *p, const DLine *pLine){
int iCol = 0;
p->lnLeft++;
blob_appendf(p->pOut,"<del>%6d</del> \n", p->lnLeft);
blob_append(&p->aCol[0],"<del>",-1);
jsonize_to_blob(&p->aCol[0], pLine->z, (int)pLine->n, &iCol);
blob_append(&p->aCol[0], "</del>\n", -1);
}
static void dfunifiedEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){
int i;
int x;
int iCol;
ChangeSpan span;
oneLineChange(pX, pY, &span);
p->lnLeft++;
p->lnRight++;
blob_appendf(p->pOut,"<del>%6d</del> \n", p->lnLeft);
blob_append(&p->aCol[0], "<del>", -1);
for(i=x=iCol=0; i<span.n; i++){
int ofst = span.a[i].iStart1;
int len = span.a[i].iLen1;
if( len ){
jsonize_to_blob(&p->aCol[0], pX->z+x, ofst - x, &iCol);
x = ofst;
blob_append(&p->aCol[0], "<mark>", 6);
jsonize_to_blob(&p->aCol[0], pX->z+x, len, &iCol);
x += len;
blob_append(&p->aCol[0], "</mark>", 7);
}
}
if( x<pX->n ) jsonize_to_blob(&p->aCol[0], pX->z+x, pX->n - x, &iCol);
blob_append(&p->aCol[0], "</del>\n", -1);
blob_appendf(&p->aCol[1]," <ins>%6d</ins>\n", p->lnRight);
blob_append(&p->aCol[2], "<ins>", -1);
for(i=x=iCol=0; i<span.n; i++){
int ofst = span.a[i].iStart2;
int len = span.a[i].iLen2;
if( len ){
jsonize_to_blob(&p->aCol[2], pY->z+x, ofst - x, &iCol);
x = ofst;
blob_append(&p->aCol[2], "<mark>", 6);
jsonize_to_blob(&p->aCol[2], pY->z+x, len, &iCol);
x += len;
blob_append(&p->aCol[2], "</mark>", 7);
}
}
if( x<pY->n ) jsonize_to_blob(&p->aCol[2], pY->z+x, pY->n - x, &iCol);
blob_append(&p->aCol[2], "</ins>\n", -1);
}
static void dfunifiedEnd(DiffBuilder *p){
dfunifiedEmitInsert(p);
blob_append(p->pOut,
"</pre></td>\n"
"<td class=\"udifftxt\" width=\"100%\"><pre class=\"udifftxt\">\n",
-1);
blob_append(p->pOut, blob_buffer(&p->aCol[0]), blob_size(&p->aCol[0]));
blob_reset(&p->aCol[0]);
blob_append(p->pOut, "</pre></td></tr>\n</table>\n", -1);
fossil_free(p);
}
static DiffBuilder *dfunifiedNew(Blob *pOut){
DiffBuilder *p = fossil_malloc(sizeof(*p));
p->xSkip = dfunifiedSkip;
p->xCommon = dfunifiedCommon;
p->xInsert = dfunifiedInsert;
p->xDelete = dfunifiedDelete;
p->xEdit = dfunifiedEdit;
p->xEnd = dfunifiedEnd;
p->lnLeft = p->lnRight = 0;
p->pOut = pOut;
blob_append(pOut,
"<table class=\"sbsdiffcols\">\n"
"<tr><td class=\"udiffln\"><pre class=\"udiffln\">\n",
-1);
blob_init(&p->aCol[0], 0, 0);
blob_init(&p->aCol[1], 0, 0);
blob_init(&p->aCol[2], 0, 0);
return p;
}
/****************************************************************************/
/*
** Format a diff using a DiffBuilder object
*/
static void formatDiff(
DContext *p, /* The computed diff */
|
| ︙ | ︙ | |||
1947 1948 1949 1950 1951 1952 1953 |
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
if( r ) skip -= nContext;
if( skip>0 ){
| | | 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 |
/* Show the initial common area */
a += skip;
b += skip;
m = R[r] - skip;
if( r ) skip -= nContext;
if( skip>0 ){
pBuilder->xSkip(pBuilder, skip, 0);
}
for(j=0; j<m; j++){
pBuilder->xCommon(pBuilder, &A[a+j]);
}
a += m;
b += m;
|
| ︙ | ︙ | |||
2022 2023 2024 2025 2026 2027 2028 |
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m && j<nContext; j++){
pBuilder->xCommon(pBuilder, &A[a+j]);
}
}
if( R[r]>nContext ){
| | | 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 |
m = R[r+nr*3];
if( m>nContext ) m = nContext;
for(j=0; j<m && j<nContext; j++){
pBuilder->xCommon(pBuilder, &A[a+j]);
}
}
if( R[r]>nContext ){
pBuilder->xSkip(pBuilder, R[r] - nContext, 1);
}
pBuilder->xEnd(pBuilder);
}
/*
** Compute the optimal longest common subsequence (LCS) using an
|
| ︙ | ︙ | |||
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 |
formatDiff(&c, pRe, diffFlags, pBuilder);
blob_append_char(pOut, '\n');
}else if( diffFlags & DIFF_SIDEBYSIDE ){
sbsDiff(&c, pOut, pRe, diffFlags);
}else if( diffFlags & DIFF_DEBUG ){
DiffBuilder *pBuilder = dfdebugNew(pOut);
formatDiff(&c, pRe, diffFlags, pBuilder);
}else{
contextDiff(&c, pOut, pRe, diffFlags);
}
fossil_free(c.aFrom);
fossil_free(c.aTo);
fossil_free(c.aEdit);
return 0;
| > > > | 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 |
formatDiff(&c, pRe, diffFlags, pBuilder);
blob_append_char(pOut, '\n');
}else if( diffFlags & DIFF_SIDEBYSIDE ){
sbsDiff(&c, pOut, pRe, diffFlags);
}else if( diffFlags & DIFF_DEBUG ){
DiffBuilder *pBuilder = dfdebugNew(pOut);
formatDiff(&c, pRe, diffFlags, pBuilder);
}else if( diffFlags & DIFF_HTML ){
DiffBuilder *pBuilder = dfunifiedNew(pOut);
formatDiff(&c, pRe, diffFlags, pBuilder);
}else{
contextDiff(&c, pOut, pRe, diffFlags);
}
fossil_free(c.aFrom);
fossil_free(c.aTo);
fossil_free(c.aEdit);
return 0;
|
| ︙ | ︙ |
Changes to src/diffcmd.c.
| ︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 |
if( !diffBlob ){
fossil_print("%s", z);
}else{
blob_appendf(diffBlob, "%s", z);
}
fossil_free(z);
}
/*
| > < > | > > > > > | | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 |
if( !diffBlob ){
fossil_print("%s", z);
}else{
blob_appendf(diffBlob, "%s", z);
}
fossil_free(z);
}
/*
** Default header text for diff with --webpage
*/
static const char zWebpageHdr[] =
@ <!DOCTYPE html>
@ <html>
@ <head>
@ <meta charset="UTF-8">
@ <style>
@ table.sbsdiffcols {
@ width: 90%%;
@ border-spacing: 0;
@ font-size: small;
@ }
@ table.sbsdiffcols td {
@ padding: 0;
@ vertical-align: top;
@ }
|
| ︙ | ︙ | |||
203 204 205 206 207 208 209 |
@ div.difftxtcol {
@ width: 10em;
@ overflow-x: auto;
@ }
@ div.diffmkrcol {
@ padding: 0 1em;
@ }
| < < < < < < < < < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
@ div.difftxtcol {
@ width: 10em;
@ overflow-x: auto;
@ }
@ div.diffmkrcol {
@ padding: 0 1em;
@ }
@ span.diffchng {
@ background-color: #c0c0ff;
@ }
@ span.diffadd {
@ background-color: #c0ffc0;
@ }
@ span.diffrm {
@ background-color: #ffc8c8;
@ }
@ span.diffhr {
@ display: inline-block;
@ margin: .5em 0 1em;
@ color: #0000ff;
@ }
@ span.diffln {
@ color: #a0a0a0;
@ }
@ table.udiff {
@ width: 90%%;
@ border-spacing: 0;
@ }
@ pre.udiffln {
@ color: #a0a0a0;
@ }
@ pre.udiffln ins {
@ background-color: #a0e4b2;
@ text-decoration: none;
@ }
@ pre.udiffln del {
@ background-color: #ffc0c0;
@ text-decoration: none;
@ }
@ pre.udifftxt ins {
@ background-color: #dafbe1;
@ text-decoration: none;
@ }
@ pre.udifftxt del {
@ background-color: #ffe8e8;
@ text-decoration: none;
@ }
@ pre.udifftxt ins mark {
@ background-color: #a0e4b2;
@ text-decoration: none;
@ }
@ pre.udifftxt del mark {
@ background-color: #ffc0c0;
@ text-decoration: none;
@ }
@ h1 {
@ font-size: 150%%;
@ }
@ </style>
@ </head>
@ <body>
;
|
| ︙ | ︙ | |||
299 300 301 302 303 304 305 |
#ifndef _WIN32
signal(SIGINT, diff_www_interrupt);
#else
SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
#endif
}
if( (diffFlags & DIFF_WEBPAGE)!=0 ){
| < < < < < < | | 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
#ifndef _WIN32
signal(SIGINT, diff_www_interrupt);
#else
SetConsoleCtrlHandler(diff_console_ctrl_handler, TRUE);
#endif
}
if( (diffFlags & DIFF_WEBPAGE)!=0 ){
fossil_print(zWebpageHdr/*works-like:""*/);
fflush(stdout);
}
}
/* Do any final output required by a diff and complete the diff
** process.
**
|
| ︙ | ︙ |