Fossil SCM
Improved alignment of partial line diffs. More work to be done in this area. Also fix a problem in diff.js that was causing problems when comparing two empty files.
Commit
24d28cb7c980001899e67604a8e049867fcc00f212ed1c46484e7fdf7846089f
Parent
3e08b15858b770f…
2 files changed
+75
-3
+2
-1
+75
-3
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -458,11 +458,11 @@ | ||
| 458 | 458 | } |
| 459 | 459 | |
| 460 | 460 | #define MX_CSN 8 /* Maximum number of change spans across a change region */ |
| 461 | 461 | |
| 462 | 462 | /* |
| 463 | -** A description of zero or more (up to SBS_CSN) areas of commonality | |
| 463 | +** A description of zero or more (up to MX_CSN) areas of difference | |
| 464 | 464 | ** between two lines of text. |
| 465 | 465 | */ |
| 466 | 466 | typedef struct LineChange LineChange; |
| 467 | 467 | struct LineChange { |
| 468 | 468 | int n; /* Number of change spans */ |
| @@ -532,11 +532,11 @@ | ||
| 532 | 532 | p->a[0].iStart1 = 0; |
| 533 | 533 | p->a[0].iLen1 = nA; |
| 534 | 534 | p->a[0].iStart2 = 0; |
| 535 | 535 | p->a[0].iLen2 = nB; |
| 536 | 536 | p->a[0].isMin = 0; |
| 537 | - while( p->n<MX_CSN ){ | |
| 537 | + while( p->n<MX_CSN-1 ){ | |
| 538 | 538 | int mxi = -1; |
| 539 | 539 | int mxLen = -1; |
| 540 | 540 | int x, i; |
| 541 | 541 | int aLCS[4]; |
| 542 | 542 | struct Span *a, *b; |
| @@ -570,10 +570,78 @@ | ||
| 570 | 570 | a->iLen2 = aLCS[2]; |
| 571 | 571 | b->isMin = 0; |
| 572 | 572 | } |
| 573 | 573 | return p->n; |
| 574 | 574 | } |
| 575 | + | |
| 576 | +/* | |
| 577 | +** Return true if the string starts with n spaces | |
| 578 | +*/ | |
| 579 | +static int allSpaces(const char *z, int n){ | |
| 580 | + int i; | |
| 581 | + for(i=0; i<n && fossil_isspace(z[i]); i++){} | |
| 582 | + return i==n; | |
| 583 | +} | |
| 584 | + | |
| 585 | +/* | |
| 586 | +** Try to improve the human-readability of the LineChange p. | |
| 587 | +** | |
| 588 | +** (1) If the first change span shows a change of indentation, try to | |
| 589 | +** move that indentation change to the left margin. | |
| 590 | +** | |
| 591 | +** (2) Try to shift changes so that they begin or end with a space. | |
| 592 | +*/ | |
| 593 | +static void improveReadability( | |
| 594 | + const char *zA, /* Left line of the change */ | |
| 595 | + const char *zB, /* Right line of the change */ | |
| 596 | + LineChange *p /* The LineChange to be adjusted */ | |
| 597 | +){ | |
| 598 | + int j, n, len; | |
| 599 | + if( p->n<1 ) return; | |
| 600 | + | |
| 601 | + /* (1) Attempt to move indentation changes to the left margin */ | |
| 602 | + if( p->a[0].iLen1==0 | |
| 603 | + && (len = p->a[0].iLen2)>0 | |
| 604 | + && (j = p->a[0].iStart2)>0 | |
| 605 | + && zB[0]==zB[j] | |
| 606 | + && allSpaces(zB, j) | |
| 607 | + ){ | |
| 608 | + for(n=1; n<len && n<j && zB[j]==zB[j+n]; n++){} | |
| 609 | + if( n<len ){ | |
| 610 | + memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n); | |
| 611 | + p->n++; | |
| 612 | + p->a[0] = p->a[1]; | |
| 613 | + p->a[1].iStart2 += n; | |
| 614 | + p->a[1].iLen2 -= n; | |
| 615 | + p->a[0].iLen2 = n; | |
| 616 | + } | |
| 617 | + p->a[0].iStart1 = 0; | |
| 618 | + p->a[0].iStart2 = 0; | |
| 619 | + }else | |
| 620 | + if( p->a[0].iLen2==0 | |
| 621 | + && (len = p->a[0].iLen1)>0 | |
| 622 | + && (j = p->a[0].iStart1)>0 | |
| 623 | + && zA[0]==zA[j] | |
| 624 | + && allSpaces(zA, j) | |
| 625 | + ){ | |
| 626 | + for(n=1; n<len && n<j && zA[j]==zA[j+n]; n++){} | |
| 627 | + if( n<len ){ | |
| 628 | + memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n); | |
| 629 | + p->n++; | |
| 630 | + p->a[0] = p->a[1]; | |
| 631 | + p->a[1].iStart1 += n; | |
| 632 | + p->a[1].iLen1 -= n; | |
| 633 | + p->a[0].iLen1 = n; | |
| 634 | + } | |
| 635 | + p->a[0].iStart1 = 0; | |
| 636 | + p->a[0].iStart2 = 0; | |
| 637 | + } | |
| 638 | + | |
| 639 | + /* (2) Try to shift changes so that they begin or end with a | |
| 640 | + ** space. (TBD) */ | |
| 641 | +} | |
| 642 | + | |
| 575 | 643 | |
| 576 | 644 | /* |
| 577 | 645 | ** Given two lines of text, pFrom and pTo, compute a set of changes |
| 578 | 646 | ** between those two lines, for enhanced display purposes. |
| 579 | 647 | ** |
| @@ -662,10 +730,11 @@ | ||
| 662 | 730 | p->n = 1; |
| 663 | 731 | p->a[0].iStart1 = nPrefix; |
| 664 | 732 | p->a[0].iLen1 = 0; |
| 665 | 733 | p->a[0].iStart2 = nPrefix; |
| 666 | 734 | p->a[0].iLen2 = nRight - nCommon; |
| 735 | + improveReadability(zLeft, zRight, p); | |
| 667 | 736 | return; |
| 668 | 737 | } |
| 669 | 738 | |
| 670 | 739 | /* A single chunk of text deleted */ |
| 671 | 740 | if( nCommon==nRight ){ |
| @@ -672,10 +741,11 @@ | ||
| 672 | 741 | p->n = 1; |
| 673 | 742 | p->a[0].iStart1 = nPrefix; |
| 674 | 743 | p->a[0].iLen1 = nLeft - nCommon; |
| 675 | 744 | p->a[0].iStart2 = nPrefix; |
| 676 | 745 | p->a[0].iLen2 = 0; |
| 746 | + improveReadability(zLeft, zRight, p); | |
| 677 | 747 | return; |
| 678 | 748 | } |
| 679 | 749 | |
| 680 | 750 | /* At this point we know that there is a chunk of text that has |
| 681 | 751 | ** changed between the left and the right. Check to see if there |
| @@ -691,19 +761,21 @@ | ||
| 691 | 761 | int i; |
| 692 | 762 | for(i=0; i<p->n; i++){ |
| 693 | 763 | p->a[i].iStart1 += nPrefix; |
| 694 | 764 | p->a[i].iStart2 += nPrefix; |
| 695 | 765 | } |
| 766 | + improveReadability(zLeft, zRight, p); | |
| 696 | 767 | return; |
| 697 | 768 | } |
| 698 | 769 | |
| 699 | 770 | /* If all else fails, show a single big change between left and right */ |
| 700 | 771 | p->n = 1; |
| 701 | 772 | p->a[0].iStart1 = nPrefix; |
| 702 | 773 | p->a[0].iLen1 = nLeft - nCommon; |
| 703 | 774 | p->a[0].iStart2 = nPrefix; |
| 704 | 775 | p->a[0].iLen2 = nRight - nCommon; |
| 776 | + improveReadability(zLeft, zRight, p); | |
| 705 | 777 | } |
| 706 | 778 | |
| 707 | 779 | /* |
| 708 | 780 | ** COMMAND: test-line-diff |
| 709 | 781 | ** Usage: %fossil% test-line-diff STRING1 STRING2 |
| @@ -1625,11 +1697,11 @@ | ||
| 1625 | 1697 | blob_append_char(&p->aCol[3], '\n'); |
| 1626 | 1698 | } |
| 1627 | 1699 | static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1628 | 1700 | int i; |
| 1629 | 1701 | int x; |
| 1630 | - LineChange chng; | |
| 1702 | + LineChange chng; | |
| 1631 | 1703 | oneLineChange(pX, pY, &chng); |
| 1632 | 1704 | dfsplitStartRow(p); |
| 1633 | 1705 | dfsplitChangeState(p, 3); |
| 1634 | 1706 | p->lnLeft++; |
| 1635 | 1707 | p->lnRight++; |
| 1636 | 1708 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -458,11 +458,11 @@ | |
| 458 | } |
| 459 | |
| 460 | #define MX_CSN 8 /* Maximum number of change spans across a change region */ |
| 461 | |
| 462 | /* |
| 463 | ** A description of zero or more (up to SBS_CSN) areas of commonality |
| 464 | ** between two lines of text. |
| 465 | */ |
| 466 | typedef struct LineChange LineChange; |
| 467 | struct LineChange { |
| 468 | int n; /* Number of change spans */ |
| @@ -532,11 +532,11 @@ | |
| 532 | p->a[0].iStart1 = 0; |
| 533 | p->a[0].iLen1 = nA; |
| 534 | p->a[0].iStart2 = 0; |
| 535 | p->a[0].iLen2 = nB; |
| 536 | p->a[0].isMin = 0; |
| 537 | while( p->n<MX_CSN ){ |
| 538 | int mxi = -1; |
| 539 | int mxLen = -1; |
| 540 | int x, i; |
| 541 | int aLCS[4]; |
| 542 | struct Span *a, *b; |
| @@ -570,10 +570,78 @@ | |
| 570 | a->iLen2 = aLCS[2]; |
| 571 | b->isMin = 0; |
| 572 | } |
| 573 | return p->n; |
| 574 | } |
| 575 | |
| 576 | /* |
| 577 | ** Given two lines of text, pFrom and pTo, compute a set of changes |
| 578 | ** between those two lines, for enhanced display purposes. |
| 579 | ** |
| @@ -662,10 +730,11 @@ | |
| 662 | p->n = 1; |
| 663 | p->a[0].iStart1 = nPrefix; |
| 664 | p->a[0].iLen1 = 0; |
| 665 | p->a[0].iStart2 = nPrefix; |
| 666 | p->a[0].iLen2 = nRight - nCommon; |
| 667 | return; |
| 668 | } |
| 669 | |
| 670 | /* A single chunk of text deleted */ |
| 671 | if( nCommon==nRight ){ |
| @@ -672,10 +741,11 @@ | |
| 672 | p->n = 1; |
| 673 | p->a[0].iStart1 = nPrefix; |
| 674 | p->a[0].iLen1 = nLeft - nCommon; |
| 675 | p->a[0].iStart2 = nPrefix; |
| 676 | p->a[0].iLen2 = 0; |
| 677 | return; |
| 678 | } |
| 679 | |
| 680 | /* At this point we know that there is a chunk of text that has |
| 681 | ** changed between the left and the right. Check to see if there |
| @@ -691,19 +761,21 @@ | |
| 691 | int i; |
| 692 | for(i=0; i<p->n; i++){ |
| 693 | p->a[i].iStart1 += nPrefix; |
| 694 | p->a[i].iStart2 += nPrefix; |
| 695 | } |
| 696 | return; |
| 697 | } |
| 698 | |
| 699 | /* If all else fails, show a single big change between left and right */ |
| 700 | p->n = 1; |
| 701 | p->a[0].iStart1 = nPrefix; |
| 702 | p->a[0].iLen1 = nLeft - nCommon; |
| 703 | p->a[0].iStart2 = nPrefix; |
| 704 | p->a[0].iLen2 = nRight - nCommon; |
| 705 | } |
| 706 | |
| 707 | /* |
| 708 | ** COMMAND: test-line-diff |
| 709 | ** Usage: %fossil% test-line-diff STRING1 STRING2 |
| @@ -1625,11 +1697,11 @@ | |
| 1625 | blob_append_char(&p->aCol[3], '\n'); |
| 1626 | } |
| 1627 | static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1628 | int i; |
| 1629 | int x; |
| 1630 | LineChange chng; |
| 1631 | oneLineChange(pX, pY, &chng); |
| 1632 | dfsplitStartRow(p); |
| 1633 | dfsplitChangeState(p, 3); |
| 1634 | p->lnLeft++; |
| 1635 | p->lnRight++; |
| 1636 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -458,11 +458,11 @@ | |
| 458 | } |
| 459 | |
| 460 | #define MX_CSN 8 /* Maximum number of change spans across a change region */ |
| 461 | |
| 462 | /* |
| 463 | ** A description of zero or more (up to MX_CSN) areas of difference |
| 464 | ** between two lines of text. |
| 465 | */ |
| 466 | typedef struct LineChange LineChange; |
| 467 | struct LineChange { |
| 468 | int n; /* Number of change spans */ |
| @@ -532,11 +532,11 @@ | |
| 532 | p->a[0].iStart1 = 0; |
| 533 | p->a[0].iLen1 = nA; |
| 534 | p->a[0].iStart2 = 0; |
| 535 | p->a[0].iLen2 = nB; |
| 536 | p->a[0].isMin = 0; |
| 537 | while( p->n<MX_CSN-1 ){ |
| 538 | int mxi = -1; |
| 539 | int mxLen = -1; |
| 540 | int x, i; |
| 541 | int aLCS[4]; |
| 542 | struct Span *a, *b; |
| @@ -570,10 +570,78 @@ | |
| 570 | a->iLen2 = aLCS[2]; |
| 571 | b->isMin = 0; |
| 572 | } |
| 573 | return p->n; |
| 574 | } |
| 575 | |
| 576 | /* |
| 577 | ** Return true if the string starts with n spaces |
| 578 | */ |
| 579 | static int allSpaces(const char *z, int n){ |
| 580 | int i; |
| 581 | for(i=0; i<n && fossil_isspace(z[i]); i++){} |
| 582 | return i==n; |
| 583 | } |
| 584 | |
| 585 | /* |
| 586 | ** Try to improve the human-readability of the LineChange p. |
| 587 | ** |
| 588 | ** (1) If the first change span shows a change of indentation, try to |
| 589 | ** move that indentation change to the left margin. |
| 590 | ** |
| 591 | ** (2) Try to shift changes so that they begin or end with a space. |
| 592 | */ |
| 593 | static void improveReadability( |
| 594 | const char *zA, /* Left line of the change */ |
| 595 | const char *zB, /* Right line of the change */ |
| 596 | LineChange *p /* The LineChange to be adjusted */ |
| 597 | ){ |
| 598 | int j, n, len; |
| 599 | if( p->n<1 ) return; |
| 600 | |
| 601 | /* (1) Attempt to move indentation changes to the left margin */ |
| 602 | if( p->a[0].iLen1==0 |
| 603 | && (len = p->a[0].iLen2)>0 |
| 604 | && (j = p->a[0].iStart2)>0 |
| 605 | && zB[0]==zB[j] |
| 606 | && allSpaces(zB, j) |
| 607 | ){ |
| 608 | for(n=1; n<len && n<j && zB[j]==zB[j+n]; n++){} |
| 609 | if( n<len ){ |
| 610 | memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n); |
| 611 | p->n++; |
| 612 | p->a[0] = p->a[1]; |
| 613 | p->a[1].iStart2 += n; |
| 614 | p->a[1].iLen2 -= n; |
| 615 | p->a[0].iLen2 = n; |
| 616 | } |
| 617 | p->a[0].iStart1 = 0; |
| 618 | p->a[0].iStart2 = 0; |
| 619 | }else |
| 620 | if( p->a[0].iLen2==0 |
| 621 | && (len = p->a[0].iLen1)>0 |
| 622 | && (j = p->a[0].iStart1)>0 |
| 623 | && zA[0]==zA[j] |
| 624 | && allSpaces(zA, j) |
| 625 | ){ |
| 626 | for(n=1; n<len && n<j && zA[j]==zA[j+n]; n++){} |
| 627 | if( n<len ){ |
| 628 | memmove(&p->a[1], &p->a[0], sizeof(p->a[0])*p->n); |
| 629 | p->n++; |
| 630 | p->a[0] = p->a[1]; |
| 631 | p->a[1].iStart1 += n; |
| 632 | p->a[1].iLen1 -= n; |
| 633 | p->a[0].iLen1 = n; |
| 634 | } |
| 635 | p->a[0].iStart1 = 0; |
| 636 | p->a[0].iStart2 = 0; |
| 637 | } |
| 638 | |
| 639 | /* (2) Try to shift changes so that they begin or end with a |
| 640 | ** space. (TBD) */ |
| 641 | } |
| 642 | |
| 643 | |
| 644 | /* |
| 645 | ** Given two lines of text, pFrom and pTo, compute a set of changes |
| 646 | ** between those two lines, for enhanced display purposes. |
| 647 | ** |
| @@ -662,10 +730,11 @@ | |
| 730 | p->n = 1; |
| 731 | p->a[0].iStart1 = nPrefix; |
| 732 | p->a[0].iLen1 = 0; |
| 733 | p->a[0].iStart2 = nPrefix; |
| 734 | p->a[0].iLen2 = nRight - nCommon; |
| 735 | improveReadability(zLeft, zRight, p); |
| 736 | return; |
| 737 | } |
| 738 | |
| 739 | /* A single chunk of text deleted */ |
| 740 | if( nCommon==nRight ){ |
| @@ -672,10 +741,11 @@ | |
| 741 | p->n = 1; |
| 742 | p->a[0].iStart1 = nPrefix; |
| 743 | p->a[0].iLen1 = nLeft - nCommon; |
| 744 | p->a[0].iStart2 = nPrefix; |
| 745 | p->a[0].iLen2 = 0; |
| 746 | improveReadability(zLeft, zRight, p); |
| 747 | return; |
| 748 | } |
| 749 | |
| 750 | /* At this point we know that there is a chunk of text that has |
| 751 | ** changed between the left and the right. Check to see if there |
| @@ -691,19 +761,21 @@ | |
| 761 | int i; |
| 762 | for(i=0; i<p->n; i++){ |
| 763 | p->a[i].iStart1 += nPrefix; |
| 764 | p->a[i].iStart2 += nPrefix; |
| 765 | } |
| 766 | improveReadability(zLeft, zRight, p); |
| 767 | return; |
| 768 | } |
| 769 | |
| 770 | /* If all else fails, show a single big change between left and right */ |
| 771 | p->n = 1; |
| 772 | p->a[0].iStart1 = nPrefix; |
| 773 | p->a[0].iLen1 = nLeft - nCommon; |
| 774 | p->a[0].iStart2 = nPrefix; |
| 775 | p->a[0].iLen2 = nRight - nCommon; |
| 776 | improveReadability(zLeft, zRight, p); |
| 777 | } |
| 778 | |
| 779 | /* |
| 780 | ** COMMAND: test-line-diff |
| 781 | ** Usage: %fossil% test-line-diff STRING1 STRING2 |
| @@ -1625,11 +1697,11 @@ | |
| 1697 | blob_append_char(&p->aCol[3], '\n'); |
| 1698 | } |
| 1699 | static void dfsplitEdit(DiffBuilder *p, const DLine *pX, const DLine *pY){ |
| 1700 | int i; |
| 1701 | int x; |
| 1702 | LineChange chng; |
| 1703 | oneLineChange(pX, pY, &chng); |
| 1704 | dfsplitStartRow(p); |
| 1705 | dfsplitChangeState(p, 3); |
| 1706 | p->lnLeft++; |
| 1707 | p->lnRight++; |
| 1708 |
+2
-1
| --- src/diff.js | ||
| +++ src/diff.js | ||
| @@ -10,11 +10,12 @@ | ||
| 10 | 10 | (function(){ |
| 11 | 11 | var SCROLL_LEN = 25; |
| 12 | 12 | function initDiff(diff){ |
| 13 | 13 | var txtCols = diff.querySelectorAll('td.difftxt'); |
| 14 | 14 | var txtPres = diff.querySelectorAll('td.difftxt pre'); |
| 15 | - var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth); | |
| 15 | + var width = 0; | |
| 16 | + if(txtPres.length>=2)Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth); | |
| 16 | 17 | var i; |
| 17 | 18 | for(i=0; i<txtCols.length; i++){ |
| 18 | 19 | txtCols[i].style.width = width + 'px'; |
| 19 | 20 | txtPres[i].style.maxWidth = width + 'px'; |
| 20 | 21 | txtPres[i].style.width = width + 'px'; |
| 21 | 22 |
| --- src/diff.js | |
| +++ src/diff.js | |
| @@ -10,11 +10,12 @@ | |
| 10 | (function(){ |
| 11 | var SCROLL_LEN = 25; |
| 12 | function initDiff(diff){ |
| 13 | var txtCols = diff.querySelectorAll('td.difftxt'); |
| 14 | var txtPres = diff.querySelectorAll('td.difftxt pre'); |
| 15 | var width = Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth); |
| 16 | var i; |
| 17 | for(i=0; i<txtCols.length; i++){ |
| 18 | txtCols[i].style.width = width + 'px'; |
| 19 | txtPres[i].style.maxWidth = width + 'px'; |
| 20 | txtPres[i].style.width = width + 'px'; |
| 21 |
| --- src/diff.js | |
| +++ src/diff.js | |
| @@ -10,11 +10,12 @@ | |
| 10 | (function(){ |
| 11 | var SCROLL_LEN = 25; |
| 12 | function initDiff(diff){ |
| 13 | var txtCols = diff.querySelectorAll('td.difftxt'); |
| 14 | var txtPres = diff.querySelectorAll('td.difftxt pre'); |
| 15 | var width = 0; |
| 16 | if(txtPres.length>=2)Math.max(txtPres[0].scrollWidth, txtPres[1].scrollWidth); |
| 17 | var i; |
| 18 | for(i=0; i<txtCols.length; i++){ |
| 19 | txtCols[i].style.width = width + 'px'; |
| 20 | txtPres[i].style.maxWidth = width + 'px'; |
| 21 | txtPres[i].style.width = width + 'px'; |
| 22 |