Fossil SCM

Further diff enhancements: Allow up to two diff-marks per line on a side-by-side diff.

drh 2012-02-11 18:25 trunk
Commit 937514b96854b8ba378850ebab10cd893fed5d75
1 file changed +157 -11
+157 -11
--- src/diff.c
+++ src/diff.c
@@ -363,10 +363,13 @@
363363
int width; /* Maximum width of a column in the output */
364364
unsigned char escHtml; /* True to escape html characters */
365365
int iStart; /* Write zStart prior to character iStart */
366366
const char *zStart; /* A <span> tag */
367367
int iEnd; /* Write </span> prior to character iEnd */
368
+ int iStart2; /* Write zStart2 prior to character iStart2 */
369
+ const char *zStart2; /* A <span> tag */
370
+ int iEnd2; /* Write </span> prior to character iEnd2 */
368371
};
369372
370373
/*
371374
** Flags for sbsWriteText()
372375
*/
@@ -381,10 +384,11 @@
381384
static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
382385
int n = pLine->h & LENGTH_MASK;
383386
int i; /* Number of input characters consumed */
384387
int j; /* Number of output characters generated */
385388
int k; /* Cursor position */
389
+ int needEndSpan = 0;
386390
const char *zIn = pLine->z;
387391
char *z = &p->zLine[p->n];
388392
int w = p->width;
389393
for(i=j=k=0; k<w && i<n; i++, k++){
390394
char c = zIn[i];
@@ -391,13 +395,24 @@
391395
if( p->escHtml ){
392396
if( i==p->iStart ){
393397
int x = strlen(p->zStart);
394398
memcpy(z+j, p->zStart, x);
395399
j += x;
400
+ needEndSpan = 1;
401
+ if( p->iStart2 ){
402
+ p->iStart = p->iStart2;
403
+ p->zStart = p->zStart2;
404
+ p->iStart2 = 0;
405
+ }
396406
}else if( i==p->iEnd ){
397407
memcpy(z+j, "</span>", 7);
398408
j += 7;
409
+ needEndSpan = 0;
410
+ if( p->iEnd2 ){
411
+ p->iEnd = p->iEnd2;
412
+ p->iEnd2 = 0;
413
+ }
399414
}
400415
}
401416
if( c=='\t' ){
402417
z[j++] = ' ';
403418
while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
@@ -414,11 +429,11 @@
414429
j += 4;
415430
}else{
416431
z[j++] = c;
417432
}
418433
}
419
- if( p->escHtml && i<=p->iEnd ){
434
+ if( needEndSpan ){
420435
memcpy(&z[j], "</span>", 7);
421436
j += 7;
422437
}
423438
if( (flags & SBS_PAD)!=0 ){
424439
while( k<w ){ k++; z[j++] = ' '; }
@@ -459,10 +474,77 @@
459474
sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
460475
p->n += 6;
461476
sbsWriteHtml(p, "</span>");
462477
p->zLine[p->n++] = ' ';
463478
}
479
+
480
+/*
481
+** The two text segments zLeft and zRight are known to be different on
482
+** both ends, but they might have a common segment in the middle. If
483
+** they do not have a common segment, return 0. If they do have a large
484
+** common segment, return 1 and before doing so set:
485
+**
486
+** aLCS[0] = start of the common segment in zLeft
487
+** aLCS[1] = end of the common segment in zLeft
488
+** aLCS[2] = start of the common segment in zLeft
489
+** aLCS[3] = end of the common segment in zLeft
490
+**
491
+** This computation is for display purposes only and does not have to be
492
+** optimal or exact.
493
+*/
494
+static int textLCS(
495
+ const char *zLeft, int nA, /* String on the left */
496
+ const char *zRight, int nB, /* String on the right */
497
+ int *aLCS /* Identify bounds of LCS here */
498
+){
499
+ const unsigned char *zA = (const unsigned char*)zLeft; /* left string */
500
+ const unsigned char *zB = (const unsigned char*)zRight; /* right string */
501
+ int nt; /* Number of target points */
502
+ int ti[3]; /* Index for start of each 4-byte target */
503
+ unsigned int target[3]; /* 4-byte alignment targets */
504
+ unsigned int probe; /* probe to compare against target */
505
+ int iAS, iAE, iBS, iBE; /* Range of common segment */
506
+ int i, j; /* Loop counters */
507
+ int rc = 0; /* Result code. 1 for success */
508
+
509
+ if( nA<6 || nB<6 ) return 0;
510
+ memset(aLCS, 0, sizeof(int)*4);
511
+ ti[0] = i = nB/2-2;
512
+ target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
513
+ probe = 0;
514
+ if( nB<16 ){
515
+ nt = 1;
516
+ }else{
517
+ ti[1] = i = nB/4-2;
518
+ target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
519
+ ti[2] = i = (nB*3)/4-2;
520
+ target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
521
+ nt = 3;
522
+ }
523
+ probe = (zA[0]<<16) | (zA[1]<<8) | zA[2];
524
+ for(i=3; i<nA; i++){
525
+ probe = (probe<<8) | zA[i];
526
+ for(j=0; j<nt; j++){
527
+ if( probe==target[j] ){
528
+ iAS = i-3;
529
+ iAE = i+1;
530
+ iBS = ti[j];
531
+ iBE = ti[j]+4;
532
+ while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; }
533
+ while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; }
534
+ if( iAE-iAS > aLCS[1] - aLCS[0] ){
535
+ aLCS[0] = iAS;
536
+ aLCS[1] = iAE;
537
+ aLCS[2] = iBS;
538
+ aLCS[3] = iBE;
539
+ rc = 1;
540
+ }
541
+ }
542
+ }
543
+ }
544
+ return rc;
545
+}
464546
465547
/*
466548
** Write out lines that have been edited. Adjust the highlight to cover
467549
** only those parts of the line that actually changed.
468550
*/
@@ -477,10 +559,16 @@
477559
int nRight; /* Length of right line in bytes */
478560
int nPrefix; /* Length of common prefix */
479561
int nSuffix; /* Length of common suffix */
480562
const char *zLeft; /* Text of the left line */
481563
const char *zRight; /* Text of the right line */
564
+ int nLeftDiff; /* nLeft - nPrefix - nSuffix */
565
+ int nRightDiff; /* nRight - nPrefix - nSuffix */
566
+ int aLCS[4]; /* Bounds of common middle segment */
567
+ static const char zClassRm[] = "<span class=\"diffrm\">";
568
+ static const char zClassAdd[] = "<span class=\"diffadd\">";
569
+ static const char zClassChng[] = "<span class=\"diffchng\">";
482570
483571
nLeft = pLeft->h & LENGTH_MASK;
484572
zLeft = pLeft->z;
485573
nRight = pRight->h & LENGTH_MASK;
486574
zRight = pRight->z;
@@ -497,44 +585,102 @@
497585
}
498586
if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
499587
}
500588
if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
501589
if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
590
+
591
+ /* A single chunk of text inserted on the right */
502592
if( nPrefix+nSuffix==nLeft ){
503
- /* Text inserted on the right */
504593
sbsWriteLineno(p, lnLeft);
594
+ p->iStart2 = p->iEnd2 = 0;
505595
p->iStart = p->iEnd = -1;
506596
sbsWriteText(p, pLeft, SBS_PAD);
507597
sbsWrite(p, " | ", 3);
508598
sbsWriteLineno(p, lnRight);
509599
p->iStart = nPrefix;
510600
p->iEnd = nRight - nSuffix;
511
- p->zStart = "<span class=\"diffadd\">";
601
+ p->zStart = zClassAdd;
512602
sbsWriteText(p, pRight, SBS_NEWLINE);
513
- }else if( nPrefix+nSuffix==nRight ){
603
+ return;
604
+ }
605
+
606
+ /* A single chunk of text deleted from the left */
607
+ if( nPrefix+nSuffix==nRight ){
514608
/* Text deleted from the left */
515609
sbsWriteLineno(p, lnLeft);
610
+ p->iStart2 = p->iEnd2 = 0;
516611
p->iStart = nPrefix;
517612
p->iEnd = nLeft - nSuffix;
518
- p->zStart = "<span class=\"diffrm\">";
613
+ p->zStart = zClassRm;
519614
sbsWriteText(p, pLeft, SBS_PAD);
520615
sbsWrite(p, " | ", 3);
521616
sbsWriteLineno(p, lnRight);
522617
p->iStart = p->iEnd = -1;
523618
sbsWriteText(p, pRight, SBS_NEWLINE);
524
- }else{
525
- /* Text modified between left and right */
619
+ return;
620
+ }
621
+
622
+ /* At this point we know that there is a chunk of text that has
623
+ ** changed between the left and the right. Check to see if there
624
+ ** is a large unchanged section in the middle of that changed block.
625
+ */
626
+ nLeftDiff = nLeft - nSuffix - nPrefix;
627
+ nRightDiff = nRight - nSuffix - nPrefix;
628
+ if( p->escHtml
629
+ && nLeftDiff >= 6
630
+ && nRightDiff >= 6
631
+ && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
632
+ ){
526633
sbsWriteLineno(p, lnLeft);
527634
p->iStart = nPrefix;
528
- p->iEnd = nLeft - nSuffix;
529
- p->zStart = "<span class=\"diffchng\">";
635
+ p->iEnd = nPrefix + aLCS[0];
636
+ p->zStart = aLCS[2]==0 ? zClassRm : zClassChng;
637
+ p->iStart2 = nPrefix + aLCS[1];
638
+ p->iEnd2 = nLeft - nSuffix;
639
+ p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
640
+ if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
641
+ if( p->iStart==p->iEnd ){
642
+ p->iStart = p->iStart2;
643
+ p->iEnd = p->iEnd2;
644
+ p->zStart = p->zStart2;
645
+ p->iStart2 = 0;
646
+ p->iEnd2 = 0;
647
+ }
648
+ if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
530649
sbsWriteText(p, pLeft, SBS_PAD);
531650
sbsWrite(p, " | ", 3);
532651
sbsWriteLineno(p, lnRight);
533
- p->iEnd = nRight - nSuffix;
652
+ p->iStart = nPrefix;
653
+ p->iEnd = nPrefix + aLCS[2];
654
+ p->zStart = aLCS[0]==0 ? zClassAdd : zClassChng;
655
+ p->iStart2 = nPrefix + aLCS[3];
656
+ p->iEnd2 = nRight - nSuffix;
657
+ p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
658
+ if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
659
+ if( p->iStart==p->iEnd ){
660
+ p->iStart = p->iStart2;
661
+ p->iEnd = p->iEnd2;
662
+ p->zStart = p->zStart2;
663
+ p->iStart2 = 0;
664
+ p->iEnd2 = 0;
665
+ }
666
+ if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
534667
sbsWriteText(p, pRight, SBS_NEWLINE);
668
+ return;
535669
}
670
+
671
+ /* If all else fails, show a single big change between left and right */
672
+ sbsWriteLineno(p, lnLeft);
673
+ p->iStart2 = p->iEnd2 = 0;
674
+ p->iStart = nPrefix;
675
+ p->iEnd = nLeft - nSuffix;
676
+ p->zStart = zClassChng;
677
+ sbsWriteText(p, pLeft, SBS_PAD);
678
+ sbsWrite(p, " | ", 3);
679
+ sbsWriteLineno(p, lnRight);
680
+ p->iEnd = nRight - nSuffix;
681
+ sbsWriteText(p, pRight, SBS_NEWLINE);
536682
}
537683
538684
/*
539685
** Minimum of two values
540686
*/
@@ -734,11 +880,11 @@
734880
int m, ma, mb;/* Number of lines to output */
735881
int skip; /* Number of lines to skip */
736882
int nChunk = 0; /* Number of chunks of diff output seen so far */
737883
SbsLine s; /* Output line buffer */
738884
739
- s.zLine = fossil_malloc( 10*width + 100 );
885
+ s.zLine = fossil_malloc( 10*width + 200 );
740886
if( s.zLine==0 ) return;
741887
s.width = width;
742888
s.escHtml = escHtml;
743889
s.iStart = -1;
744890
s.iEnd = -1;
745891
--- src/diff.c
+++ src/diff.c
@@ -363,10 +363,13 @@
363 int width; /* Maximum width of a column in the output */
364 unsigned char escHtml; /* True to escape html characters */
365 int iStart; /* Write zStart prior to character iStart */
366 const char *zStart; /* A <span> tag */
367 int iEnd; /* Write </span> prior to character iEnd */
 
 
 
