Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch diff-enhancements Excluding Merge-Ins
This is equivalent to a diff from a75e2d2504 to a505abccc6
2011-10-21
| ||
21:55 | Merge the side-by-side diff spacing bug fix into trunk. check-in: 54e730c339 user: drh tags: trunk | |
21:50 | Fix a spacing bug in the display of side-by-side diffs. Closed-Leaf check-in: a505abccc6 user: drh tags: diff-enhancements | |
21:34 | Merge the diff enhancements into trunk. check-in: c244605862 user: drh tags: trunk | |
21:31 | Add support for side-by-side diff from the command-line "diff" command. check-in: ac81759f65 user: drh tags: diff-enhancements | |
20:24 | Begin improvement efforts on the "diff" functions by adding the --context option to the "diff" command. check-in: 3bbbbdfd7d user: drh tags: diff-enhancements | |
12:52 | Version 1.20. check-in: a75e2d2504 user: drh tags: trunk, release, version-1.20 | |
2011-10-20
| ||
17:10 | minor 1.20 changelog tweak. check-in: 1d12fcc416 user: stephan tags: trunk | |
Changes to src/diff.c.
19 19 ** text files. 20 20 */ 21 21 #include "config.h" 22 22 #include "diff.h" 23 23 #include <assert.h> 24 24 25 25 26 +#if INTERFACE 27 +/* 28 +** Allowed flag parameters to the text_diff() and html_sbsdiff() funtions: 29 +*/ 30 +#define DIFF_CONTEXT_MASK 0x0000fff /* Lines of context. Default if 0 */ 31 +#define DIFF_WIDTH_MASK 0x00ff000 /* side-by-side column width */ 32 +#define DIFF_IGNORE_EOLWS 0x0100000 /* Ignore end-of-line whitespace */ 33 +#define DIFF_SIDEBYSIDE 0x0200000 /* Generate a side-by-side diff */ 34 +#define DIFF_NEWFILE 0x0400000 /* Missing files are as empty files */ 35 + 36 +#endif /* INTERFACE */ 37 + 26 38 /* 27 39 ** Maximum length of a line in a text file. (8192) 28 40 */ 29 41 #define LENGTH_MASK_SZ 13 30 42 #define LENGTH_MASK ((1<<LENGTH_MASK_SZ)-1) 31 43 32 44 /* ................................................................................ 283 295 m = R[r+nr*3]; 284 296 if( m>nContext ) m = nContext; 285 297 for(j=0; j<m; j++){ 286 298 appendDiffLine(pOut, " ", &B[b+j]); 287 299 } 288 300 } 289 301 } 302 + 303 +/* 304 +** Append spaces to a blob 305 +*/ 306 +static void appendSpace(Blob *pOut, int n){ 307 + const char z100[101] = 308 + " " 309 + " "; 310 + while( n>100 ){ 311 + blob_append(pOut, z100, 100); n -= 100; 312 + } 313 + if( n>0 ){ 314 + blob_append(pOut, z100, n); 315 + } 316 +} 317 + 318 +/* 319 +** Append text to a sbs diff output 320 +*/ 321 +static void appendSbsLine(Blob *pOut, DLine *pLine, int width, int pad){ 322 + int sz = pLine->h & LENGTH_MASK; 323 + if( sz<width ){ 324 + blob_append(pOut, pLine->z, sz); 325 + if( pad ) appendSpace(pOut, width-sz); 326 + }else{ 327 + blob_append(pOut, pLine->z, width); 328 + } 329 +} 330 + 331 + 332 +/* 333 +** Given a diff context in which the aEdit[] array has been filled 334 +** in, compute a side-by-side diff into pOut. 335 +*/ 336 +static void sbsDiff(DContext *p, Blob *pOut, int nContext, int width){ 337 + DLine *A; /* Left side of the diff */ 338 + DLine *B; /* Right side of the diff */ 339 + int a = 0; /* Index of next line in A[] */ 340 + int b = 0; /* Index of next line in B[] */ 341 + int *R; /* Array of COPY/DELETE/INSERT triples */ 342 + int r; /* Index into R[] */ 343 + int nr; /* Number of COPY/DELETE/INSERT triples to process */ 344 + int mxr; /* Maximum value for r */ 345 + int na, nb; /* Number of lines shown from A and B */ 346 + int i, j; /* Loop counters */ 347 + int m, ma, mb;/* Number of lines to output */ 348 + int skip; /* Number of lines to skip */ 349 + char zFormat[50]; /* Output format */ 350 + 351 + sqlite3_snprintf(sizeof(zFormat), zFormat, 352 + "%%4d %%%d.%ds %%c %%4d %%.%ds\n", 353 + width, width, width); 354 + A = p->aFrom; 355 + B = p->aTo; 356 + R = p->aEdit; 357 + mxr = p->nEdit; 358 + while( mxr>2 && R[mxr-1]==0 && R[mxr-2]==0 ){ mxr -= 3; } 359 + for(r=0; r<mxr; r += 3*nr){ 360 + /* Figure out how many triples to show in a single block */ 361 + for(nr=1; R[r+nr*3]>0 && R[r+nr*3]<nContext*2; nr++){} 362 + /* printf("r=%d nr=%d\n", r, nr); */ 363 + 364 + /* For the current block comprising nr triples, figure out 365 + ** how many lines of A and B are to be displayed 366 + */ 367 + if( R[r]>nContext ){ 368 + na = nb = nContext; 369 + skip = R[r] - nContext; 370 + }else{ 371 + na = nb = R[r]; 372 + skip = 0; 373 + } 374 + for(i=0; i<nr; i++){ 375 + na += R[r+i*3+1]; 376 + nb += R[r+i*3+2]; 377 + } 378 + if( R[r+nr*3]>nContext ){ 379 + na += nContext; 380 + nb += nContext; 381 + }else{ 382 + na += R[r+nr*3]; 383 + nb += R[r+nr*3]; 384 + } 385 + for(i=1; i<nr; i++){ 386 + na += R[r+i*3]; 387 + nb += R[r+i*3]; 388 + } 389 + /* 390 + * If the patch changes an empty file or results in an empty file, 391 + * the block header must use 0,0 as position indicator and not 1,0. 392 + * Otherwise, patch would be confused and may reject the diff. 393 + */ 394 + blob_appendf(pOut,"@@ -%d,%d +%d,%d @@\n", 395 + na ? a+skip+1 : 0, na, 396 + nb ? b+skip+1 : 0, nb); 397 + 398 + /* Show the initial common area */ 399 + a += skip; 400 + b += skip; 401 + m = R[r] - skip; 402 + for(j=0; j<m; j++){ 403 + blob_appendf(pOut, "%6d ", a+j); 404 + appendSbsLine(pOut, &A[a+j], width, 1); 405 + blob_appendf(pOut, " %6d ", b+j); 406 + appendSbsLine(pOut, &B[b+j], width, 0); 407 + blob_append(pOut, "\n", 1); 408 + } 409 + a += m; 410 + b += m; 411 + 412 + /* Show the differences */ 413 + for(i=0; i<nr; i++){ 414 + ma = R[r+i*3+1]; 415 + mb = R[r+i*3+2]; 416 + m = ma<mb ? ma : mb; 417 + for(j=0; j<m; j++){ 418 + blob_appendf(pOut, "%6d ", a+j); 419 + appendSbsLine(pOut, &A[a+j], width, 1); 420 + blob_appendf(pOut, " | %6d ", b+j); 421 + appendSbsLine(pOut, &B[b+j], width, 0); 422 + blob_append(pOut, "\n", 1); 423 + } 424 + a += m; 425 + b += m; 426 + ma -= m; 427 + mb -= m; 428 + for(j=0; j<ma; j++){ 429 + blob_appendf(pOut, "%6d ", a+j); 430 + appendSbsLine(pOut, &A[a+j], width, 1); 431 + blob_append(pOut, " <\n", 3); 432 + } 433 + a += ma; 434 + for(j=0; j<mb; j++){ 435 + appendSpace(pOut, width+7); 436 + blob_appendf(pOut, " > %6d ", b+j); 437 + appendSbsLine(pOut, &B[b+j], width, 0); 438 + blob_append(pOut, "\n", 1); 439 + } 440 + b += mb; 441 + if( i<nr-1 ){ 442 + m = R[r+i*3+3]; 443 + for(j=0; j<m; j++){ 444 + blob_appendf(pOut, "%6d ", a+j); 445 + appendSbsLine(pOut, &A[a+j], width, 1); 446 + blob_appendf(pOut, " %6d ", b+j); 447 + appendSbsLine(pOut, &B[b+j], width, 0); 448 + blob_append(pOut, "\n", 1); 449 + } 450 + b += m; 451 + a += m; 452 + } 453 + } 454 + 455 + /* Show the final common area */ 456 + assert( nr==i ); 457 + m = R[r+nr*3]; 458 + if( m>nContext ) m = nContext; 459 + for(j=0; j<m; j++){ 460 + blob_appendf(pOut, "%6d ", a+j); 461 + appendSbsLine(pOut, &A[a+j], width, 1); 462 + blob_appendf(pOut, " %6d ", b+j); 463 + appendSbsLine(pOut, &B[b+j], width, 0); 464 + blob_append(pOut, "\n", 1); 465 + } 466 + } 467 +} 290 468 291 469 /* 292 470 ** Compute the optimal longest common subsequence (LCS) using an 293 471 ** exhaustive search. This version of the LCS is only used for 294 472 ** shorter input strings since runtime is O(N*N) where N is the 295 473 ** input string length. 296 474 */ ................................................................................ 536 714 ** This diff utility does not work on binary files. If a binary 537 715 ** file is encountered, 0 is returned and pOut is written with 538 716 ** text "cannot compute difference between binary files". 539 717 */ 540 718 int *text_diff( 541 719 Blob *pA_Blob, /* FROM file */ 542 720 Blob *pB_Blob, /* TO file */ 543 - Blob *pOut, /* Write unified diff here if not NULL */ 544 - int nContext, /* Amount of context to unified diff */ 545 - int ignoreEolWs /* Ignore whitespace at the end of lines */ 721 + Blob *pOut, /* Write diff here if not NULL */ 722 + int diffFlags /* DIFF_* flags defined above */ 546 723 ){ 724 + int ignoreEolWs; /* Ignore whitespace at the end of lines */ 725 + int nContext; /* Amount of context to display */ 547 726 DContext c; 548 - 727 + 728 + nContext = diffFlags & DIFF_CONTEXT_MASK; 729 + if( nContext==0 ) nContext = 5; 730 + ignoreEolWs = (diffFlags & DIFF_IGNORE_EOLWS)!=0; 731 + 549 732 /* Prepare the input files */ 550 733 memset(&c, 0, sizeof(c)); 551 734 c.aFrom = break_into_lines(blob_str(pA_Blob), blob_size(pA_Blob), 552 735 &c.nFrom, ignoreEolWs); 553 736 c.aTo = break_into_lines(blob_str(pB_Blob), blob_size(pB_Blob), 554 737 &c.nTo, ignoreEolWs); 555 738 if( c.aFrom==0 || c.aTo==0 ){ ................................................................................ 561 744 return 0; 562 745 } 563 746 564 747 /* Compute the difference */ 565 748 diff_all(&c); 566 749 567 750 if( pOut ){ 568 - /* Compute a context diff if requested */ 569 - contextDiff(&c, pOut, nContext); 751 + /* Compute a context or side-by-side diff into pOut */ 752 + if( diffFlags & DIFF_SIDEBYSIDE ){ 753 + int width = (diffFlags & DIFF_WIDTH_MASK)/(DIFF_CONTEXT_MASK+1); 754 + if( width==0 ) width = 80; 755 + sbsDiff(&c, pOut, nContext, width); 756 + }else{ 757 + contextDiff(&c, pOut, nContext); 758 + } 570 759 free(c.aFrom); 571 760 free(c.aTo); 572 761 free(c.aEdit); 573 762 return 0; 574 763 }else{ 575 764 /* If a context diff is not requested, then return the 576 765 ** array of COPY/DELETE/INSERT triples. ................................................................................ 658 847 iFrom=iTo=0; 659 848 i=0; 660 849 while( i<c.nEdit ){ 661 850 int j; 662 851 /* Copied lines */ 663 852 for( j=0; j<c.aEdit[i]; j++){ 664 853 /* Hide lines which are copied and are further away from block boundaries 665 - ** than nConext lines. For each block with hidden lines, show a row 854 + ** than nContext lines. For each block with hidden lines, show a row 666 855 ** notifying the user about the hidden rows. 667 856 */ 668 857 if( j<nContext || j>c.aEdit[i]-nContext-1 ){ 669 858 @ <tr> 670 859 }else if( j==nContext && j<c.aEdit[i]-nContext-1 ){ 671 860 @ <tr> 672 861 @ <td class="meta" colspan="5" style="white-space: nowrap;"> ................................................................................ 774 963 int i; 775 964 int *R; 776 965 if( g.argc<4 ) usage("FILE1 FILE2 ..."); 777 966 blob_read_from_file(&a, g.argv[2]); 778 967 for(i=3; i<g.argc; i++){ 779 968 if( i>3 ) fossil_print("-------------------------------\n"); 780 969 blob_read_from_file(&b, g.argv[i]); 781 - R = text_diff(&a, &b, 0, 0, 0); 970 + R = text_diff(&a, &b, 0, 0); 782 971 for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ 783 972 fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); 784 973 } 785 974 /* free(R); */ 786 975 blob_reset(&b); 787 976 } 788 977 } 789 978 790 979 /* 791 980 ** COMMAND: test-udiff 792 981 */ 793 982 void test_udiff_cmd(void){ 794 983 Blob a, b, out; 795 - if( g.argc!=4 ) usage("FILE1 FILE2"); 984 + int diffFlag = find_option("sbs",0,0)!=0 ? DIFF_SIDEBYSIDE : 0; 985 + int nContext = 5; 986 + const char *z; 987 + if( (z = find_option("context","c",1))!=0 && atoi(z)>0 ){ 988 + nContext = atoi(z); 989 + } 990 + if( nContext<=0 ) nContext = 5; 991 + if( (nContext&DIFF_CONTEXT_MASK)!=nContext ) nContext = DIFF_CONTEXT_MASK; 992 + if( g.argc!=4 ) usage("[--sbs] [--context N] FILE1 FILE2"); 796 993 blob_read_from_file(&a, g.argv[2]); 797 994 blob_read_from_file(&b, g.argv[3]); 798 995 blob_zero(&out); 799 - text_diff(&a, &b, &out, 3, 0); 996 + text_diff(&a, &b, &out, nContext | diffFlag); 800 997 blob_write_to_file(&out, "-"); 801 998 } 802 999 803 1000 /************************************************************************** 804 1001 ** The basic difference engine is above. What follows is the annotation 805 1002 ** engine. Both are in the same file since they share many components. 806 1003 */
Changes to src/diffcmd.c.
17 17 ** 18 18 ** This file contains code used to implement the "diff" command 19 19 */ 20 20 #include "config.h" 21 21 #include "diffcmd.h" 22 22 #include <assert.h> 23 23 24 -/* 25 -** Diff option flags 26 -*/ 27 -#define DIFF_NEWFILE 0x01 /* Treat non-existing fails as empty files */ 28 -#define DIFF_NOEOLWS 0x02 /* Ignore whitespace at the end of lines */ 29 - 30 24 /* 31 25 ** Output the results of a diff. Output goes to stdout for command-line 32 26 ** or to the CGI/HTTP result buffer for web pages. 33 27 */ 34 28 static void diff_printf(const char *zFormat, ...){ 35 29 va_list ap; 36 30 va_start(ap, zFormat); ................................................................................ 60 54 ** command zDiffCmd to do the diffing. 61 55 */ 62 56 void diff_file( 63 57 Blob *pFile1, /* In memory content to compare from */ 64 58 const char *zFile2, /* On disk content to compare to */ 65 59 const char *zName, /* Display name of the file */ 66 60 const char *zDiffCmd, /* Command for comparison */ 67 - int ignoreEolWs /* Ignore whitespace at end of line */ 61 + int diffFlags /* Flags to control the diff */ 68 62 ){ 69 63 if( zDiffCmd==0 ){ 70 64 Blob out; /* Diff output text */ 71 65 Blob file2; /* Content of zFile2 */ 72 66 const char *zName2; /* Name of zFile2 for display */ 73 67 74 68 /* Read content of zFile2 into memory */ ................................................................................ 82 76 blob_read_from_file(&file2, zFile2); 83 77 } 84 78 zName2 = zName; 85 79 } 86 80 87 81 /* Compute and output the differences */ 88 82 blob_zero(&out); 89 - text_diff(pFile1, &file2, &out, 5, ignoreEolWs); 83 + text_diff(pFile1, &file2, &out, diffFlags); 90 84 if( blob_size(&out) ){ 91 85 diff_printf("--- %s\n+++ %s\n", zName, zName2); 92 86 diff_printf("%s\n", blob_str(&out)); 93 87 } 94 88 95 89 /* Release memory resources */ 96 90 blob_reset(&file2); ................................................................................ 136 130 ** command zDiffCmd to do the diffing. 137 131 */ 138 132 void diff_file_mem( 139 133 Blob *pFile1, /* In memory content to compare from */ 140 134 Blob *pFile2, /* In memory content to compare to */ 141 135 const char *zName, /* Display name of the file */ 142 136 const char *zDiffCmd, /* Command for comparison */ 143 - int ignoreEolWs /* Ignore whitespace at end of lines */ 137 + int diffFlags /* Diff flags */ 144 138 ){ 145 139 if( zDiffCmd==0 ){ 146 140 Blob out; /* Diff output text */ 147 141 148 142 blob_zero(&out); 149 - text_diff(pFile1, pFile2, &out, 5, ignoreEolWs); 143 + text_diff(pFile1, pFile2, &out, diffFlags); 150 144 diff_printf("--- %s\n+++ %s\n", zName, zName); 151 145 diff_printf("%s\n", blob_str(&out)); 152 146 153 147 /* Release memory resources */ 154 148 blob_reset(&out); 155 149 }else{ 156 150 Blob cmd; ................................................................................ 183 177 /* 184 178 ** Do a diff against a single file named in zFileTreeName from version zFrom 185 179 ** against the same file on disk. 186 180 */ 187 181 static void diff_one_against_disk( 188 182 const char *zFrom, /* Name of file */ 189 183 const char *zDiffCmd, /* Use this "diff" command */ 190 - int ignoreEolWs, /* Ignore whitespace changes at end of lines */ 184 + int diffFlags, /* Diff control flags */ 191 185 const char *zFileTreeName 192 186 ){ 193 187 Blob fname; 194 188 Blob content; 195 189 int isLink; 196 190 file_tree_name(zFileTreeName, &fname, 1); 197 191 historical_version_of_file(zFrom, blob_str(&fname), &content, &isLink, 0, 0); 198 192 if( !isLink != !file_wd_islink(zFrom) ){ 199 193 diff_printf("cannot compute difference between symlink and regular file\n"); 200 194 }else{ 201 - diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, ignoreEolWs); 195 + diff_file(&content, zFileTreeName, zFileTreeName, zDiffCmd, diffFlags); 202 196 } 203 197 blob_reset(&content); 204 198 blob_reset(&fname); 205 199 } 206 200 207 201 /* 208 202 ** Run a diff between the version zFrom and files on disk. zFrom might ................................................................................ 213 207 const char *zFrom, /* Version to difference from */ 214 208 const char *zDiffCmd, /* Use this diff command. NULL for built-in */ 215 209 int diffFlags /* Flags controlling diff output */ 216 210 ){ 217 211 int vid; 218 212 Blob sql; 219 213 Stmt q; 220 - int ignoreEolWs; /* Ignore end-of-line whitespace */ 221 214 int asNewFile; /* Treat non-existant files as empty files */ 222 215 223 - ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0; 224 216 asNewFile = (diffFlags & DIFF_NEWFILE)!=0; 225 217 vid = db_lget_int("checkout", 0); 226 218 vfile_check_signature(vid, 1, 0); 227 219 blob_zero(&sql); 228 220 db_begin_transaction(); 229 221 if( zFrom ){ 230 222 int rid = name_to_typed_rid(zFrom, "ci"); ................................................................................ 298 290 } 299 291 if( srcid>0 ){ 300 292 content_get(srcid, &content); 301 293 }else{ 302 294 blob_zero(&content); 303 295 } 304 296 diff_print_index(zPathname); 305 - diff_file(&content, zFullName, zPathname, zDiffCmd, ignoreEolWs); 297 + diff_file(&content, zFullName, zPathname, zDiffCmd, diffFlags); 306 298 blob_reset(&content); 307 299 } 308 300 free(zToFree); 309 301 } 310 302 db_finalize(&q); 311 303 db_end_transaction(1); /* ROLLBACK */ 312 304 } ................................................................................ 315 307 ** Output the differences between two versions of a single file. 316 308 ** zFrom and zTo are the check-ins containing the two file versions. 317 309 */ 318 310 static void diff_one_two_versions( 319 311 const char *zFrom, 320 312 const char *zTo, 321 313 const char *zDiffCmd, 322 - int ignoreEolWs, 314 + int diffFlags, 323 315 const char *zFileTreeName 324 316 ){ 325 317 char *zName; 326 318 Blob fname; 327 319 Blob v1, v2; 328 320 int isLink1, isLink2; 329 321 file_tree_name(zFileTreeName, &fname, 1); ................................................................................ 330 322 zName = blob_str(&fname); 331 323 historical_version_of_file(zFrom, zName, &v1, &isLink1, 0, 0); 332 324 historical_version_of_file(zTo, zName, &v2, &isLink2, 0, 0); 333 325 if( isLink1 != isLink2 ){ 334 326 diff_printf("--- %s\n+++ %s\n", zName, zName); 335 327 diff_printf("cannot compute difference between symlink and regular file\n"); 336 328 }else{ 337 - diff_file_mem(&v1, &v2, zName, zDiffCmd, ignoreEolWs); 329 + diff_file_mem(&v1, &v2, zName, zDiffCmd, diffFlags); 338 330 } 339 331 blob_reset(&v1); 340 332 blob_reset(&v2); 341 333 blob_reset(&fname); 342 334 } 343 335 344 336 /* ................................................................................ 345 337 ** Show the difference between two files identified by ManifestFile 346 338 ** entries. 347 339 */ 348 340 static void diff_manifest_entry( 349 341 struct ManifestFile *pFrom, 350 342 struct ManifestFile *pTo, 351 343 const char *zDiffCmd, 352 - int ignoreEolWs 344 + int diffFlags 353 345 ){ 354 346 Blob f1, f2; 355 347 int rid; 356 348 const char *zName = pFrom ? pFrom->zName : pTo->zName; 357 349 diff_print_index(zName); 358 350 if( pFrom ){ 359 351 rid = uuid_to_rid(pFrom->zUuid, 0); ................................................................................ 363 355 } 364 356 if( pTo ){ 365 357 rid = uuid_to_rid(pTo->zUuid, 0); 366 358 content_get(rid, &f2); 367 359 }else{ 368 360 blob_zero(&f2); 369 361 } 370 - diff_file_mem(&f1, &f2, zName, zDiffCmd, ignoreEolWs); 362 + diff_file_mem(&f1, &f2, zName, zDiffCmd, diffFlags); 371 363 blob_reset(&f1); 372 364 blob_reset(&f2); 373 365 } 374 366 375 367 /* 376 368 ** Output the differences between two check-ins. 377 369 */ ................................................................................ 379 371 const char *zFrom, 380 372 const char *zTo, 381 373 const char *zDiffCmd, 382 374 int diffFlags 383 375 ){ 384 376 Manifest *pFrom, *pTo; 385 377 ManifestFile *pFromFile, *pToFile; 386 - int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0; 387 378 int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0; 388 379 389 380 pFrom = manifest_get_by_name(zFrom, 0); 390 381 manifest_file_rewind(pFrom); 391 382 pFromFile = manifest_file_next(pFrom,0); 392 383 pTo = manifest_get_by_name(zTo, 0); 393 384 manifest_file_rewind(pTo); ................................................................................ 401 392 cmp = -1; 402 393 }else{ 403 394 cmp = fossil_strcmp(pFromFile->zName, pToFile->zName); 404 395 } 405 396 if( cmp<0 ){ 406 397 diff_printf("DELETED %s\n", pFromFile->zName); 407 398 if( asNewFlag ){ 408 - diff_manifest_entry(pFromFile, 0, zDiffCmd, ignoreEolWs); 399 + diff_manifest_entry(pFromFile, 0, zDiffCmd, diffFlags); 409 400 } 410 401 pFromFile = manifest_file_next(pFrom,0); 411 402 }else if( cmp>0 ){ 412 403 diff_printf("ADDED %s\n", pToFile->zName); 413 404 if( asNewFlag ){ 414 - diff_manifest_entry(0, pToFile, zDiffCmd, ignoreEolWs); 405 + diff_manifest_entry(0, pToFile, zDiffCmd, diffFlags); 415 406 } 416 407 pToFile = manifest_file_next(pTo,0); 417 408 }else if( fossil_strcmp(pFromFile->zUuid, pToFile->zUuid)==0 ){ 418 409 /* No changes */ 419 410 pFromFile = manifest_file_next(pFrom,0); 420 411 pToFile = manifest_file_next(pTo,0); 421 412 }else{ 422 413 /* diff_printf("CHANGED %s\n", pFromFile->zName); */ 423 - diff_manifest_entry(pFromFile, pToFile, zDiffCmd, ignoreEolWs); 414 + diff_manifest_entry(pFromFile, pToFile, zDiffCmd, diffFlags); 424 415 pFromFile = manifest_file_next(pFrom,0); 425 416 pToFile = manifest_file_next(pTo,0); 426 417 } 427 418 } 428 419 manifest_destroy(pFrom); 429 420 manifest_destroy(pTo); 430 421 } ................................................................................ 454 445 ** the "setting" command. If no external diff program is configured, then 455 446 ** the "-i" option is a no-op. The "-i" option converts "gdiff" into "diff". 456 447 ** 457 448 ** The "-N" or "--new-file" option causes the complete text of added or 458 449 ** deleted files to be displayed. 459 450 ** 460 451 ** Options: 452 +** --context|-c N Use N lines of context 461 453 ** --from|-r VERSION select VERSION as source for the diff 462 454 ** --new-file|-N output complete text of added or deleted files 463 455 ** -i use internal diff logic 464 456 ** --to VERSION select VERSION as target for the diff 457 +** --side-by-side|-y side-by-side diff 458 +** --width|-W N Width of lines in side-by-side diff 465 459 */ 466 460 void diff_cmd(void){ 467 461 int isGDiff; /* True for gdiff. False for normal diff */ 468 462 int isInternDiff; /* True for internal diff */ 469 463 int hasNFlag; /* True if -N or --new-file flag is used */ 470 464 const char *zFrom; /* Source version number */ 471 465 const char *zTo; /* Target version number */ 472 466 const char *zDiffCmd = 0; /* External diff command. NULL for internal diff */ 473 467 int diffFlags = 0; /* Flags to control the DIFF */ 468 + const char *z; 474 469 int f; 475 470 476 471 isGDiff = g.argv[1][0]=='g'; 477 472 isInternDiff = find_option("internal","i",0)!=0; 478 473 zFrom = find_option("from", "r", 1); 479 474 zTo = find_option("to", 0, 1); 480 475 hasNFlag = find_option("new-file","N",0)!=0; 476 + if( find_option("side-by-side","y",0)!=0 ) diffFlags |= DIFF_SIDEBYSIDE; 477 + if( (z = find_option("context","c",1))!=0 && (f = atoi(z))>0 ){ 478 + if( f > DIFF_CONTEXT_MASK ) f = DIFF_CONTEXT_MASK; 479 + diffFlags |= f; 480 + } 481 + if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){ 482 + f *= DIFF_CONTEXT_MASK+1; 483 + if( f > DIFF_WIDTH_MASK ) f = DIFF_CONTEXT_MASK; 484 + diffFlags |= f; 485 + } 481 486 482 487 483 488 if( hasNFlag ) diffFlags |= DIFF_NEWFILE; 484 489 if( zTo==0 ){ 485 490 db_must_be_within_tree(); 486 491 verify_all_options(); 487 492 if( !isInternDiff ){
Changes to src/info.c.
268 268 if( zTo ){ 269 269 toid = uuid_to_rid(zTo, 0); 270 270 content_get(toid, &to); 271 271 }else{ 272 272 blob_zero(&to); 273 273 } 274 274 blob_zero(&out); 275 - text_diff(&from, &to, &out, 5, 1); 275 + text_diff(&from, &to, &out, DIFF_IGNORE_EOLWS | 5); 276 276 @ %h(blob_str(&out)) 277 277 blob_reset(&from); 278 278 blob_reset(&to); 279 279 blob_reset(&out); 280 280 } 281 281 282 282 ................................................................................ 1089 1089 }else{ 1090 1090 blob_zero(&diff); 1091 1091 pOut = &diff; 1092 1092 } 1093 1093 if( !sideBySide || isPatch ){ 1094 1094 content_get(v1, &c1); 1095 1095 content_get(v2, &c2); 1096 - text_diff(&c1, &c2, pOut, 4, 1); 1096 + text_diff(&c1, &c2, pOut, 4 | 0); 1097 1097 blob_reset(&c1); 1098 1098 blob_reset(&c2); 1099 1099 } 1100 1100 if( !isPatch ){ 1101 1101 style_header("Diff"); 1102 1102 style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", 1103 1103 g.zTop, P("v1"), P("v2"));
Changes to src/merge3.c.
169 169 ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is 170 170 ** an array of integer triples. Within each triple, the first integer 171 171 ** is the number of lines of text to copy directly from the pivot, 172 172 ** the second integer is the number of lines of text to omit from the 173 173 ** pivot, and the third integer is the number of lines of text that are 174 174 ** inserted. The edit array ends with a triple of 0,0,0. 175 175 */ 176 - aC1 = text_diff(pPivot, pV1, 0, 0, 0); 177 - aC2 = text_diff(pPivot, pV2, 0, 0, 0); 176 + aC1 = text_diff(pPivot, pV1, 0, 0); 177 + aC2 = text_diff(pPivot, pV2, 0, 0); 178 178 if( aC1==0 || aC2==0 ){ 179 179 free(aC1); 180 180 free(aC2); 181 181 return -1; 182 182 } 183 183 184 184 blob_rewind(pV1); /* Rewind inputs: Needed to reconstruct output */
Changes to src/wiki.c.
619 619 if( pW1==0 ) fossil_redirect_home(); 620 620 blob_init(&w1, pW1->zWiki, -1); 621 621 blob_zero(&w2); 622 622 if( rid2 && (pW2 = manifest_get(rid2, CFTYPE_WIKI))!=0 ){ 623 623 blob_init(&w2, pW2->zWiki, -1); 624 624 } 625 625 blob_zero(&d); 626 - text_diff(&w2, &w1, &d, 5, 1); 626 + text_diff(&w2, &w1, &d, 5 | DIFF_IGNORE_EOLWS); 627 627 @ <pre> 628 628 @ %h(blob_str(&d)) 629 629 @ </pre> 630 630 manifest_destroy(pW1); 631 631 manifest_destroy(pW2); 632 632 style_footer(); 633 633 }