Fossil SCM

Started adding support for showing side-by-side diffs in the web ui.

jan 2011-10-13 23:48 trunk
Commit a6a8e8941356779fd5f85492a8e14e6fdb66066f
3 files changed +168 +47 -8 +43
+168
--- src/diff.c
+++ src/diff.c
@@ -578,10 +578,178 @@
578578
free(c.aFrom);
579579
free(c.aTo);
580580
return c.aEdit;
581581
}
582582
}
583
+
584
+
585
+/*
586
+ * References in the fossil repository:
587
+ * /vdiff?from=080d27a&to=4b0f813&detail=1
588
+ * /vdiff?from=636804745b&to=c1d78e0556&detail=1
589
+ * /vdiff?from=c0b6c28d29&to=25169506b7&detail=1
590
+ * /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1
591
+ */
592
+int *html_sbsdiff(
593
+ Blob *pA_Blob, /* FROM file */
594
+ Blob *pB_Blob, /* TO file */
595
+ int nContext, /* Amount of context to unified diff */
596
+ int ignoreEolWs /* Ignore whitespace at the end of lines */
597
+){
598
+ DContext c;
599
+ int i;
600
+ int iFrom, iTo;
601
+ char *linebuf;
602
+
603
+ /* Prepare the input files */
604
+ memset(&c, 0, sizeof(c));
605
+ c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
606
+ &c.nFrom, ignoreEolWs);
607
+ c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
608
+ &c.nTo, ignoreEolWs);
609
+ if( c.aFrom==0 || c.aTo==0 ){
610
+ free(c.aFrom);
611
+ free(c.aTo);
612
+ /* TODO Error handling */
613
+ return 0;
614
+ }
615
+
616
+ /* Compute the difference */
617
+ diff_all(&c);
618
+
619
+ linebuf = fossil_malloc(LENGTH_MASK+1);
620
+ if( !linebuf ){
621
+ /* TODO Handle error */
622
+ }
623
+
624
+ iFrom=iTo=0;
625
+ i=0;
626
+ while( i<c.nEdit ){
627
+ int j;
628
+ /* Copied lines */
629
+ for( j=0; j<c.aEdit[i]; j++){
630
+ int len;
631
+ int dist;
632
+
633
+ /* Hide lines which are copied and are further away from block boundaries
634
+ ** then nConext lines. For each block with hidden lines, show a row
635
+ ** notifying the user about the hidden rows.
636
+ */
637
+ if( j<nContext || j>c.aEdit[i]-nContext-1 ){
638
+ @ <tr>
639
+ }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
640
+ @ <tr>
641
+ @ <td class="meta" colspan="5" style="white-space: nowrap;">
642
+ @ %d(c.aEdit[i]-2*nContext) hidden line(s).</td>
643
+ @ </tr>
644
+ continue;
645
+ }else{
646
+ @ <tr style="display:none;">
647
+ }
648
+
649
+ len = c.aFrom[iFrom+j].h & LENGTH_MASK;
650
+ memcpy(linebuf, c.aFrom[iFrom+j].z, len);
651
+ linebuf[len] = '\0';
652
+ @ <td class="lineno">%d(iFrom+j+1)</td><td>%s(linebuf)</td>
653
+
654
+ @ <td> </td>
655
+
656
+ len = c.aTo[iTo+j].h & LENGTH_MASK;
657
+ memcpy(linebuf, c.aTo[iTo+j].z, len);
658
+ linebuf[len] = '\0';
659
+ @ <td class="lineno">%d(iTo+j+1)</td><td>%s(linebuf)</td>
660
+
661
+ @ </tr>
662
+ }
663
+ iFrom+=c.aEdit[i];
664
+ iTo+=c.aEdit[i];
665
+
666
+ if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){
667
+ int lim;
668
+ lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2];
669
+
670
+ /* Assume changed lines */
671
+ for( j=0; j<lim; j++ ){
672
+ int len;
673
+ @ <tr>
674
+
675
+ if( j<c.aEdit[i+1] ){
676
+ len = c.aFrom[iFrom+j].h & LENGTH_MASK;
677
+ memcpy(linebuf, c.aFrom[iFrom+j].z, len);
678
+ linebuf[len] = '\0';
679
+ @ <td class="changed lineno">%d(iFrom+j+1)</td>
680
+ @ <td class="changed">%s(linebuf)</td>
681
+ }else{
682
+ @ <td colspan="2"/>
683
+ }
684
+
685
+ @ <td class="changed">|</td>
686
+
687
+ if( j<c.aEdit[i+2] ){
688
+ len = c.aTo[iTo+j].h & LENGTH_MASK;
689
+ memcpy(linebuf, c.aTo[iTo+j].z, len);
690
+ linebuf[len] = '\0';
691
+ @ <td class="changed lineno">%d(iTo+j+1)</td>
692
+ @ <td class="changed">%s(linebuf)</td>
693
+ }else{
694
+ @ <td colspan="2"/>
695
+ }
696
+
697
+ @ </tr>
698
+ }
699
+ iFrom+=c.aEdit[i+1];
700
+ iTo+=c.aEdit[i+2];
701
+ }else{
702
+
703
+ /* Process deleted lines */
704
+ for( j=0; j<c.aEdit[i+1]; j++ ){
705
+ int len;
706
+ @ <tr>
707
+
708
+ len = c.aFrom[iFrom+j].h & LENGTH_MASK;
709
+ memcpy(linebuf, c.aFrom[iFrom+j].z, len);
710
+ linebuf[len] = '\0';
711
+ @ <td class="removed lineno">%d(iFrom+j+1)</td>
712
+ @ <td class="removed">%s(linebuf)</td>
713
+
714
+ @ <td>&lt;</td>
715
+
716
+ @ <td colspan="2"/>
717
+
718
+ @ </tr>
719
+ }
720
+ iFrom+=c.aEdit[i+1];
721
+
722
+ /* Process inserted lines */
723
+ for( j=0; j<c.aEdit[i+2]; j++ ){
724
+ int len;
725
+ @ <tr>
726
+ @ <td colspan="2"/>
727
+
728
+ @ <td>&gt;</td>
729
+
730
+ len = c.aTo[iTo+j].h & LENGTH_MASK;
731
+ memcpy(linebuf, c.aTo[iTo+j].z, len);
732
+ linebuf[len] = '\0';
733
+ @ <td class="added lineno">%d(iTo+j+1)</td>
734
+ @ <td class="added">%s(linebuf)</td>
735
+
736
+ @ </tr>
737
+ }
738
+ iTo+=c.aEdit[i+2];
739
+ }
740
+
741
+ i+=3;
742
+ }
743
+
744
+ free(linebuf);
745
+ free(c.aFrom);
746
+ free(c.aTo);
747
+ free(c.aEdit);
748
+ return 0;
749
+}
750
+
583751
584752
/*
585753
** COMMAND: test-rawdiff
586754
*/
587755
void test_rawdiff_cmd(void){
588756
--- src/diff.c
+++ src/diff.c
@@ -578,10 +578,178 @@
578 free(c.aFrom);
579 free(c.aTo);
580 return c.aEdit;
581 }
582 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
583
584 /*
585 ** COMMAND: test-rawdiff
586 */
587 void test_rawdiff_cmd(void){
588
--- src/diff.c
+++ src/diff.c
@@ -578,10 +578,178 @@
578 free(c.aFrom);
579 free(c.aTo);
580 return c.aEdit;
581 }
582 }
583
584
585 /*
586 * References in the fossil repository:
587 * /vdiff?from=080d27a&to=4b0f813&detail=1
588 * /vdiff?from=636804745b&to=c1d78e0556&detail=1
589 * /vdiff?from=c0b6c28d29&to=25169506b7&detail=1
590 * /vdiff?from=e3d022dffa&to=48bcfbd47b&detail=1
591 */
592 int *html_sbsdiff(
593 Blob *pA_Blob, /* FROM file */
594 Blob *pB_Blob, /* TO file */
595 int nContext, /* Amount of context to unified diff */
596 int ignoreEolWs /* Ignore whitespace at the end of lines */
597 ){
598 DContext c;
599 int i;
600 int iFrom, iTo;
601 char *linebuf;
602
603 /* Prepare the input files */
604 memset(&c, 0, sizeof(c));
605 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob),
606 &c.nFrom, ignoreEolWs);
607 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob),
608 &c.nTo, ignoreEolWs);
609 if( c.aFrom==0 || c.aTo==0 ){
610 free(c.aFrom);
611 free(c.aTo);
612 /* TODO Error handling */
613 return 0;
614 }
615
616 /* Compute the difference */
617 diff_all(&c);
618
619 linebuf = fossil_malloc(LENGTH_MASK+1);
620 if( !linebuf ){
621 /* TODO Handle error */
622 }
623
624 iFrom=iTo=0;
625 i=0;
626 while( i<c.nEdit ){
627 int j;
628 /* Copied lines */
629 for( j=0; j<c.aEdit[i]; j++){
630 int len;
631 int dist;
632
633 /* Hide lines which are copied and are further away from block boundaries
634 ** then nConext lines. For each block with hidden lines, show a row
635 ** notifying the user about the hidden rows.
636 */
637 if( j<nContext || j>c.aEdit[i]-nContext-1 ){
638 @ <tr>
639 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){
640 @ <tr>
641 @ <td class="meta" colspan="5" style="white-space: nowrap;">
642 @ %d(c.aEdit[i]-2*nContext) hidden line(s).</td>
643 @ </tr>
644 continue;
645 }else{
646 @ <tr style="display:none;">
647 }
648
649 len = c.aFrom[iFrom+j].h & LENGTH_MASK;
650 memcpy(linebuf, c.aFrom[iFrom+j].z, len);
651 linebuf[len] = '\0';
652 @ <td class="lineno">%d(iFrom+j+1)</td><td>%s(linebuf)</td>
653
654 @ <td> </td>
655
656 len = c.aTo[iTo+j].h & LENGTH_MASK;
657 memcpy(linebuf, c.aTo[iTo+j].z, len);
658 linebuf[len] = '\0';
659 @ <td class="lineno">%d(iTo+j+1)</td><td>%s(linebuf)</td>
660
661 @ </tr>
662 }
663 iFrom+=c.aEdit[i];
664 iTo+=c.aEdit[i];
665
666 if( c.aEdit[i+1]!=0 && c.aEdit[i+2]!=0 ){
667 int lim;
668 lim = c.aEdit[i+1] > c.aEdit[i+2] ? c.aEdit[i+1] : c.aEdit[i+2];
669
670 /* Assume changed lines */
671 for( j=0; j<lim; j++ ){
672 int len;
673 @ <tr>
674
675 if( j<c.aEdit[i+1] ){
676 len = c.aFrom[iFrom+j].h & LENGTH_MASK;
677 memcpy(linebuf, c.aFrom[iFrom+j].z, len);
678 linebuf[len] = '\0';
679 @ <td class="changed lineno">%d(iFrom+j+1)</td>
680 @ <td class="changed">%s(linebuf)</td>
681 }else{
682 @ <td colspan="2"/>
683 }
684
685 @ <td class="changed">|</td>
686
687 if( j<c.aEdit[i+2] ){
688 len = c.aTo[iTo+j].h & LENGTH_MASK;
689 memcpy(linebuf, c.aTo[iTo+j].z, len);
690 linebuf[len] = '\0';
691 @ <td class="changed lineno">%d(iTo+j+1)</td>
692 @ <td class="changed">%s(linebuf)</td>
693 }else{
694 @ <td colspan="2"/>
695 }
696
697 @ </tr>
698 }
699 iFrom+=c.aEdit[i+1];
700 iTo+=c.aEdit[i+2];
701 }else{
702
703 /* Process deleted lines */
704 for( j=0; j<c.aEdit[i+1]; j++ ){
705 int len;
706 @ <tr>
707
708 len = c.aFrom[iFrom+j].h & LENGTH_MASK;
709 memcpy(linebuf, c.aFrom[iFrom+j].z, len);
710 linebuf[len] = '\0';
711 @ <td class="removed lineno">%d(iFrom+j+1)</td>
712 @ <td class="removed">%s(linebuf)</td>
713
714 @ <td>&lt;</td>
715
716 @ <td colspan="2"/>
717
718 @ </tr>
719 }
720 iFrom+=c.aEdit[i+1];
721
722 /* Process inserted lines */
723 for( j=0; j<c.aEdit[i+2]; j++ ){
724 int len;
725 @ <tr>
726 @ <td colspan="2"/>
727
728 @ <td>&gt;</td>
729
730 len = c.aTo[iTo+j].h & LENGTH_MASK;
731 memcpy(linebuf, c.aTo[iTo+j].z, len);
732 linebuf[len] = '\0';
733 @ <td class="added lineno">%d(iTo+j+1)</td>
734 @ <td class="added">%s(linebuf)</td>
735
736 @ </tr>
737 }
738 iTo+=c.aEdit[i+2];
739 }
740
741 i+=3;
742 }
743
744 free(linebuf);
745 free(c.aFrom);
746 free(c.aTo);
747 free(c.aEdit);
748 return 0;
749 }
750
751
752 /*
753 ** COMMAND: test-rawdiff
754 */
755 void test_rawdiff_cmd(void){
756
+47 -8
--- src/info.c
+++ src/info.c
@@ -276,10 +276,36 @@
276276
@ %h(blob_str(&out))
277277
blob_reset(&from);
278278
blob_reset(&to);
279279
blob_reset(&out);
280280
}
281
+
282
+
283
+/*
284
+** Write the difference between two RIDs to the output
285
+*/
286
+static void generate_sbsdiff(const char *zFrom, const char *zTo){
287
+ int fromid;
288
+ int toid;
289
+ Blob from, to;
290
+ if( zFrom ){
291
+ fromid = uuid_to_rid(zFrom, 0);
292
+ content_get(fromid, &from);
293
+ }else{
294
+ blob_zero(&from);
295
+ }
296
+ if( zTo ){
297
+ toid = uuid_to_rid(zTo, 0);
298
+ content_get(toid, &to);
299
+ }else{
300
+ blob_zero(&to);
301
+ }
302
+ html_sbsdiff(&from, &to, 5, 1);
303
+ blob_reset(&from);
304
+ blob_reset(&to);
305
+}
306
+
281307
282308
/*
283309
** Write a line of web-page output that shows changes that have occurred
284310
** to a file between two check-ins.
285311
*/
@@ -287,10 +313,11 @@
287313
const char *zName, /* Name of the file that has changed */
288314
const char *zOld, /* blob.uuid before change. NULL for added files */
289315
const char *zNew, /* blob.uuid after change. NULL for deletes */
290316
const char *zOldName, /* Prior name. NULL if no name change. */
291317
int showDiff, /* Show edit diffs if true */
318
+ int sideBySide, /* Show diffs side-by-side */
292319
int mperm /* executable or symlink permission for zNew */
293320
){
294321
if( !g.perm.History ){
295322
if( zNew==0 ){
296323
@ <p>Deleted %h(zName)</p>
@@ -329,13 +356,21 @@
329356
}else{
330357
@ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
331358
@ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
332359
}
333360
if( showDiff ){
334
- @ <blockquote><pre>
335
- append_diff(zOld, zNew);
336
- @ </pre></blockquote>
361
+ if( sideBySide ){
362
+ @ <table class="sbsdiff">
363
+ @ <tr><th colspan="2" class="diffhdr"">Old (%s(zOld))</th><th/>
364
+ @ <th colspan="2" class="diffhdr">New (%s(zNew))</th></tr>
365
+ generate_sbsdiff(zOld, zNew);
366
+ @ </table>
367
+ }else{
368
+ @ <blockquote><pre>
369
+ append_diff(zOld, zNew);
370
+ @ </pre></blockquote>
371
+ }
337372
}else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
338373
@ &nbsp;&nbsp;
339374
@ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
340375
}
341376
@ </p>
@@ -361,10 +396,11 @@
361396
void ci_page(void){
362397
Stmt q;
363398
int rid;
364399
int isLeaf;
365400
int showDiff;
401
+ int sideBySide=0; /* Temporary default */
366402
const char *zName; /* Name of the checkin to be displayed */
367403
const char *zUuid; /* UUID of zName */
368404
const char *zParent; /* UUID of the parent checkin (if any) */
369405
370406
login_check_credentials();
@@ -540,11 +576,12 @@
540576
const char *zName = db_column_text(&q,0);
541577
int mperm = db_column_int(&q, 1);
542578
const char *zOld = db_column_text(&q,2);
543579
const char *zNew = db_column_text(&q,3);
544580
const char *zOldName = db_column_text(&q, 4);
545
- append_file_change_line(zName, zOld, zNew, zOldName, showDiff, mperm);
581
+ append_file_change_line(zName, zOld, zNew, zOldName, showDiff,
582
+ sideBySide, mperm);
546583
}
547584
db_finalize(&q);
548585
}
549586
style_footer();
550587
}
@@ -690,17 +727,18 @@
690727
}
691728
692729
693730
/*
694731
** WEBPAGE: vdiff
695
-** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN
732
+** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN;sbs=BOOLEAN
696733
**
697734
** Show all differences between two checkins.
698735
*/
699736
void vdiff_page(void){
700737
int ridFrom, ridTo;
701738
int showDetail = 0;
739
+ int sideBySide = 0;
702740
Manifest *pFrom, *pTo;
703741
ManifestFile *pFileFrom, *pFileTo;
704742
705743
login_check_credentials();
706744
if( !g.perm.Read ){ login_needed(); return; }
@@ -709,10 +747,11 @@
709747
pFrom = vdiff_parse_manifest("from", &ridFrom);
710748
if( pFrom==0 ) return;
711749
pTo = vdiff_parse_manifest("to", &ridTo);
712750
if( pTo==0 ) return;
713751
showDetail = atoi(PD("detail","0"));
752
+ sideBySide = atoi(PD("sbs","1"));
714753
style_header("Check-in Differences");
715754
@ <h2>Difference From:</h2><blockquote>
716755
checkin_description(ridFrom);
717756
@ </blockquote><h2>To:</h2><blockquote>
718757
checkin_description(ridTo);
@@ -731,25 +770,25 @@
731770
}else{
732771
cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
733772
}
734773
if( cmp<0 ){
735774
append_file_change_line(pFileFrom->zName,
736
- pFileFrom->zUuid, 0, 0, 0, 0);
775
+ pFileFrom->zUuid, 0, 0, 0, 0, 0);
737776
pFileFrom = manifest_file_next(pFrom, 0);
738777
}else if( cmp>0 ){
739778
append_file_change_line(pFileTo->zName,
740
- 0, pFileTo->zUuid, 0, 0,
779
+ 0, pFileTo->zUuid, 0, 0, 0,
741780
manifest_file_mperm(pFileTo));
742781
pFileTo = manifest_file_next(pTo, 0);
743782
}else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
744783
/* No changes */
745784
pFileFrom = manifest_file_next(pFrom, 0);
746785
pFileTo = manifest_file_next(pTo, 0);
747786
}else{
748787
append_file_change_line(pFileFrom->zName,
749788
pFileFrom->zUuid,
750
- pFileTo->zUuid, 0, showDetail,
789
+ pFileTo->zUuid, 0, showDetail, sideBySide,
751790
manifest_file_mperm(pFileTo));
752791
pFileFrom = manifest_file_next(pFrom, 0);
753792
pFileTo = manifest_file_next(pTo, 0);
754793
}
755794
}
756795
--- src/info.c
+++ src/info.c
@@ -276,10 +276,36 @@
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
282 /*
283 ** Write a line of web-page output that shows changes that have occurred
284 ** to a file between two check-ins.
285 */
@@ -287,10 +313,11 @@
287 const char *zName, /* Name of the file that has changed */
288 const char *zOld, /* blob.uuid before change. NULL for added files */
289 const char *zNew, /* blob.uuid after change. NULL for deletes */
290 const char *zOldName, /* Prior name. NULL if no name change. */
291 int showDiff, /* Show edit diffs if true */
 