368 };
369
370 /*
371 ** Flags for sbsWriteText()
372 */
@@ -381,10 +384,11 @@
381 static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
382 int n = pLine->h & LENGTH_MASK;
383 int i; /* Number of input characters consumed */
384 int j; /* Number of output characters generated */
385 int k; /* Cursor position */
 
386 const char *zIn = pLine->z;
387 char *z = &p->zLine[p->n];
388 int w = p->width;
389 for(i=j=k=0; k<w && i<n; i++, k++){
390 char c = zIn[i];
@@ -391,13 +395,24 @@
391 if( p->escHtml ){
392 if( i==p->iStart ){
393 int x = strlen(p->zStart);
394 memcpy(z+j, p->zStart, x);
395 j += x;
 
 
 
 
 
 
396 }else if( i==p->iEnd ){
397 memcpy(z+j, "</span>", 7);
398 j += 7;
 
 
 
 
 
399 }
400 }
401 if( c=='\t' ){
402 z[j++] = ' ';
403 while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
@@ -414,11 +429,11 @@
414 j += 4;
415 }else{
416 z[j++] = c;
417 }
418 }
419 if( p->escHtml && i<=p->iEnd ){
420 memcpy(&z[j], "</span>", 7);
421 j += 7;
422 }
423 if( (flags & SBS_PAD)!=0 ){
424 while( k<w ){ k++; z[j++] = ' '; }
@@ -459,10 +474,77 @@
459 sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
460 p->n += 6;
461 sbsWriteHtml(p, "</span>");
462 p->zLine[p->n++] = ' ';
463 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
464
465 /*
466 ** Write out lines that have been edited. Adjust the highlight to cover
467 ** only those parts of the line that actually changed.
468 */
@@ -477,10 +559,16 @@
477 int nRight; /* Length of right line in bytes */
478 int nPrefix; /* Length of common prefix */
479 int nSuffix; /* Length of common suffix */
480 const char *zLeft; /* Text of the left line */
481 const char *zRight; /* Text of the right line */
 
 
 
 
 
 
482
483 nLeft = pLeft->h & LENGTH_MASK;
484 zLeft = pLeft->z;
485 nRight = pRight->h & LENGTH_MASK;
486 zRight = pRight->z;
@@ -497,44 +585,102 @@
497 }
498 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
499 }
500 if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
501 if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
 
 
502 if( nPrefix+nSuffix==nLeft ){
503 /* Text inserted on the right */
504 sbsWriteLineno(p, lnLeft);
 
505 p->iStart = p->iEnd = -1;
506 sbsWriteText(p, pLeft, SBS_PAD);
507 sbsWrite(p, " | ", 3);
508 sbsWriteLineno(p, lnRight);
509 p->iStart = nPrefix;
510 p->iEnd = nRight - nSuffix;
511 p->zStart = "<span class=\"diffadd\">";
512 sbsWriteText(p, pRight, SBS_NEWLINE);
513 }else if( nPrefix+nSuffix==nRight ){
 
 
 
 
514 /* Text deleted from the left */
515 sbsWriteLineno(p, lnLeft);
 
516 p->iStart = nPrefix;
517 p->iEnd = nLeft - nSuffix;
518 p->zStart = "<span class=\"diffrm\">";
519 sbsWriteText(p, pLeft, SBS_PAD);
520 sbsWrite(p, " | ", 3);
521 sbsWriteLineno(p, lnRight);
522 p->iStart = p->iEnd = -1;
523 sbsWriteText(p, pRight, SBS_NEWLINE);
524 }else{
525 /* Text modified between left and right */
 
 
 
 
 
 
 
 
 
 
 
 
526 sbsWriteLineno(p, lnLeft);
527 p->iStart = nPrefix;
528 p->iEnd = nLeft - nSuffix;
529 p->zStart = "<span class=\"diffchng\">";
 
 
 
 
 
 
 
 
 
 
 
 
530 sbsWriteText(p, pLeft, SBS_PAD);
531 sbsWrite(p, " | ", 3);
532 sbsWriteLineno(p, lnRight);
533 p->iEnd = nRight - nSuffix;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534 sbsWriteText(p, pRight, SBS_NEWLINE);
 
535 }
 
 
 
 
 
 
 
 
 
 
 
 
536 }
537
538 /*
539 ** Minimum of two values
540 */
@@ -734,11 +880,11 @@
734 int m, ma, mb;/* Number of lines to output */
735 int skip; /* Number of lines to skip */
736 int nChunk = 0; /* Number of chunks of diff output seen so far */
737 SbsLine s; /* Output line buffer */
738
739 s.zLine = fossil_malloc( 10*width + 100 );
740 if( s.zLine==0 ) return;
741 s.width = width;
742 s.escHtml = escHtml;
743 s.iStart = -1;
744 s.iEnd = -1;
745
--- src/diff.c
+++ src/diff.c
@@ -363,10 +363,13 @@
363 int width; /* Maximum width of a column in the output */
364 unsigned char escHtml; /* True to escape html characters */
365 int iStart; /* Write zStart prior to character iStart */
366 const char *zStart; /* A <span> tag */
367 int iEnd; /* Write </span> prior to character iEnd */
368 int iStart2; /* Write zStart2 prior to character iStart2 */
369 const char *zStart2; /* A <span> tag */
370 int iEnd2; /* Write </span> prior to character iEnd2 */
371 };
372
373 /*
374 ** Flags for sbsWriteText()
375 */
@@ -381,10 +384,11 @@
384 static void sbsWriteText(SbsLine *p, DLine *pLine, unsigned flags){
385 int n = pLine->h & LENGTH_MASK;
386 int i; /* Number of input characters consumed */
387 int j; /* Number of output characters generated */
388 int k; /* Cursor position */
389 int needEndSpan = 0;
390 const char *zIn = pLine->z;
391 char *z = &p->zLine[p->n];
392 int w = p->width;
393 for(i=j=k=0; k<w && i<n; i++, k++){
394 char c = zIn[i];
@@ -391,13 +395,24 @@
395 if( p->escHtml ){
396 if( i==p->iStart ){
397 int x = strlen(p->zStart);
398 memcpy(z+j, p->zStart, x);
399 j += x;
400 needEndSpan = 1;
401 if( p->iStart2 ){
402 p->iStart = p->iStart2;
403 p->zStart = p->zStart2;
404 p->iStart2 = 0;
405 }
406 }else if( i==p->iEnd ){
407 memcpy(z+j, "</span>", 7);
408 j += 7;
409 needEndSpan = 0;
410 if( p->iEnd2 ){
411 p->iEnd = p->iEnd2;
412 p->iEnd2 = 0;
413 }
414 }
415 }
416 if( c=='\t' ){
417 z[j++] = ' ';
418 while( (k&7)!=7 && k<w ){ z[j++] = ' '; k++; }
@@ -414,11 +429,11 @@
429 j += 4;
430 }else{
431 z[j++] = c;
432 }
433 }
434 if( needEndSpan ){
435 memcpy(&z[j], "</span>", 7);
436 j += 7;
437 }
438 if( (flags & SBS_PAD)!=0 ){
439 while( k<w ){ k++; z[j++] = ' '; }
@@ -459,10 +474,77 @@
474 sqlite3_snprintf(7, &p->zLine[p->n], "%5d ", ln+1);
475 p->n += 6;
476 sbsWriteHtml(p, "</span>");
477 p->zLine[p->n++] = ' ';
478 }
479
480 /*
481 ** The two text segments zLeft and zRight are known to be different on
482 ** both ends, but they might have a common segment in the middle. If
483 ** they do not have a common segment, return 0. If they do have a large
484 ** common segment, return 1 and before doing so set:
485 **
486 ** aLCS[0] = start of the common segment in zLeft
487 ** aLCS[1] = end of the common segment in zLeft
488 ** aLCS[2] = start of the common segment in zLeft
489 ** aLCS[3] = end of the common segment in zLeft
490 **
491 ** This computation is for display purposes only and does not have to be
492 ** optimal or exact.
493 */
494 static int textLCS(
495 const char *zLeft, int nA, /* String on the left */
496 const char *zRight, int nB, /* String on the right */
497 int *aLCS /* Identify bounds of LCS here */
498 ){
499 const unsigned char *zA = (const unsigned char*)zLeft; /* left string */
500 const unsigned char *zB = (const unsigned char*)zRight; /* right string */
501 int nt; /* Number of target points */
502 int ti[3]; /* Index for start of each 4-byte target */
503 unsigned int target[3]; /* 4-byte alignment targets */
504 unsigned int probe; /* probe to compare against target */
505 int iAS, iAE, iBS, iBE; /* Range of common segment */
506 int i, j; /* Loop counters */
507 int rc = 0; /* Result code. 1 for success */
508
509 if( nA<6 || nB<6 ) return 0;
510 memset(aLCS, 0, sizeof(int)*4);
511 ti[0] = i = nB/2-2;
512 target[0] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
513 probe = 0;
514 if( nB<16 ){
515 nt = 1;
516 }else{
517 ti[1] = i = nB/4-2;
518 target[1] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
519 ti[2] = i = (nB*3)/4-2;
520 target[2] = (zB[i]<<24) | (zB[i+1]<<16) | (zB[i+2]<<8) | zB[i+3];
521 nt = 3;
522 }
523 probe = (zA[0]<<16) | (zA[1]<<8) | zA[2];
524 for(i=3; i<nA; i++){
525 probe = (probe<<8) | zA[i];
526 for(j=0; j<nt; j++){
527 if( probe==target[j] ){
528 iAS = i-3;
529 iAE = i+1;
530 iBS = ti[j];
531 iBE = ti[j]+4;
532 while( iAE<nA && iBE<nB && zA[iAE]==zB[iBE] ){ iAE++; iBE++; }
533 while( iAS>0 && iBS>0 && zA[iAS-1]==zB[iBS-1] ){ iAS--; iBS--; }
534 if( iAE-iAS > aLCS[1] - aLCS[0] ){
535 aLCS[0] = iAS;
536 aLCS[1] = iAE;
537 aLCS[2] = iBS;
538 aLCS[3] = iBE;
539 rc = 1;
540 }
541 }
542 }
543 }
544 return rc;
545 }
546
547 /*
548 ** Write out lines that have been edited. Adjust the highlight to cover
549 ** only those parts of the line that actually changed.
550 */
@@ -477,10 +559,16 @@
559 int nRight; /* Length of right line in bytes */
560 int nPrefix; /* Length of common prefix */
561 int nSuffix; /* Length of common suffix */
562 const char *zLeft; /* Text of the left line */
563 const char *zRight; /* Text of the right line */
564 int nLeftDiff; /* nLeft - nPrefix - nSuffix */
565 int nRightDiff; /* nRight - nPrefix - nSuffix */
566 int aLCS[4]; /* Bounds of common middle segment */
567 static const char zClassRm[] = "<span class=\"diffrm\">";
568 static const char zClassAdd[] = "<span class=\"diffadd\">";
569 static const char zClassChng[] = "<span class=\"diffchng\">";
570
571 nLeft = pLeft->h & LENGTH_MASK;
572 zLeft = pLeft->z;
573 nRight = pRight->h & LENGTH_MASK;
574 zRight = pRight->z;
@@ -497,44 +585,102 @@
585 }
586 if( nSuffix==nLeft || nSuffix==nRight ) nPrefix = 0;
587 }
588 if( nPrefix+nSuffix > nLeft ) nSuffix = nLeft - nPrefix;
589 if( nPrefix+nSuffix > nRight ) nSuffix = nRight - nPrefix;
590
591 /* A single chunk of text inserted on the right */
592 if( nPrefix+nSuffix==nLeft ){
 
593 sbsWriteLineno(p, lnLeft);
594 p->iStart2 = p->iEnd2 = 0;
595 p->iStart = p->iEnd = -1;
596 sbsWriteText(p, pLeft, SBS_PAD);
597 sbsWrite(p, " | ", 3);
598 sbsWriteLineno(p, lnRight);
599 p->iStart = nPrefix;
600 p->iEnd = nRight - nSuffix;
601 p->zStart = zClassAdd;
602 sbsWriteText(p, pRight, SBS_NEWLINE);
603 return;
604 }
605
606 /* A single chunk of text deleted from the left */
607 if( nPrefix+nSuffix==nRight ){
608 /* Text deleted from the left */
609 sbsWriteLineno(p, lnLeft);
610 p->iStart2 = p->iEnd2 = 0;
611 p->iStart = nPrefix;
612 p->iEnd = nLeft - nSuffix;
613 p->zStart = zClassRm;
614 sbsWriteText(p, pLeft, SBS_PAD);
615 sbsWrite(p, " | ", 3);
616 sbsWriteLineno(p, lnRight);
617 p->iStart = p->iEnd = -1;
618 sbsWriteText(p, pRight, SBS_NEWLINE);
619 return;
620 }
621
622 /* At this point we know that there is a chunk of text that has
623 ** changed between the left and the right. Check to see if there
624 ** is a large unchanged section in the middle of that changed block.
625 */
626 nLeftDiff = nLeft - nSuffix - nPrefix;
627 nRightDiff = nRight - nSuffix - nPrefix;
628 if( p->escHtml
629 && nLeftDiff >= 6
630 && nRightDiff >= 6
631 && textLCS(&zLeft[nPrefix], nLeftDiff, &zRight[nPrefix], nRightDiff, aLCS)
632 ){
633 sbsWriteLineno(p, lnLeft);
634 p->iStart = nPrefix;
635 p->iEnd = nPrefix + aLCS[0];
636 p->zStart = aLCS[2]==0 ? zClassRm : zClassChng;
637 p->iStart2 = nPrefix + aLCS[1];
638 p->iEnd2 = nLeft - nSuffix;
639 p->zStart2 = aLCS[3]==nRightDiff ? zClassRm : zClassChng;
640 if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
641 if( p->iStart==p->iEnd ){
642 p->iStart = p->iStart2;
643 p->iEnd = p->iEnd2;
644 p->zStart = p->zStart2;
645 p->iStart2 = 0;
646 p->iEnd2 = 0;
647 }
648 if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
649 sbsWriteText(p, pLeft, SBS_PAD);
650 sbsWrite(p, " | ", 3);
651 sbsWriteLineno(p, lnRight);
652 p->iStart = nPrefix;
653 p->iEnd = nPrefix + aLCS[2];
654 p->zStart = aLCS[0]==0 ? zClassAdd : zClassChng;
655 p->iStart2 = nPrefix + aLCS[3];
656 p->iEnd2 = nRight - nSuffix;
657 p->zStart2 = aLCS[1]==nLeftDiff ? zClassAdd : zClassChng;
658 if( p->iStart2==p->iEnd2 ) p->iStart2 = p->iEnd2 = 0;
659 if( p->iStart==p->iEnd ){
660 p->iStart = p->iStart2;
661 p->iEnd = p->iEnd2;
662 p->zStart = p->zStart2;
663 p->iStart2 = 0;
664 p->iEnd2 = 0;
665 }
666 if( p->iStart==p->iEnd ) p->iStart = p->iEnd = -1;
667 sbsWriteText(p, pRight, SBS_NEWLINE);
668 return;
669 }
670
671 /* If all else fails, show a single big change between left and right */
672 sbsWriteLineno(p, lnLeft);
673 p->iStart2 = p->iEnd2 = 0;
674 p->iStart = nPrefix;
675 p->iEnd = nLeft - nSuffix;
676 p->zStart = zClassChng;
677 sbsWriteText(p, pLeft, SBS_PAD);
678 sbsWrite(p, " | ", 3);
679 sbsWriteLineno(p, lnRight);
680 p->iEnd = nRight - nSuffix;
681 sbsWriteText(p, pRight, SBS_NEWLINE);
682 }
683
684 /*
685 ** Minimum of two values
686 */
@@ -734,11 +880,11 @@
880 int m, ma, mb;/* Number of lines to output */
881 int skip; /* Number of lines to skip */
882 int nChunk = 0; /* Number of chunks of diff output seen so far */
883 SbsLine s; /* Output line buffer */
884
885 s.zLine = fossil_malloc( 10*width + 200 );
886 if( s.zLine==0 ) return;
887 s.width = width;
888 s.escHtml = escHtml;
889 s.iStart = -1;
890 s.iEnd = -1;
891

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button