Fossil SCM
When a line changes in a side-by-side diff, only highlight the part of line that actually changed.
Commit
357d26bc36f40c814147720e02924ff83b358b15
Parent
881b65141b48d72…
2 files changed
+105
-16
+1
-1
+105
-16
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -427,19 +427,21 @@ | ||
| 427 | 427 | typedef struct SbsLine SbsLine; |
| 428 | 428 | struct SbsLine { |
| 429 | 429 | char *zLine; /* The output line under construction */ |
| 430 | 430 | int n; /* Index of next unused slot in the zLine[] */ |
| 431 | 431 | int width; /* Maximum width of a column in the output */ |
| 432 | - unsigned char escHtml; /* True to escape html characters */ | |
| 432 | + unsigned char escHtml; /* True to escape html characters */ | |
| 433 | + int iStart; /* Write zStart prior to character iStart */ | |
| 434 | + const char *zStart; /* A <span> tag */ | |
| 435 | + int iEnd; /* Write </span> prior to character iEnd */ | |
| 433 | 436 | }; |
| 434 | 437 | |
| 435 | 438 | /* |
| 436 | 439 | ** Flags for sbsWriteText() |
| 437 | 440 | */ |
| 438 | -#define SBS_NEWLINE 0x0001 /* End with \n\000 */ | |
| 439 | -#define SBS_PAD 0x0002 /* Pad output to width spaces */ | |
| 440 | -#define SBS_ENDSPAN 0x0004 /* Write a </span> after text */ | |
| 441 | +#define SBS_NEWLINE 0x0001 /* End with \n\000 */ | |
| 442 | +#define SBS_PAD 0x0002 /* Pad output to width spaces */ | |
| 441 | 443 | |
| 442 | 444 | /* |
| 443 | 445 | ** Write up to width characters of pLine into z[]. Translate tabs into |
| 444 | 446 | ** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters |
| 445 | 447 | ** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set. |
| @@ -452,10 +454,20 @@ | ||
| 452 | 454 | const char *zIn = pLine->z; |
| 453 | 455 | char *z = &p->zLine[p->n]; |
| 454 | 456 | int w = p->width; |
| 455 | 457 | for(i=j=k=0; k<w && i<n; i++, k++){ |
| 456 | 458 | char c = zIn[i]; |
| 459 | + if( p->escHtml ){ | |
| 460 | + if( i==p->iStart ){ | |
| 461 | + int x = strlen(p->zStart); | |
| 462 | + memcpy(z+j, p->zStart, x); | |
| 463 | + j += x; | |
| 464 | + }else if( i==p->iEnd ){ | |
| 465 | + memcpy(z+j, "</span>", 7); | |
| 466 | + j += 7; | |
| 467 | + } | |
| 468 | + } | |
| 457 | 469 | if( c=='\t' ){ |
| 458 | 470 | z[j++] = ' '; |
| 459 | 471 | while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; } |
| 460 | 472 | }else if( c=='\r' || c=='\f' ){ |
| 461 | 473 | z[j++] = ' '; |
| @@ -470,11 +482,11 @@ | ||
| 470 | 482 | j += 4; |
| 471 | 483 | }else{ |
| 472 | 484 | z[j++] = c; |
| 473 | 485 | } |
| 474 | 486 | } |
| 475 | - if( (flags & SBS_ENDSPAN) && p->escHtml ){ | |
| 487 | + if( p->escHtml && i<=p->iEnd ){ | |
| 476 | 488 | memcpy(&z[j], "</span>", 7); |
| 477 | 489 | j += 7; |
| 478 | 490 | } |
| 479 | 491 | if( (flags & SBS_PAD)!=0 ){ |
| 480 | 492 | while( k<w ){ k++; z[j++] = ' '; } |
| @@ -516,10 +528,84 @@ | ||
| 516 | 528 | p->n += 6; |
| 517 | 529 | sbsWriteHtml(p, "</span>"); |
| 518 | 530 | p->zLine[p->n++] = ' '; |
| 519 | 531 | } |
| 520 | 532 | |
| 533 | +/* | |
| 534 | +** Write out lines that have been edited. Adjust the highlight to cover | |
| 535 | +** only those parts of the line that actually changed. | |
| 536 | +*/ | |
| 537 | +static void sbsWriteLineChange( | |
| 538 | + SbsLine *p, /* The SBS output line */ | |
| 539 | + DLine *pLeft, /* Left line of the change */ | |
| 540 | + int lnLeft, /* Line number for the left line */ | |
| 541 | + DLine *pRight, /* Right line of the change */ | |
| 542 | + int lnRight /* Line number of the right line */ | |
| 543 | +){ | |
| 544 | + int nLeft; /* Length of left line in bytes */ | |
| 545 | + int nRight; /* Length of right line in bytes */ | |
| 546 | + int nPrefix; /* Length of common prefix */ | |
| 547 | + int nSuffix; /* Length of common suffix */ | |
| 548 | + int width; /* Total column width */ | |
| 549 | + const char *zLeft; /* Text of the left line */ | |
| 550 | + const char *zRight; /* Text of the right line */ | |
| 551 | + | |
| 552 | + nLeft = pLeft->h & LENGTH_MASK; | |
| 553 | + zLeft = pLeft->z; | |
| 554 | + nRight = pRight->h & LENGTH_MASK; | |
| 555 | + zRight = pRight->z; | |
| 556 | + | |
| 557 | + nPrefix = 0; | |
| 558 | + while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){ | |
| 559 | + nPrefix++; | |
| 560 | + } | |
| 561 | + nSuffix = 0; | |
| 562 | + if( nPrefix<nLeft && nPrefix<nRight ){ | |
| 563 | + while( nSuffix<nLeft && nSuffix<nRight | |
| 564 | + && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ | |
| 565 | + nSuffix++; | |
| 566 | + } | |
| 567 | + if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; | |
| 568 | + } | |
| 569 | + if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix; | |
| 570 | + if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix; | |
| 571 | + if( nPrefix+nSuffix==nLeft ){ | |
| 572 | + /* Text inserted on the right */ | |
| 573 | + sbsWriteLineno(p, lnLeft); | |
| 574 | + p->iStart = p->iEnd = -1; | |
| 575 | + sbsWriteText(p, pLeft, SBS_PAD); | |
| 576 | + sbsWrite(p, " | ", 3); | |
| 577 | + sbsWriteLineno(p, lnRight); | |
| 578 | + p->iStart = nPrefix; | |
| 579 | + p->iEnd = nRight - nSuffix; | |
| 580 | + p->zStart = "<span class=\"diffadd\">"; | |
| 581 | + sbsWriteText(p, pRight, SBS_NEWLINE); | |
| 582 | + }else if( nPrefix+nSuffix==nRight ){ | |
| 583 | + /* Text deleted from the left */ | |
| 584 | + sbsWriteLineno(p, lnLeft); | |
| 585 | + p->iStart = nPrefix; | |
| 586 | + p->iEnd = nLeft - nSuffix; | |
| 587 | + p->zStart = "<span class=\"diffrm\">"; | |
| 588 | + sbsWriteText(p, pLeft, SBS_PAD); | |
| 589 | + sbsWrite(p, " | ", 3); | |
| 590 | + sbsWriteLineno(p, lnRight); | |
| 591 | + p->iStart = p->iEnd = -1; | |
| 592 | + sbsWriteText(p, pRight, SBS_NEWLINE); | |
| 593 | + }else{ | |
| 594 | + /* Text modified between left and right */ | |
| 595 | + sbsWriteLineno(p, lnLeft); | |
| 596 | + p->iStart = nPrefix; | |
| 597 | + p->iEnd = nLeft - nSuffix; | |
| 598 | + p->zStart = "<span class=\"diffchng\">"; | |
| 599 | + sbsWriteText(p, pLeft, SBS_PAD); | |
| 600 | + sbsWrite(p, " | ", 3); | |
| 601 | + sbsWriteLineno(p, lnRight); | |
| 602 | + p->iEnd = nRight - nSuffix; | |
| 603 | + sbsWriteText(p, pRight, SBS_NEWLINE); | |
| 604 | + } | |
| 605 | +} | |
| 606 | + | |
| 521 | 607 | |
| 522 | 608 | /* |
| 523 | 609 | ** Given a diff context in which the aEdit[] array has been filled |
| 524 | 610 | ** in, compute a side-by-side diff into pOut. |
| 525 | 611 | */ |
| @@ -546,10 +632,12 @@ | ||
| 546 | 632 | |
| 547 | 633 | s.zLine = fossil_malloc( 10*width + 100 ); |
| 548 | 634 | if( s.zLine==0 ) return; |
| 549 | 635 | s.width = width; |
| 550 | 636 | s.escHtml = escHtml; |
| 637 | + s.iStart = -1; | |
| 638 | + s.iEnd = -1; | |
| 551 | 639 | A = p->aFrom; |
| 552 | 640 | B = p->aTo; |
| 553 | 641 | R = p->aEdit; |
| 554 | 642 | mxr = p->nEdit; |
| 555 | 643 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -599,10 +687,11 @@ | ||
| 599 | 687 | b += skip; |
| 600 | 688 | m = R[r] - skip; |
| 601 | 689 | for(j=0; j<m; j++){ |
| 602 | 690 | s.n = 0; |
| 603 | 691 | sbsWriteLineno(&s, a+j); |
| 692 | + s.iStart = s.iEnd = -1; | |
| 604 | 693 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 605 | 694 | sbsWrite(&s, " ", 3); |
| 606 | 695 | sbsWriteLineno(&s, b+j); |
| 607 | 696 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 608 | 697 | blob_append(pOut, s.zLine, s.n); |
| @@ -619,34 +708,32 @@ | ||
| 619 | 708 | match_dline(&A[a],&B[b]) < match_dline(&A[a],&B[b+1]) ) ){ |
| 620 | 709 | s.n = 0; |
| 621 | 710 | sbsWriteSpace(&s, width + 7); |
| 622 | 711 | sbsWrite(&s, " > ", 3); |
| 623 | 712 | sbsWriteLineno(&s, b); |
| 624 | - sbsWriteHtml(&s, "<span class=\"diffadd\">"); | |
| 625 | - sbsWriteText(&s, &B[b], SBS_NEWLINE | SBS_ENDSPAN); | |
| 713 | + s.iStart = 0; | |
| 714 | + s.zStart = "<span class=\"diffadd\">"; | |
| 715 | + s.iEnd = s.width; | |
| 716 | + sbsWriteText(&s, &B[b], SBS_NEWLINE); | |
| 626 | 717 | blob_append(pOut, s.zLine, s.n); |
| 627 | 718 | mb--; |
| 628 | 719 | b++; |
| 629 | 720 | }else if( ma>mb && (mb==0 || |
| 630 | 721 | match_dline(&A[a],&B[b]) < match_dline(&A[a+1],&B[b])) ){ |
| 631 | 722 | s.n = 0; |
| 632 | 723 | sbsWriteLineno(&s, a); |
| 633 | - sbsWriteHtml(&s, "<span class=\"diffrm\">"); | |
| 634 | - sbsWriteText(&s, &A[a], SBS_PAD | SBS_ENDSPAN); | |
| 724 | + s.iStart = 0; | |
| 725 | + s.zStart = "<span class=\"diffrm\">"; | |
| 726 | + s.iEnd = s.width; | |
| 727 | + sbsWriteText(&s, &A[a], SBS_PAD); | |
| 635 | 728 | sbsWrite(&s, " <\n", 3); |
| 636 | 729 | blob_append(pOut, s.zLine, s.n); |
| 637 | 730 | ma--; |
| 638 | 731 | a++; |
| 639 | 732 | }else{ |
| 640 | 733 | s.n = 0; |
| 641 | - sbsWriteLineno(&s, a); | |
| 642 | - sbsWriteHtml(&s, "<span class=\"diffchng\">"); | |
| 643 | - sbsWriteText(&s, &A[a], SBS_PAD | SBS_ENDSPAN); | |
| 644 | - sbsWrite(&s, " | ", 3); | |
| 645 | - sbsWriteLineno(&s, b); | |
| 646 | - sbsWriteHtml(&s, "<span class=\"diffchng\">"); | |
| 647 | - sbsWriteText(&s, &B[b], SBS_NEWLINE | SBS_ENDSPAN); | |
| 734 | + sbsWriteLineChange(&s, &A[a], a, &B[b], b); | |
| 648 | 735 | blob_append(pOut, s.zLine, s.n); |
| 649 | 736 | ma--; |
| 650 | 737 | mb--; |
| 651 | 738 | a++; |
| 652 | 739 | b++; |
| @@ -655,10 +742,11 @@ | ||
| 655 | 742 | if( i<nr-1 ){ |
| 656 | 743 | m = R[r+i*3+3]; |
| 657 | 744 | for(j=0; j<m; j++){ |
| 658 | 745 | s.n = 0; |
| 659 | 746 | sbsWriteLineno(&s, a+j); |
| 747 | + s.iStart = s.iEnd = -1; | |
| 660 | 748 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 661 | 749 | sbsWrite(&s, " ", 3); |
| 662 | 750 | sbsWriteLineno(&s, b+j); |
| 663 | 751 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 664 | 752 | blob_append(pOut, s.zLine, s.n); |
| @@ -673,10 +761,11 @@ | ||
| 673 | 761 | m = R[r+nr*3]; |
| 674 | 762 | if( m>nContext ) m = nContext; |
| 675 | 763 | for(j=0; j<m; j++){ |
| 676 | 764 | s.n = 0; |
| 677 | 765 | sbsWriteLineno(&s, a+j); |
| 766 | + s.iStart = s.iEnd = -1; | |
| 678 | 767 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 679 | 768 | sbsWrite(&s, " ", 3); |
| 680 | 769 | sbsWriteLineno(&s, b+j); |
| 681 | 770 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 682 | 771 | blob_append(pOut, s.zLine, s.n); |
| 683 | 772 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -427,19 +427,21 @@ | |
| 427 | typedef struct SbsLine SbsLine; |
| 428 | struct SbsLine { |
| 429 | char *zLine; /* The output line under construction */ |
| 430 | int n; /* Index of next unused slot in the zLine[] */ |
| 431 | int width; /* Maximum width of a column in the output */ |
| 432 | unsigned char escHtml; /* True to escape html characters */ |
| 433 | }; |
| 434 | |
| 435 | /* |
| 436 | ** Flags for sbsWriteText() |
| 437 | */ |
| 438 | #define SBS_NEWLINE 0x0001 /* End with \n\000 */ |
| 439 | #define SBS_PAD 0x0002 /* Pad output to width spaces */ |
| 440 | #define SBS_ENDSPAN 0x0004 /* Write a </span> after text */ |
| 441 | |
| 442 | /* |
| 443 | ** Write up to width characters of pLine into z[]. Translate tabs into |
| 444 | ** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters |
| 445 | ** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set. |
| @@ -452,10 +454,20 @@ | |
| 452 | const char *zIn = pLine->z; |
| 453 | char *z = &p->zLine[p->n]; |
| 454 | int w = p->width; |
| 455 | for(i=j=k=0; k<w && i<n; i++, k++){ |
| 456 | char c = zIn[i]; |
| 457 | if( c=='\t' ){ |
| 458 | z[j++] = ' '; |
| 459 | while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; } |
| 460 | }else if( c=='\r' || c=='\f' ){ |
| 461 | z[j++] = ' '; |
| @@ -470,11 +482,11 @@ | |
| 470 | j += 4; |
| 471 | }else{ |
| 472 | z[j++] = c; |
| 473 | } |
| 474 | } |
| 475 | if( (flags & SBS_ENDSPAN) && p->escHtml ){ |
| 476 | memcpy(&z[j], "</span>", 7); |
| 477 | j += 7; |
| 478 | } |
| 479 | if( (flags & SBS_PAD)!=0 ){ |
| 480 | while( k<w ){ k++; z[j++] = ' '; } |
| @@ -516,10 +528,84 @@ | |
| 516 | p->n += 6; |
| 517 | sbsWriteHtml(p, "</span>"); |
| 518 | p->zLine[p->n++] = ' '; |
| 519 | } |
| 520 | |
| 521 | |
| 522 | /* |
| 523 | ** Given a diff context in which the aEdit[] array has been filled |
| 524 | ** in, compute a side-by-side diff into pOut. |
| 525 | */ |
| @@ -546,10 +632,12 @@ | |
| 546 | |
| 547 | s.zLine = fossil_malloc( 10*width + 100 ); |
| 548 | if( s.zLine==0 ) return; |
| 549 | s.width = width; |
| 550 | s.escHtml = escHtml; |
| 551 | A = p->aFrom; |
| 552 | B = p->aTo; |
| 553 | R = p->aEdit; |
| 554 | mxr = p->nEdit; |
| 555 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -599,10 +687,11 @@ | |
| 599 | b += skip; |
| 600 | m = R[r] - skip; |
| 601 | for(j=0; j<m; j++){ |
| 602 | s.n = 0; |
| 603 | sbsWriteLineno(&s, a+j); |
| 604 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 605 | sbsWrite(&s, " ", 3); |
| 606 | sbsWriteLineno(&s, b+j); |
| 607 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 608 | blob_append(pOut, s.zLine, s.n); |
| @@ -619,34 +708,32 @@ | |
| 619 | match_dline(&A[a],&B[b]) < match_dline(&A[a],&B[b+1]) ) ){ |
| 620 | s.n = 0; |
| 621 | sbsWriteSpace(&s, width + 7); |
| 622 | sbsWrite(&s, " > ", 3); |
| 623 | sbsWriteLineno(&s, b); |
| 624 | sbsWriteHtml(&s, "<span class=\"diffadd\">"); |
| 625 | sbsWriteText(&s, &B[b], SBS_NEWLINE | SBS_ENDSPAN); |
| 626 | blob_append(pOut, s.zLine, s.n); |
| 627 | mb--; |
| 628 | b++; |
| 629 | }else if( ma>mb && (mb==0 || |
| 630 | match_dline(&A[a],&B[b]) < match_dline(&A[a+1],&B[b])) ){ |
| 631 | s.n = 0; |
| 632 | sbsWriteLineno(&s, a); |
| 633 | sbsWriteHtml(&s, "<span class=\"diffrm\">"); |
| 634 | sbsWriteText(&s, &A[a], SBS_PAD | SBS_ENDSPAN); |
| 635 | sbsWrite(&s, " <\n", 3); |
| 636 | blob_append(pOut, s.zLine, s.n); |
| 637 | ma--; |
| 638 | a++; |
| 639 | }else{ |
| 640 | s.n = 0; |
| 641 | sbsWriteLineno(&s, a); |
| 642 | sbsWriteHtml(&s, "<span class=\"diffchng\">"); |
| 643 | sbsWriteText(&s, &A[a], SBS_PAD | SBS_ENDSPAN); |
| 644 | sbsWrite(&s, " | ", 3); |
| 645 | sbsWriteLineno(&s, b); |
| 646 | sbsWriteHtml(&s, "<span class=\"diffchng\">"); |
| 647 | sbsWriteText(&s, &B[b], SBS_NEWLINE | SBS_ENDSPAN); |
| 648 | blob_append(pOut, s.zLine, s.n); |
| 649 | ma--; |
| 650 | mb--; |
| 651 | a++; |
| 652 | b++; |
| @@ -655,10 +742,11 @@ | |
| 655 | if( i<nr-1 ){ |
| 656 | m = R[r+i*3+3]; |
| 657 | for(j=0; j<m; j++){ |
| 658 | s.n = 0; |
| 659 | sbsWriteLineno(&s, a+j); |
| 660 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 661 | sbsWrite(&s, " ", 3); |
| 662 | sbsWriteLineno(&s, b+j); |
| 663 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 664 | blob_append(pOut, s.zLine, s.n); |
| @@ -673,10 +761,11 @@ | |
| 673 | m = R[r+nr*3]; |
| 674 | if( m>nContext ) m = nContext; |
| 675 | for(j=0; j<m; j++){ |
| 676 | s.n = 0; |
| 677 | sbsWriteLineno(&s, a+j); |
| 678 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 679 | sbsWrite(&s, " ", 3); |
| 680 | sbsWriteLineno(&s, b+j); |
| 681 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 682 | blob_append(pOut, s.zLine, s.n); |
| 683 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -427,19 +427,21 @@ | |
| 427 | typedef struct SbsLine SbsLine; |
| 428 | struct SbsLine { |
| 429 | char *zLine; /* The output line under construction */ |
| 430 | int n; /* Index of next unused slot in the zLine[] */ |
| 431 | int width; /* Maximum width of a column in the output */ |
| 432 | unsigned char escHtml; /* True to escape html characters */ |
| 433 | int iStart; /* Write zStart prior to character iStart */ |
| 434 | const char *zStart; /* A <span> tag */ |
| 435 | int iEnd; /* Write </span> prior to character iEnd */ |
| 436 | }; |
| 437 | |
| 438 | /* |
| 439 | ** Flags for sbsWriteText() |
| 440 | */ |
| 441 | #define SBS_NEWLINE 0x0001 /* End with \n\000 */ |
| 442 | #define SBS_PAD 0x0002 /* Pad output to width spaces */ |
| 443 | |
| 444 | /* |
| 445 | ** Write up to width characters of pLine into z[]. Translate tabs into |
| 446 | ** spaces. Add a newline if SBS_NEWLINE is set. Translate HTML characters |
| 447 | ** if SBS_HTML is set. Pad the rendering out width bytes if SBS_PAD is set. |
| @@ -452,10 +454,20 @@ | |
| 454 | const char *zIn = pLine->z; |
| 455 | char *z = &p->zLine[p->n]; |
| 456 | int w = p->width; |
| 457 | for(i=j=k=0; k<w && i<n; i++, k++){ |
| 458 | char c = zIn[i]; |
| 459 | if( p->escHtml ){ |
| 460 | if( i==p->iStart ){ |
| 461 | int x = strlen(p->zStart); |
| 462 | memcpy(z+j, p->zStart, x); |
| 463 | j += x; |
| 464 | }else if( i==p->iEnd ){ |
| 465 | memcpy(z+j, "</span>", 7); |
| 466 | j += 7; |
| 467 | } |
| 468 | } |
| 469 | if( c=='\t' ){ |
| 470 | z[j++] = ' '; |
| 471 | while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; } |
| 472 | }else if( c=='\r' || c=='\f' ){ |
| 473 | z[j++] = ' '; |
| @@ -470,11 +482,11 @@ | |
| 482 | j += 4; |
| 483 | }else{ |
| 484 | z[j++] = c; |
| 485 | } |
| 486 | } |
| 487 | if( p->escHtml && i<=p->iEnd ){ |
| 488 | memcpy(&z[j], "</span>", 7); |
| 489 | j += 7; |
| 490 | } |
| 491 | if( (flags & SBS_PAD)!=0 ){ |
| 492 | while( k<w ){ k++; z[j++] = ' '; } |
| @@ -516,10 +528,84 @@ | |
| 528 | p->n += 6; |
| 529 | sbsWriteHtml(p, "</span>"); |
| 530 | p->zLine[p->n++] = ' '; |
| 531 | } |
| 532 | |
| 533 | /* |
| 534 | ** Write out lines that have been edited. Adjust the highlight to cover |
| 535 | ** only those parts of the line that actually changed. |
| 536 | */ |
| 537 | static void sbsWriteLineChange( |
| 538 | SbsLine *p, /* The SBS output line */ |
| 539 | DLine *pLeft, /* Left line of the change */ |
| 540 | int lnLeft, /* Line number for the left line */ |
| 541 | DLine *pRight, /* Right line of the change */ |
| 542 | int lnRight /* Line number of the right line */ |
| 543 | ){ |
| 544 | int nLeft; /* Length of left line in bytes */ |
| 545 | int nRight; /* Length of right line in bytes */ |
| 546 | int nPrefix; /* Length of common prefix */ |
| 547 | int nSuffix; /* Length of common suffix */ |
| 548 | int width; /* Total column width */ |
| 549 | const char *zLeft; /* Text of the left line */ |
| 550 | const char *zRight; /* Text of the right line */ |
| 551 | |
| 552 | nLeft = pLeft->h & LENGTH_MASK; |
| 553 | zLeft = pLeft->z; |
| 554 | nRight = pRight->h & LENGTH_MASK; |
| 555 | zRight = pRight->z; |
| 556 | |
| 557 | nPrefix = 0; |
| 558 | while( nPrefix<nLeft && nPrefix<nRight && zLeft[nPrefix]==zRight[nPrefix] ){ |
| 559 | nPrefix++; |
| 560 | } |
| 561 | nSuffix = 0; |
| 562 | if( nPrefix<nLeft && nPrefix<nRight ){ |
| 563 | while( nSuffix<nLeft && nSuffix<nRight |
| 564 | && zLeft[nLeft-nSuffix-1]==zRight[nRight-nSuffix-1] ){ |
| 565 | nSuffix++; |
| 566 | } |
| 567 | if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0; |
| 568 | } |
| 569 | if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix; |
| 570 | if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix; |
| 571 | if( nPrefix+nSuffix==nLeft ){ |
| 572 | /* Text inserted on the right */ |
| 573 | sbsWriteLineno(p, lnLeft); |
| 574 | p->iStart = p->iEnd = -1; |
| 575 | sbsWriteText(p, pLeft, SBS_PAD); |
| 576 | sbsWrite(p, " | ", 3); |
| 577 | sbsWriteLineno(p, lnRight); |
| 578 | p->iStart = nPrefix; |
| 579 | p->iEnd = nRight - nSuffix; |
| 580 | p->zStart = "<span class=\"diffadd\">"; |
| 581 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 582 | }else if( nPrefix+nSuffix==nRight ){ |
| 583 | /* Text deleted from the left */ |
| 584 | sbsWriteLineno(p, lnLeft); |
| 585 | p->iStart = nPrefix; |
| 586 | p->iEnd = nLeft - nSuffix; |
| 587 | p->zStart = "<span class=\"diffrm\">"; |
| 588 | sbsWriteText(p, pLeft, SBS_PAD); |
| 589 | sbsWrite(p, " | ", 3); |
| 590 | sbsWriteLineno(p, lnRight); |
| 591 | p->iStart = p->iEnd = -1; |
| 592 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 593 | }else{ |
| 594 | /* Text modified between left and right */ |
| 595 | sbsWriteLineno(p, lnLeft); |
| 596 | p->iStart = nPrefix; |
| 597 | p->iEnd = nLeft - nSuffix; |
| 598 | p->zStart = "<span class=\"diffchng\">"; |
| 599 | sbsWriteText(p, pLeft, SBS_PAD); |
| 600 | sbsWrite(p, " | ", 3); |
| 601 | sbsWriteLineno(p, lnRight); |
| 602 | p->iEnd = nRight - nSuffix; |
| 603 | sbsWriteText(p, pRight, SBS_NEWLINE); |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | |
| 608 | /* |
| 609 | ** Given a diff context in which the aEdit[] array has been filled |
| 610 | ** in, compute a side-by-side diff into pOut. |
| 611 | */ |
| @@ -546,10 +632,12 @@ | |
| 632 | |
| 633 | s.zLine = fossil_malloc( 10*width + 100 ); |
| 634 | if( s.zLine==0 ) return; |
| 635 | s.width = width; |
| 636 | s.escHtml = escHtml; |
| 637 | s.iStart = -1; |
| 638 | s.iEnd = -1; |
| 639 | A = p->aFrom; |
| 640 | B = p->aTo; |
| 641 | R = p->aEdit; |
| 642 | mxr = p->nEdit; |
| 643 | while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } |
| @@ -599,10 +687,11 @@ | |
| 687 | b += skip; |
| 688 | m = R[r] - skip; |
| 689 | for(j=0; j<m; j++){ |
| 690 | s.n = 0; |
| 691 | sbsWriteLineno(&s, a+j); |
| 692 | s.iStart = s.iEnd = -1; |
| 693 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 694 | sbsWrite(&s, " ", 3); |
| 695 | sbsWriteLineno(&s, b+j); |
| 696 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 697 | blob_append(pOut, s.zLine, s.n); |
| @@ -619,34 +708,32 @@ | |
| 708 | match_dline(&A[a],&B[b]) < match_dline(&A[a],&B[b+1]) ) ){ |
| 709 | s.n = 0; |
| 710 | sbsWriteSpace(&s, width + 7); |
| 711 | sbsWrite(&s, " > ", 3); |
| 712 | sbsWriteLineno(&s, b); |
| 713 | s.iStart = 0; |
| 714 | s.zStart = "<span class=\"diffadd\">"; |
| 715 | s.iEnd = s.width; |
| 716 | sbsWriteText(&s, &B[b], SBS_NEWLINE); |
| 717 | blob_append(pOut, s.zLine, s.n); |
| 718 | mb--; |
| 719 | b++; |
| 720 | }else if( ma>mb && (mb==0 || |
| 721 | match_dline(&A[a],&B[b]) < match_dline(&A[a+1],&B[b])) ){ |
| 722 | s.n = 0; |
| 723 | sbsWriteLineno(&s, a); |
| 724 | s.iStart = 0; |
| 725 | s.zStart = "<span class=\"diffrm\">"; |
| 726 | s.iEnd = s.width; |
| 727 | sbsWriteText(&s, &A[a], SBS_PAD); |
| 728 | sbsWrite(&s, " <\n", 3); |
| 729 | blob_append(pOut, s.zLine, s.n); |
| 730 | ma--; |
| 731 | a++; |
| 732 | }else{ |
| 733 | s.n = 0; |
| 734 | sbsWriteLineChange(&s, &A[a], a, &B[b], b); |
| 735 | blob_append(pOut, s.zLine, s.n); |
| 736 | ma--; |
| 737 | mb--; |
| 738 | a++; |
| 739 | b++; |
| @@ -655,10 +742,11 @@ | |
| 742 | if( i<nr-1 ){ |
| 743 | m = R[r+i*3+3]; |
| 744 | for(j=0; j<m; j++){ |
| 745 | s.n = 0; |
| 746 | sbsWriteLineno(&s, a+j); |
| 747 | s.iStart = s.iEnd = -1; |
| 748 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 749 | sbsWrite(&s, " ", 3); |
| 750 | sbsWriteLineno(&s, b+j); |
| 751 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 752 | blob_append(pOut, s.zLine, s.n); |
| @@ -673,10 +761,11 @@ | |
| 761 | m = R[r+nr*3]; |
| 762 | if( m>nContext ) m = nContext; |
| 763 | for(j=0; j<m; j++){ |
| 764 | s.n = 0; |
| 765 | sbsWriteLineno(&s, a+j); |
| 766 | s.iStart = s.iEnd = -1; |
| 767 | sbsWriteText(&s, &A[a+j], SBS_PAD); |
| 768 | sbsWrite(&s, " ", 3); |
| 769 | sbsWriteLineno(&s, b+j); |
| 770 | sbsWriteText(&s, &B[b+j], SBS_NEWLINE); |
| 771 | blob_append(pOut, s.zLine, s.n); |
| 772 |
+1
-1
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -764,11 +764,11 @@ | ||
| 764 | 764 | @ font-family: monospace; |
| 765 | 765 | @ white-space: pre; |
| 766 | 766 | }, |
| 767 | 767 | { "span.diffchng", |
| 768 | 768 | "changes in a diff", |
| 769 | - @ background-color: #ffffc8; | |
| 769 | + @ background-color: #e0e0ff; | |
| 770 | 770 | }, |
| 771 | 771 | { "span.diffadd", |
| 772 | 772 | "added code in a diff", |
| 773 | 773 | @ background-color: #e0ffe0; |
| 774 | 774 | }, |
| 775 | 775 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -764,11 +764,11 @@ | |
| 764 | @ font-family: monospace; |
| 765 | @ white-space: pre; |
| 766 | }, |
| 767 | { "span.diffchng", |
| 768 | "changes in a diff", |
| 769 | @ background-color: #ffffc8; |
| 770 | }, |
| 771 | { "span.diffadd", |
| 772 | "added code in a diff", |
| 773 | @ background-color: #e0ffe0; |
| 774 | }, |
| 775 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -764,11 +764,11 @@ | |
| 764 | @ font-family: monospace; |
| 765 | @ white-space: pre; |
| 766 | }, |
| 767 | { "span.diffchng", |
| 768 | "changes in a diff", |
| 769 | @ background-color: #e0e0ff; |
| 770 | }, |
| 771 | { "span.diffadd", |
| 772 | "added code in a diff", |
| 773 | @ background-color: #e0ffe0; |
| 774 | }, |
| 775 |