292 int mperm /* executable or symlink permission for zNew */
293 ){
294 if( !g.perm.History ){
295 if( zNew==0 ){
296 @ <p>Deleted %h(zName)</p>
@@ -329,13 +356,21 @@
329 }else{
330 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
331 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
332 }
333 if( showDiff ){
334 @ <blockquote><pre>
335 append_diff(zOld, zNew);
336 @ </pre></blockquote>
 
 
 
 
 
 
 
 
337 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
338 @ &nbsp;&nbsp;
339 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
340 }
341 @ </p>
@@ -361,10 +396,11 @@
361 void ci_page(void){
362 Stmt q;
363 int rid;
364 int isLeaf;
365 int showDiff;
 
366 const char *zName; /* Name of the checkin to be displayed */
367 const char *zUuid; /* UUID of zName */
368 const char *zParent; /* UUID of the parent checkin (if any) */
369
370 login_check_credentials();
@@ -540,11 +576,12 @@
540 const char *zName = db_column_text(&q,0);
541 int mperm = db_column_int(&q, 1);
542 const char *zOld = db_column_text(&q,2);
543 const char *zNew = db_column_text(&q,3);
544 const char *zOldName = db_column_text(&q, 4);
545 append_file_change_line(zName, zOld, zNew, zOldName, showDiff, mperm);
 
546 }
547 db_finalize(&q);
548 }
549 style_footer();
550 }
@@ -690,17 +727,18 @@
690 }
691
692
693 /*
694 ** WEBPAGE: vdiff
695 ** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN
696 **
697 ** Show all differences between two checkins.
698 */
699 void vdiff_page(void){
700 int ridFrom, ridTo;
701 int showDetail = 0;
 
702 Manifest *pFrom, *pTo;
703 ManifestFile *pFileFrom, *pFileTo;
704
705 login_check_credentials();
706 if( !g.perm.Read ){ login_needed(); return; }
@@ -709,10 +747,11 @@
709 pFrom = vdiff_parse_manifest("from", &ridFrom);
710 if( pFrom==0 ) return;
711 pTo = vdiff_parse_manifest("to", &ridTo);
712 if( pTo==0 ) return;
713 showDetail = atoi(PD("detail","0"));
 
714 style_header("Check-in Differences");
715 @ <h2>Difference From:</h2><blockquote>
716 checkin_description(ridFrom);
717 @ </blockquote><h2>To:</h2><blockquote>
718 checkin_description(ridTo);
@@ -731,25 +770,25 @@
731 }else{
732 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
733 }
734 if( cmp<0 ){
735 append_file_change_line(pFileFrom->zName,
736 pFileFrom->zUuid, 0, 0, 0, 0);
737 pFileFrom = manifest_file_next(pFrom, 0);
738 }else if( cmp>0 ){
739 append_file_change_line(pFileTo->zName,
740 0, pFileTo->zUuid, 0, 0,
741 manifest_file_mperm(pFileTo));
742 pFileTo = manifest_file_next(pTo, 0);
743 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
744 /* No changes */
745 pFileFrom = manifest_file_next(pFrom, 0);
746 pFileTo = manifest_file_next(pTo, 0);
747 }else{
748 append_file_change_line(pFileFrom->zName,
749 pFileFrom->zUuid,
750 pFileTo->zUuid, 0, showDetail,
751 manifest_file_mperm(pFileTo));
752 pFileFrom = manifest_file_next(pFrom, 0);
753 pFileTo = manifest_file_next(pTo, 0);
754 }
755 }
756
--- src/info.c
+++ src/info.c
@@ -276,10 +276,36 @@
276 @ %h(blob_str(&out))
277 blob_reset(&from);
278 blob_reset(&to);
279 blob_reset(&out);
280 }
281
282
283 /*
284 ** Write the difference between two RIDs to the output
285 */
286 static void generate_sbsdiff(const char *zFrom, const char *zTo){
287 int fromid;
288 int toid;
289 Blob from, to;
290 if( zFrom ){
291 fromid = uuid_to_rid(zFrom, 0);
292 content_get(fromid, &from);
293 }else{
294 blob_zero(&from);
295 }
296 if( zTo ){
297 toid = uuid_to_rid(zTo, 0);
298 content_get(toid, &to);
299 }else{
300 blob_zero(&to);
301 }
302 html_sbsdiff(&from, &to, 5, 1);
303 blob_reset(&from);
304 blob_reset(&to);
305 }
306
307
308 /*
309 ** Write a line of web-page output that shows changes that have occurred
310 ** to a file between two check-ins.
311 */
@@ -287,10 +313,11 @@
313 const char *zName, /* Name of the file that has changed */
314 const char *zOld, /* blob.uuid before change. NULL for added files */
315 const char *zNew, /* blob.uuid after change. NULL for deletes */
316 const char *zOldName, /* Prior name. NULL if no name change. */
317 int showDiff, /* Show edit diffs if true */
318 int sideBySide, /* Show diffs side-by-side */
319 int mperm /* executable or symlink permission for zNew */
320 ){
321 if( !g.perm.History ){
322 if( zNew==0 ){
323 @ <p>Deleted %h(zName)</p>
@@ -329,13 +356,21 @@
356 }else{
357 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
358 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a>
359 }
360 if( showDiff ){
361 if( sideBySide ){
362 @ <table class="sbsdiff">
363 @ <tr><th colspan="2" class="diffhdr"">Old (%s(zOld))</th><th/>
364 @ <th colspan="2" class="diffhdr">New (%s(zNew))</th></tr>
365 generate_sbsdiff(zOld, zNew);
366 @ </table>
367 }else{
368 @ <blockquote><pre>
369 append_diff(zOld, zNew);
370 @ </pre></blockquote>
371 }
372 }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){
373 @ &nbsp;&nbsp;
374 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&amp;v2=%S(zNew)">[diff]</a>
375 }
376 @ </p>
@@ -361,10 +396,11 @@
396 void ci_page(void){
397 Stmt q;
398 int rid;
399 int isLeaf;
400 int showDiff;
401 int sideBySide=0; /* Temporary default */
402 const char *zName; /* Name of the checkin to be displayed */
403 const char *zUuid; /* UUID of zName */
404 const char *zParent; /* UUID of the parent checkin (if any) */
405
406 login_check_credentials();
@@ -540,11 +576,12 @@
576 const char *zName = db_column_text(&q,0);
577 int mperm = db_column_int(&q, 1);
578 const char *zOld = db_column_text(&q,2);
579 const char *zNew = db_column_text(&q,3);
580 const char *zOldName = db_column_text(&q, 4);
581 append_file_change_line(zName, zOld, zNew, zOldName, showDiff,
582 sideBySide, mperm);
583 }
584 db_finalize(&q);
585 }
586 style_footer();
587 }
@@ -690,17 +727,18 @@
727 }
728
729
730 /*
731 ** WEBPAGE: vdiff
732 ** URL: /vdiff?from=UUID&amp;to=UUID&amp;detail=BOOLEAN;sbs=BOOLEAN
733 **
734 ** Show all differences between two checkins.
735 */
736 void vdiff_page(void){
737 int ridFrom, ridTo;
738 int showDetail = 0;
739 int sideBySide = 0;
740 Manifest *pFrom, *pTo;
741 ManifestFile *pFileFrom, *pFileTo;
742
743 login_check_credentials();
744 if( !g.perm.Read ){ login_needed(); return; }
@@ -709,10 +747,11 @@
747 pFrom = vdiff_parse_manifest("from", &ridFrom);
748 if( pFrom==0 ) return;
749 pTo = vdiff_parse_manifest("to", &ridTo);
750 if( pTo==0 ) return;
751 showDetail = atoi(PD("detail","0"));
752 sideBySide = atoi(PD("sbs","1"));
753 style_header("Check-in Differences");
754 @ <h2>Difference From:</h2><blockquote>
755 checkin_description(ridFrom);
756 @ </blockquote><h2>To:</h2><blockquote>
757 checkin_description(ridTo);
@@ -731,25 +770,25 @@
770 }else{
771 cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName);
772 }
773 if( cmp<0 ){
774 append_file_change_line(pFileFrom->zName,
775 pFileFrom->zUuid, 0, 0, 0, 0, 0);
776 pFileFrom = manifest_file_next(pFrom, 0);
777 }else if( cmp>0 ){
778 append_file_change_line(pFileTo->zName,
779 0, pFileTo->zUuid, 0, 0, 0,
780 manifest_file_mperm(pFileTo));
781 pFileTo = manifest_file_next(pTo, 0);
782 }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){
783 /* No changes */
784 pFileFrom = manifest_file_next(pFrom, 0);
785 pFileTo = manifest_file_next(pTo, 0);
786 }else{
787 append_file_change_line(pFileFrom->zName,
788 pFileFrom->zUuid,
789 pFileTo->zUuid, 0, showDetail, sideBySide,
790 manifest_file_mperm(pFileTo));
791 pFileFrom = manifest_file_next(pFrom, 0);
792 pFileTo = manifest_file_next(pTo, 0);
793 }
794 }
795
+43
--- src/skins.c
+++ src/skins.c
@@ -885,10 +885,53 @@
885885
@ padding: 3px 5px;
886886
@ }
887887
@
888888
@ textarea {
889889
@ font-size: 1em;
890
+@ }
891
+@
892
+@ /* Side-by-side diff */
893
+@ table.sbsdiff {
894
+@ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
895
+@ font-size: 7pt;
896
+@ border-collapse:collapse;
897
+@ white-space: pre;
898
+@ width: 100%;
899
+@ border: 1px #000 dashed;
900
+@ }
901
+@
902
+@ table.sbsdiff th.diffhdr {
903
+@ border-bottom: dotted;
904
+@ border-width: 1px;
905
+@ }
906
+@
907
+@ table.sbsdiff tr td {
908
+@ white-space: pre;
909
+@ padding-left: 3px;
910
+@ padding-right: 3px;
911
+@ margin: 0px;
912
+@ }
913
+@
914
+@ table.sbsdiff tr td.lineno {
915
+@ text-align: right;
916
+@ }
917
+@
918
+@ table.sbsdiff tr td.meta {
919
+@ background-color: rgb(170, 160, 255);
920
+@ text-align: center;
921
+@ }
922
+@
923
+@ table.sbsdiff tr td.added {
924
+@ background-color: rgb(180, 250, 180);
925
+@ }
926
+@
927
+@ table.sbsdiff tr td.removed {
928
+@ background-color: rgb(250, 130, 130);
929
+@ }
930
+@
931
+@ table.sbsdiff tr td.changed {
932
+@ background-color: rgb(210, 210, 200);
890933
@ }');
891934
@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
892935
@ <head>
893936
@ <title>$<project_name>: $<title></title>
894937
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
895938
--- src/skins.c
+++ src/skins.c
@@ -885,10 +885,53 @@
885 @ padding: 3px 5px;
886 @ }
887 @
888 @ textarea {
889 @ font-size: 1em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
890 @ }');
891 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
892 @ <head>
893 @ <title>$<project_name>: $<title></title>
894 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
895
--- src/skins.c
+++ src/skins.c
@@ -885,10 +885,53 @@
885 @ padding: 3px 5px;
886 @ }
887 @
888 @ textarea {
889 @ font-size: 1em;
890 @ }
891 @
892 @ /* Side-by-side diff */
893 @ table.sbsdiff {
894 @ font-family: Dejavu Sans Mono, Monaco, Lucida Console, monospace;
895 @ font-size: 7pt;
896 @ border-collapse:collapse;
897 @ white-space: pre;
898 @ width: 100%;
899 @ border: 1px #000 dashed;
900 @ }
901 @
902 @ table.sbsdiff th.diffhdr {
903 @ border-bottom: dotted;
904 @ border-width: 1px;
905 @ }
906 @
907 @ table.sbsdiff tr td {
908 @ white-space: pre;
909 @ padding-left: 3px;
910 @ padding-right: 3px;
911 @ margin: 0px;
912 @ }
913 @
914 @ table.sbsdiff tr td.lineno {
915 @ text-align: right;
916 @ }
917 @
918 @ table.sbsdiff tr td.meta {
919 @ background-color: rgb(170, 160, 255);
920 @ text-align: center;
921 @ }
922 @
923 @ table.sbsdiff tr td.added {
924 @ background-color: rgb(180, 250, 180);
925 @ }
926 @
927 @ table.sbsdiff tr td.removed {
928 @ background-color: rgb(250, 130, 130);
929 @ }
930 @
931 @ table.sbsdiff tr td.changed {
932 @ background-color: rgb(210, 210, 200);
933 @ }');
934 @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html>
935 @ <head>
936 @ <title>$<project_name>: $<title></title>
937 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed"
938

Keyboard Shortcuts

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