| | @@ -276,10 +276,40 @@ |
| 276 | 276 | @ %h(blob_str(&out)) |
| 277 | 277 | blob_reset(&from); |
| 278 | 278 | blob_reset(&to); |
| 279 | 279 | blob_reset(&out); |
| 280 | 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 | + @ <table class="sbsdiff"> |
| 303 | + @ <tr><th colspan="2" class="diffhdr">Old (%S(zFrom))</th><th/> |
| 304 | + @ <th colspan="2" class="diffhdr">New (%S(zTo))</th></tr> |
| 305 | + html_sbsdiff(&from, &to, 5, 1); |
| 306 | + @ </table> |
| 307 | + blob_reset(&from); |
| 308 | + blob_reset(&to); |
| 309 | +} |
| 310 | + |
| 281 | 311 | |
| 282 | 312 | /* |
| 283 | 313 | ** Write a line of web-page output that shows changes that have occurred |
| 284 | 314 | ** to a file between two check-ins. |
| 285 | 315 | */ |
| | @@ -287,10 +317,11 @@ |
| 287 | 317 | const char *zName, /* Name of the file that has changed */ |
| 288 | 318 | const char *zOld, /* blob.uuid before change. NULL for added files */ |
| 289 | 319 | const char *zNew, /* blob.uuid after change. NULL for deletes */ |
| 290 | 320 | const char *zOldName, /* Prior name. NULL if no name change. */ |
| 291 | 321 | int showDiff, /* Show edit diffs if true */ |
| 322 | + int sideBySide, /* Show diffs side-by-side */ |
| 292 | 323 | int mperm /* executable or symlink permission for zNew */ |
| 293 | 324 | ){ |
| 294 | 325 | if( !g.perm.History ){ |
| 295 | 326 | if( zNew==0 ){ |
| 296 | 327 | @ <p>Deleted %h(zName)</p> |
| | @@ -329,13 +360,17 @@ |
| 329 | 360 | }else{ |
| 330 | 361 | @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a> |
| 331 | 362 | @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a> |
| 332 | 363 | } |
| 333 | 364 | if( showDiff ){ |
| 334 | | - @ <blockquote><pre> |
| 335 | | - append_diff(zOld, zNew); |
| 336 | | - @ </pre></blockquote> |
| 365 | + if( sideBySide ){ |
| 366 | + generate_sbsdiff(zOld, zNew); |
| 367 | + }else{ |
| 368 | + @ <blockquote><pre> |
| 369 | + append_diff(zOld, zNew); |
| 370 | + @ </pre></blockquote> |
| 371 | + } |
| 337 | 372 | }else if( zOld && zNew && fossil_strcmp(zOld,zNew)!=0 ){ |
| 338 | 373 | @ |
| 339 | 374 | @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a> |
| 340 | 375 | } |
| 341 | 376 | @ </p> |
| | @@ -361,10 +396,11 @@ |
| 361 | 396 | void ci_page(void){ |
| 362 | 397 | Stmt q; |
| 363 | 398 | int rid; |
| 364 | 399 | int isLeaf; |
| 365 | 400 | int showDiff; |
| 401 | + int sideBySide; |
| 366 | 402 | const char *zName; /* Name of the checkin to be displayed */ |
| 367 | 403 | const char *zUuid; /* UUID of zName */ |
| 368 | 404 | const char *zParent; /* UUID of the parent checkin (if any) */ |
| 369 | 405 | |
| 370 | 406 | login_check_credentials(); |
| | @@ -390,10 +426,11 @@ |
| 390 | 426 | " FROM blob, event" |
| 391 | 427 | " WHERE blob.rid=%d" |
| 392 | 428 | " AND event.objid=%d", |
| 393 | 429 | rid, rid |
| 394 | 430 | ); |
| 431 | + sideBySide = atoi(PD("sbs","1")); |
| 395 | 432 | if( db_step(&q)==SQLITE_ROW ){ |
| 396 | 433 | const char *zUuid = db_column_text(&q, 0); |
| 397 | 434 | char *zTitle = mprintf("Check-in [%.10s]", zUuid); |
| 398 | 435 | char *zEUser, *zEComment; |
| 399 | 436 | const char *zUser; |
| | @@ -511,18 +548,42 @@ |
| 511 | 548 | showDiff = g.zPath[0]!='c'; |
| 512 | 549 | if( db_get_boolean("show-version-diffs", 0)==0 ){ |
| 513 | 550 | showDiff = !showDiff; |
| 514 | 551 | if( showDiff ){ |
| 515 | 552 | @ <a href="%s(g.zTop)/vinfo/%T(zName)">[hide diffs]</a> |
| 553 | + @ |
| 554 | + if( sideBySide ){ |
| 555 | + @ <a href="%s(g.zTop)/ci/%T(zName)?sbs=0"> |
| 556 | + @ [unified diffs]</a> |
| 557 | + }else{ |
| 558 | + @ <a href="%s(g.zTop)/ci/%T(zName)?sbs=1"> |
| 559 | + @ [side-by-side diffs]</a> |
| 560 | + } |
| 516 | 561 | }else{ |
| 517 | | - @ <a href="%s(g.zTop)/ci/%T(zName)">[show diffs]</a> |
| 562 | + @ <a href="%s(g.zTop)/ci/%T(zName)?sbs=0"> |
| 563 | + @ [show unified diffs]</a> |
| 564 | + @ |
| 565 | + @ <a href="%s(g.zTop)/ci/%T(zName)?sbs=1"> |
| 566 | + @ [show side-by-side diffs]</a> |
| 518 | 567 | } |
| 519 | 568 | }else{ |
| 520 | 569 | if( showDiff ){ |
| 521 | 570 | @ <a href="%s(g.zTop)/ci/%T(zName)">[hide diffs]</a> |
| 571 | + @ |
| 572 | + if( sideBySide ){ |
| 573 | + @ <a href="%s(g.zTop)/info/%T(zName)?sbs=0"> |
| 574 | + @ [unified diffs]</a> |
| 575 | + }else{ |
| 576 | + @ <a href="%s(g.zTop)/info/%T(zName)?sbs=1"> |
| 577 | + @ [side-by-side diffs]</a> |
| 578 | + } |
| 522 | 579 | }else{ |
| 523 | | - @ <a href="%s(g.zTop)/vinfo/%T(zName)">[show diffs]</a> |
| 580 | + @ <a href="%s(g.zTop)/vinfo/%T(zName)?sbs=0"> |
| 581 | + @ [show unified diffs]</a> |
| 582 | + @ |
| 583 | + @ <a href="%s(g.zTop)/vinfo/%T(zName)?sbs=1"> |
| 584 | + @ [show side-by-side diffs]</a> |
| 524 | 585 | } |
| 525 | 586 | } |
| 526 | 587 | @ |
| 527 | 588 | @ <a href="%s(g.zTop)/vpatch?from=%S(zParent)&to=%S(zUuid)">[patch]</a><br/> |
| 528 | 589 | db_prepare(&q, |
| | @@ -540,11 +601,12 @@ |
| 540 | 601 | const char *zName = db_column_text(&q,0); |
| 541 | 602 | int mperm = db_column_int(&q, 1); |
| 542 | 603 | const char *zOld = db_column_text(&q,2); |
| 543 | 604 | const char *zNew = db_column_text(&q,3); |
| 544 | 605 | const char *zOldName = db_column_text(&q, 4); |
| 545 | | - append_file_change_line(zName, zOld, zNew, zOldName, showDiff, mperm); |
| 606 | + append_file_change_line(zName, zOld, zNew, zOldName, showDiff, |
| 607 | + sideBySide, mperm); |
| 546 | 608 | } |
| 547 | 609 | db_finalize(&q); |
| 548 | 610 | } |
| 549 | 611 | style_footer(); |
| 550 | 612 | } |
| | @@ -690,17 +752,18 @@ |
| 690 | 752 | } |
| 691 | 753 | |
| 692 | 754 | |
| 693 | 755 | /* |
| 694 | 756 | ** WEBPAGE: vdiff |
| 695 | | -** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN |
| 757 | +** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN;sbs=BOOLEAN |
| 696 | 758 | ** |
| 697 | 759 | ** Show all differences between two checkins. |
| 698 | 760 | */ |
| 699 | 761 | void vdiff_page(void){ |
| 700 | 762 | int ridFrom, ridTo; |
| 701 | 763 | int showDetail = 0; |
| 764 | + int sideBySide = 0; |
| 702 | 765 | Manifest *pFrom, *pTo; |
| 703 | 766 | ManifestFile *pFileFrom, *pFileTo; |
| 704 | 767 | |
| 705 | 768 | login_check_credentials(); |
| 706 | 769 | if( !g.perm.Read ){ login_needed(); return; } |
| | @@ -709,10 +772,20 @@ |
| 709 | 772 | pFrom = vdiff_parse_manifest("from", &ridFrom); |
| 710 | 773 | if( pFrom==0 ) return; |
| 711 | 774 | pTo = vdiff_parse_manifest("to", &ridTo); |
| 712 | 775 | if( pTo==0 ) return; |
| 713 | 776 | showDetail = atoi(PD("detail","0")); |
| 777 | + sideBySide = atoi(PD("sbs","1")); |
| 778 | + if( !sideBySide ){ |
| 779 | + style_submenu_element("Side-by-side Diff", "sbsdiff", |
| 780 | + "%s/vdiff?from=%T&to=%T&detail=%d&sbs=1", |
| 781 | + g.zTop, P("from"), P("to"), showDetail); |
| 782 | + }else{ |
| 783 | + style_submenu_element("Unified Diff", "udiff", |
| 784 | + "%s/vdiff?from=%T&to=%T&detail=%d&sbs=0", |
| 785 | + g.zTop, P("from"), P("to"), showDetail); |
| 786 | + } |
| 714 | 787 | style_header("Check-in Differences"); |
| 715 | 788 | @ <h2>Difference From:</h2><blockquote> |
| 716 | 789 | checkin_description(ridFrom); |
| 717 | 790 | @ </blockquote><h2>To:</h2><blockquote> |
| 718 | 791 | checkin_description(ridTo); |
| | @@ -731,25 +804,25 @@ |
| 731 | 804 | }else{ |
| 732 | 805 | cmp = fossil_strcmp(pFileFrom->zName, pFileTo->zName); |
| 733 | 806 | } |
| 734 | 807 | if( cmp<0 ){ |
| 735 | 808 | append_file_change_line(pFileFrom->zName, |
| 736 | | - pFileFrom->zUuid, 0, 0, 0, 0); |
| 809 | + pFileFrom->zUuid, 0, 0, 0, 0, 0); |
| 737 | 810 | pFileFrom = manifest_file_next(pFrom, 0); |
| 738 | 811 | }else if( cmp>0 ){ |
| 739 | 812 | append_file_change_line(pFileTo->zName, |
| 740 | | - 0, pFileTo->zUuid, 0, 0, |
| 813 | + 0, pFileTo->zUuid, 0, 0, 0, |
| 741 | 814 | manifest_file_mperm(pFileTo)); |
| 742 | 815 | pFileTo = manifest_file_next(pTo, 0); |
| 743 | 816 | }else if( fossil_strcmp(pFileFrom->zUuid, pFileTo->zUuid)==0 ){ |
| 744 | 817 | /* No changes */ |
| 745 | 818 | pFileFrom = manifest_file_next(pFrom, 0); |
| 746 | 819 | pFileTo = manifest_file_next(pTo, 0); |
| 747 | 820 | }else{ |
| 748 | 821 | append_file_change_line(pFileFrom->zName, |
| 749 | 822 | pFileFrom->zUuid, |
| 750 | | - pFileTo->zUuid, 0, showDetail, |
| 823 | + pFileTo->zUuid, 0, showDetail, sideBySide, |
| 751 | 824 | manifest_file_mperm(pFileTo)); |
| 752 | 825 | pFileFrom = manifest_file_next(pFrom, 0); |
| 753 | 826 | pFileTo = manifest_file_next(pTo, 0); |
| 754 | 827 | } |
| 755 | 828 | } |
| | @@ -983,28 +1056,30 @@ |
| 983 | 1056 | } |
| 984 | 1057 | |
| 985 | 1058 | |
| 986 | 1059 | /* |
| 987 | 1060 | ** WEBPAGE: fdiff |
| 988 | | -** URL: fdiff?v1=UUID&v2=UUID&patch |
| 1061 | +** URL: fdiff?v1=UUID&v2=UUID&patch&sbs=BOOLEAN |
| 989 | 1062 | ** |
| 990 | | -** Two arguments, v1 and v2, identify the files to be diffed. Show the |
| 991 | | -** difference between the two artifacts. Generate plaintext if "patch" |
| 992 | | -** is present. |
| 1063 | +** Two arguments, v1 and v2, identify the files to be diffed. Show the |
| 1064 | +** difference between the two artifacts. Show diff side by side unless sbs |
| 1065 | +** is 0. Generate plaintext if "patch" is present. |
| 993 | 1066 | */ |
| 994 | 1067 | void diff_page(void){ |
| 995 | 1068 | int v1, v2; |
| 996 | 1069 | int isPatch; |
| 1070 | + int sideBySide; |
| 997 | 1071 | Blob c1, c2, diff, *pOut; |
| 998 | 1072 | char *zV1; |
| 999 | 1073 | char *zV2; |
| 1000 | 1074 | |
| 1001 | 1075 | login_check_credentials(); |
| 1002 | 1076 | if( !g.perm.Read ){ login_needed(); return; } |
| 1003 | 1077 | v1 = name_to_rid_www("v1"); |
| 1004 | 1078 | v2 = name_to_rid_www("v2"); |
| 1005 | 1079 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 1080 | + sideBySide = atoi(PD("sbs","1")); |
| 1006 | 1081 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 1007 | 1082 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 1008 | 1083 | isPatch = P("patch")!=0; |
| 1009 | 1084 | if( isPatch ){ |
| 1010 | 1085 | pOut = cgi_output_blob(); |
| | @@ -1011,28 +1086,44 @@ |
| 1011 | 1086 | cgi_set_content_type("text/plain"); |
| 1012 | 1087 | }else{ |
| 1013 | 1088 | blob_zero(&diff); |
| 1014 | 1089 | pOut = &diff; |
| 1015 | 1090 | } |
| 1016 | | - content_get(v1, &c1); |
| 1017 | | - content_get(v2, &c2); |
| 1018 | | - text_diff(&c1, &c2, pOut, 4, 1); |
| 1019 | | - blob_reset(&c1); |
| 1020 | | - blob_reset(&c2); |
| 1091 | + if( !sideBySide || isPatch ){ |
| 1092 | + content_get(v1, &c1); |
| 1093 | + content_get(v2, &c2); |
| 1094 | + text_diff(&c1, &c2, pOut, 4, 1); |
| 1095 | + blob_reset(&c1); |
| 1096 | + blob_reset(&c2); |
| 1097 | + } |
| 1021 | 1098 | if( !isPatch ){ |
| 1022 | 1099 | style_header("Diff"); |
| 1023 | 1100 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 1024 | 1101 | g.zTop, P("v1"), P("v2")); |
| 1102 | + if( !sideBySide ){ |
| 1103 | + style_submenu_element("Side-by-side Diff", "sbsdiff", |
| 1104 | + "%s/fdiff?v1=%T&v2=%T&sbs=1", |
| 1105 | + g.zTop, P("v1"), P("v2")); |
| 1106 | + }else{ |
| 1107 | + style_submenu_element("Unified Diff", "udiff", |
| 1108 | + "%s/fdiff?v1=%T&v2=%T&sbs=0", |
| 1109 | + g.zTop, P("v1"), P("v2")); |
| 1110 | + } |
| 1111 | + |
| 1025 | 1112 | @ <h2>Differences From |
| 1026 | 1113 | @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> |
| 1027 | 1114 | object_description(v1, 0, 0); |
| 1028 | 1115 | @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> |
| 1029 | 1116 | object_description(v2, 0, 0); |
| 1030 | 1117 | @ <hr /> |
| 1031 | | - @ <blockquote><pre> |
| 1032 | | - @ %h(blob_str(&diff)) |
| 1033 | | - @ </pre></blockquote> |
| 1118 | + if( sideBySide ){ |
| 1119 | + generate_sbsdiff(zV1, zV2); |
| 1120 | + }else{ |
| 1121 | + @ <blockquote><pre> |
| 1122 | + @ %h(blob_str(&diff)) |
| 1123 | + @ </pre></blockquote> |
| 1124 | + } |
| 1034 | 1125 | blob_reset(&diff); |
| 1035 | 1126 | style_footer(); |
| 1036 | 1127 | } |
| 1037 | 1128 | } |
| 1038 | 1129 | |
| 1039 | 1130 | |