Fossil SCM

Improve the "fossil merge-info --tk" GUI by adding a new menu to show two-way diffs between selected columns. This enhancement required other diff-related enhancements: (1) add the --label option to all diff commands. (2) Add the new "fossil fdiff" command.

drh 2025-02-19 21:47 trunk
Commit e54a4b5fa96df3313ce22ae22794034f926e604c3e821a3008c9cdb3f06bf80f
+52 -3
--- src/diff.c
+++ src/diff.c
@@ -108,10 +108,11 @@
108108
u32 nFile; /* Number of files diffed so far */
109109
const char *zDiffCmd; /* External diff command to use instead of builtin */
110110
const char *zBinGlob; /* GLOB pattern for binary files */
111111
ReCompiled *pRe; /* Show only changes matching this pattern */
112112
const char *zLeftHash; /* HASH-id of the left file */
113
+ const char *azLabel[2]; /* Optional labels for left and right files */
113114
};
114115
115116
#endif /* INTERFACE */
116117
117118
/*
@@ -3236,10 +3237,11 @@
32363237
** --dark Use dark mode for Tcl/Tk and HTML output
32373238
** --html Format for HTML DIFF_HTML
32383239
** -i|--internal Use built-in diff, not an external tool
32393240
** --invert Invert the diff DIFF_INVERT
32403241
** --json Output formatted as JSON
3242
+** --label NAME Column label. Can be repeated once.
32413243
** -n|--linenum Show line numbers DIFF_LINENO
32423244
** -N|--new-file Alias for --verbose
32433245
** --noopt Disable optimization DIFF_NOOPT
32443246
** --numstat Show change counts DIFF_NUMSTAT
32453247
** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
@@ -3308,10 +3310,14 @@
33083310
}
33093311
}
33103312
if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
33113313
pCfg->wColumn = f;
33123314
}
3315
+ pCfg->azLabel[0] = find_option("label",0,1);
3316
+ if( pCfg->azLabel[0] ){
3317
+ pCfg->azLabel[1] = find_option("label",0,1);
3318
+ }
33133319
if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
33143320
if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
33153321
if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
33163322
if( find_option("versions","h",0)!=0 ) diffFlags |= DIFF_SHOW_VERS;
33173323
if( find_option("dark",0,0)!=0 ) diffFlags |= DIFF_DARKMODE;
@@ -3353,13 +3359,10 @@
33533359
** computing differences between files that are under management.
33543360
**
33553361
** This command prints the differences between the two files FILE1 and FILE2.
33563362
** all of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
33573363
** See the "diff" command for a full list of command-line options.
3358
-**
3359
-** This command used to be called "test-diff". The older "test-diff" spelling
3360
-** still works, for compatibility.
33613364
*/
33623365
void xdiff_cmd(void){
33633366
Blob a, b, out;
33643367
const char *zRe; /* Regex filter for diff output */
33653368
DiffConfig DCfg;
@@ -3381,10 +3384,56 @@
33813384
blob_zero(&out);
33823385
diff_begin(&DCfg);
33833386
diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
33843387
blob_read_from_file(&a, g.argv[2], ExtFILE);
33853388
blob_read_from_file(&b, g.argv[3], ExtFILE);
3389
+ text_diff(&a, &b, &out, &DCfg);
3390
+ blob_write_to_file(&out, "-");
3391
+ diff_end(&DCfg, 0);
3392
+ re_free(DCfg.pRe);
3393
+}
3394
+
3395
+/*
3396
+** COMMAND: fdiff
3397
+**
3398
+** Usage: %fossil fdiff [options] HASH1 HASH2
3399
+**
3400
+** Compute a diff between two artifacts in a repository (either a repository
3401
+** identified by the "-R FILENAME" option, or the repository that contains
3402
+** the working directory).
3403
+**
3404
+** All of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
3405
+** See the "diff" command for a full list of command-line options.
3406
+*/
3407
+void fdiff_cmd(void){
3408
+ Blob a, b, out;
3409
+ const char *zRe; /* Regex filter for diff output */
3410
+ int rid;
3411
+ DiffConfig DCfg;
3412
+
3413
+ if( find_option("tk",0,0)!=0 ){
3414
+ diff_tk("fdiff", 2);
3415
+ return;
3416
+ }
3417
+ find_option("i",0,0);
3418
+ find_option("v",0,0);
3419
+ diff_options(&DCfg, 0, 0);
3420
+ zRe = find_option("regexp","e",1);
3421
+ if( zRe ){
3422
+ const char *zErr = re_compile(&DCfg.pRe, zRe, 0);
3423
+ if( zErr ) fossil_fatal("regex error: %s", zErr);
3424
+ }
3425
+ db_find_and_open_repository(0, 0);
3426
+ verify_all_options();
3427
+ if( g.argc!=4 ) usage("HASH1 HASH2");
3428
+ blob_zero(&out);
3429
+ diff_begin(&DCfg);
3430
+ diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
3431
+ rid = name_to_typed_rid(g.argv[2], 0);
3432
+ content_get(rid, &a);
3433
+ rid = name_to_typed_rid(g.argv[3], 0);
3434
+ content_get(rid, &b);
33863435
text_diff(&a, &b, &out, &DCfg);
33873436
blob_write_to_file(&out, "-");
33883437
diff_end(&DCfg, 0);
33893438
re_free(DCfg.pRe);
33903439
}
33913440
--- src/diff.c
+++ src/diff.c
@@ -108,10 +108,11 @@
108 u32 nFile; /* Number of files diffed so far */
109 const char *zDiffCmd; /* External diff command to use instead of builtin */
110 const char *zBinGlob; /* GLOB pattern for binary files */
111 ReCompiled *pRe; /* Show only changes matching this pattern */
112 const char *zLeftHash; /* HASH-id of the left file */
 
113 };
114
115 #endif /* INTERFACE */
116
117 /*
@@ -3236,10 +3237,11 @@
3236 ** --dark Use dark mode for Tcl/Tk and HTML output
3237 ** --html Format for HTML DIFF_HTML
3238 ** -i|--internal Use built-in diff, not an external tool
3239 ** --invert Invert the diff DIFF_INVERT
3240 ** --json Output formatted as JSON
 
3241 ** -n|--linenum Show line numbers DIFF_LINENO
3242 ** -N|--new-file Alias for --verbose
3243 ** --noopt Disable optimization DIFF_NOOPT
3244 ** --numstat Show change counts DIFF_NUMSTAT
3245 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
@@ -3308,10 +3310,14 @@
3308 }
3309 }
3310 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
3311 pCfg->wColumn = f;
3312 }
 
 
 
 
3313 if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
3314 if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
3315 if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
3316 if( find_option("versions","h",0)!=0 ) diffFlags |= DIFF_SHOW_VERS;
3317 if( find_option("dark",0,0)!=0 ) diffFlags |= DIFF_DARKMODE;
@@ -3353,13 +3359,10 @@
3353 ** computing differences between files that are under management.
3354 **
3355 ** This command prints the differences between the two files FILE1 and FILE2.
3356 ** all of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
3357 ** See the "diff" command for a full list of command-line options.
3358 **
3359 ** This command used to be called "test-diff". The older "test-diff" spelling
3360 ** still works, for compatibility.
3361 */
3362 void xdiff_cmd(void){
3363 Blob a, b, out;
3364 const char *zRe; /* Regex filter for diff output */
3365 DiffConfig DCfg;
@@ -3381,10 +3384,56 @@
3381 blob_zero(&out);
3382 diff_begin(&DCfg);
3383 diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
3384 blob_read_from_file(&a, g.argv[2], ExtFILE);
3385 blob_read_from_file(&b, g.argv[3], ExtFILE);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3386 text_diff(&a, &b, &out, &DCfg);
3387 blob_write_to_file(&out, "-");
3388 diff_end(&DCfg, 0);
3389 re_free(DCfg.pRe);
3390 }
3391
--- src/diff.c
+++ src/diff.c
@@ -108,10 +108,11 @@
108 u32 nFile; /* Number of files diffed so far */
109 const char *zDiffCmd; /* External diff command to use instead of builtin */
110 const char *zBinGlob; /* GLOB pattern for binary files */
111 ReCompiled *pRe; /* Show only changes matching this pattern */
112 const char *zLeftHash; /* HASH-id of the left file */
113 const char *azLabel[2]; /* Optional labels for left and right files */
114 };
115
116 #endif /* INTERFACE */
117
118 /*
@@ -3236,10 +3237,11 @@
3237 ** --dark Use dark mode for Tcl/Tk and HTML output
3238 ** --html Format for HTML DIFF_HTML
3239 ** -i|--internal Use built-in diff, not an external tool
3240 ** --invert Invert the diff DIFF_INVERT
3241 ** --json Output formatted as JSON
3242 ** --label NAME Column label. Can be repeated once.
3243 ** -n|--linenum Show line numbers DIFF_LINENO
3244 ** -N|--new-file Alias for --verbose
3245 ** --noopt Disable optimization DIFF_NOOPT
3246 ** --numstat Show change counts DIFF_NUMSTAT
3247 ** --strip-trailing-cr Strip trailing CR DIFF_STRIP_EOLCR
@@ -3308,10 +3310,14 @@
3310 }
3311 }
3312 if( (z = find_option("width","W",1))!=0 && (f = atoi(z))>0 ){
3313 pCfg->wColumn = f;
3314 }
3315 pCfg->azLabel[0] = find_option("label",0,1);
3316 if( pCfg->azLabel[0] ){
3317 pCfg->azLabel[1] = find_option("label",0,1);
3318 }
3319 if( find_option("linenum","n",0)!=0 ) diffFlags |= DIFF_LINENO;
3320 if( find_option("noopt",0,0)!=0 ) diffFlags |= DIFF_NOOPT;
3321 if( find_option("numstat",0,0)!=0 ) diffFlags |= DIFF_NUMSTAT;
3322 if( find_option("versions","h",0)!=0 ) diffFlags |= DIFF_SHOW_VERS;
3323 if( find_option("dark",0,0)!=0 ) diffFlags |= DIFF_DARKMODE;
@@ -3353,13 +3359,10 @@
3359 ** computing differences between files that are under management.
3360 **
3361 ** This command prints the differences between the two files FILE1 and FILE2.
3362 ** all of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
3363 ** See the "diff" command for a full list of command-line options.
 
 
 
3364 */
3365 void xdiff_cmd(void){
3366 Blob a, b, out;
3367 const char *zRe; /* Regex filter for diff output */
3368 DiffConfig DCfg;
@@ -3381,10 +3384,56 @@
3384 blob_zero(&out);
3385 diff_begin(&DCfg);
3386 diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
3387 blob_read_from_file(&a, g.argv[2], ExtFILE);
3388 blob_read_from_file(&b, g.argv[3], ExtFILE);
3389 text_diff(&a, &b, &out, &DCfg);
3390 blob_write_to_file(&out, "-");
3391 diff_end(&DCfg, 0);
3392 re_free(DCfg.pRe);
3393 }
3394
3395 /*
3396 ** COMMAND: fdiff
3397 **
3398 ** Usage: %fossil fdiff [options] HASH1 HASH2
3399 **
3400 ** Compute a diff between two artifacts in a repository (either a repository
3401 ** identified by the "-R FILENAME" option, or the repository that contains
3402 ** the working directory).
3403 **
3404 ** All of the usual diff formatting options (--tk, --by, -c N, etc.) apply.
3405 ** See the "diff" command for a full list of command-line options.
3406 */
3407 void fdiff_cmd(void){
3408 Blob a, b, out;
3409 const char *zRe; /* Regex filter for diff output */
3410 int rid;
3411 DiffConfig DCfg;
3412
3413 if( find_option("tk",0,0)!=0 ){
3414 diff_tk("fdiff", 2);
3415 return;
3416 }
3417 find_option("i",0,0);
3418 find_option("v",0,0);
3419 diff_options(&DCfg, 0, 0);
3420 zRe = find_option("regexp","e",1);
3421 if( zRe ){
3422 const char *zErr = re_compile(&DCfg.pRe, zRe, 0);
3423 if( zErr ) fossil_fatal("regex error: %s", zErr);
3424 }
3425 db_find_and_open_repository(0, 0);
3426 verify_all_options();
3427 if( g.argc!=4 ) usage("HASH1 HASH2");
3428 blob_zero(&out);
3429 diff_begin(&DCfg);
3430 diff_print_filenames(g.argv[2], g.argv[3], &DCfg, &out);
3431 rid = name_to_typed_rid(g.argv[2], 0);
3432 content_get(rid, &a);
3433 rid = name_to_typed_rid(g.argv[3], 0);
3434 content_get(rid, &b);
3435 text_diff(&a, &b, &out, &DCfg);
3436 blob_write_to_file(&out, "-");
3437 diff_end(&DCfg, 0);
3438 re_free(DCfg.pRe);
3439 }
3440
+32 -12
--- src/diff.tcl
+++ src/diff.tcl
@@ -110,34 +110,54 @@
110110
111111
set fromIndex [lsearch -glob $fossilcmd *-from]
112112
set toIndex [lsearch -glob $fossilcmd *-to]
113113
set branchIndex [lsearch -glob $fossilcmd *-branch]
114114
set checkinIndex [lsearch -glob $fossilcmd *-checkin]
115
- if {[string match *?--external-baseline* $fossilcmd]} {
116
- set fA {external baseline}
115
+ if {[lsearch -glob $fossilcmd *-label]>=0} {
116
+ set fA {}
117
+ set fB {}
117118
} else {
118
- set fA {base check-in}
119
- }
120
- set fB {current check-out}
121
- if {$fromIndex > -1} {set fA [lindex $fossilcmd $fromIndex+1]}
122
- if {$toIndex > -1} {set fB [lindex $fossilcmd $toIndex+1]}
123
- if {$branchIndex > -1} {set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"}
124
- if {$checkinIndex > -1} {set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]}
125
-
119
+ if {[string match *?--external-baseline* $fossilcmd]} {
120
+ set fA {external baseline}
121
+ } else {
122
+ set fA {base check-in}
123
+ }
124
+ set fB {current check-out}
125
+ if {$fromIndex > -1} {
126
+ set fA [lindex $fossilcmd $fromIndex+1]
127
+ }
128
+ if {$toIndex > -1} {
129
+ set fB [lindex $fossilcmd $toIndex+1]
130
+ }
131
+ if {$branchIndex > -1} {
132
+ set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"
133
+ }
134
+ if {$checkinIndex > -1} {
135
+ set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]
136
+ }
137
+ }
126138
127139
while {[set line [getLine $difftxt $N ii]] != -1} {
128140
switch -- [lindex $line 0] {
129141
FILE {
130142
incr nDiffs
131143
foreach wx [list [string length $n1] [string length $n2]] {
132144
if {$wx>$widths(ln)} {set widths(ln) $wx}
133145
}
134146
.lnA insert end \n fn \n -
135
- .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
147
+ if {$fA==""} {
148
+ .txtA insert end "[lindex $line 1]\n" fn \n -
149
+ } else {
150
+ .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
151
+ }
136152
.mkr insert end \n fn \n -
137153
.lnB insert end \n fn \n -
138
- .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
154
+ if {$fB==""} {
155
+ .txtB insert end "[lindex $line 2]\n" fn \n -
156
+ } else {
157
+ .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
158
+ }
139159
.wfiles.lb insert end [lindex $line 2]
140160
set n1 0
141161
set n2 0
142162
}
143163
SKIP {
144164
--- src/diff.tcl
+++ src/diff.tcl
@@ -110,34 +110,54 @@
110
111 set fromIndex [lsearch -glob $fossilcmd *-from]
112 set toIndex [lsearch -glob $fossilcmd *-to]
113 set branchIndex [lsearch -glob $fossilcmd *-branch]
114 set checkinIndex [lsearch -glob $fossilcmd *-checkin]
115 if {[string match *?--external-baseline* $fossilcmd]} {
116 set fA {external baseline}
 
117 } else {
118 set fA {base check-in}
119 }
120 set fB {current check-out}
121 if {$fromIndex > -1} {set fA [lindex $fossilcmd $fromIndex+1]}
122 if {$toIndex > -1} {set fB [lindex $fossilcmd $toIndex+1]}
123 if {$branchIndex > -1} {set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"}
124 if {$checkinIndex > -1} {set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]}
125
 
 
 
 
 
 
 
 
 
 
 
126
127 while {[set line [getLine $difftxt $N ii]] != -1} {
128 switch -- [lindex $line 0] {
129 FILE {
130 incr nDiffs
131 foreach wx [list [string length $n1] [string length $n2]] {
132 if {$wx>$widths(ln)} {set widths(ln) $wx}
133 }
134 .lnA insert end \n fn \n -
135 .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
 
 
 
 
136 .mkr insert end \n fn \n -
137 .lnB insert end \n fn \n -
138 .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
 
 
 
 
139 .wfiles.lb insert end [lindex $line 2]
140 set n1 0
141 set n2 0
142 }
143 SKIP {
144
--- src/diff.tcl
+++ src/diff.tcl
@@ -110,34 +110,54 @@
110
111 set fromIndex [lsearch -glob $fossilcmd *-from]
112 set toIndex [lsearch -glob $fossilcmd *-to]
113 set branchIndex [lsearch -glob $fossilcmd *-branch]
114 set checkinIndex [lsearch -glob $fossilcmd *-checkin]
115 if {[lsearch -glob $fossilcmd *-label]>=0} {
116 set fA {}
117 set fB {}
118 } else {
119 if {[string match *?--external-baseline* $fossilcmd]} {
120 set fA {external baseline}
121 } else {
122 set fA {base check-in}
123 }
124 set fB {current check-out}
125 if {$fromIndex > -1} {
126 set fA [lindex $fossilcmd $fromIndex+1]
127 }
128 if {$toIndex > -1} {
129 set fB [lindex $fossilcmd $toIndex+1]
130 }
131 if {$branchIndex > -1} {
132 set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"
133 }
134 if {$checkinIndex > -1} {
135 set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]
136 }
137 }
138
139 while {[set line [getLine $difftxt $N ii]] != -1} {
140 switch -- [lindex $line 0] {
141 FILE {
142 incr nDiffs
143 foreach wx [list [string length $n1] [string length $n2]] {
144 if {$wx>$widths(ln)} {set widths(ln) $wx}
145 }
146 .lnA insert end \n fn \n -
147 if {$fA==""} {
148 .txtA insert end "[lindex $line 1]\n" fn \n -
149 } else {
150 .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
151 }
152 .mkr insert end \n fn \n -
153 .lnB insert end \n fn \n -
154 if {$fB==""} {
155 .txtB insert end "[lindex $line 2]\n" fn \n -
156 } else {
157 .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
158 }
159 .wfiles.lb insert end [lindex $line 2]
160 set n1 0
161 set n2 0
162 }
163 SKIP {
164
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -164,10 +164,12 @@
164164
){
165165
u64 diffFlags = pCfg->diffFlags;
166166
/* Standardize on /dev/null, regardless of platform. */
167167
if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null";
168168
if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null";
169
+ if( pCfg->azLabel[0] ) zLeft = pCfg->azLabel[0];
170
+ if( pCfg->azLabel[1] ) zRight = pCfg->azLabel[1];
169171
if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
170172
/* no-op */
171173
}else if( diffFlags & DIFF_DEBUG ){
172174
blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight);
173175
}else if( diffFlags & DIFF_WEBPAGE ){
174176
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -164,10 +164,12 @@
164 ){
165 u64 diffFlags = pCfg->diffFlags;
166 /* Standardize on /dev/null, regardless of platform. */
167 if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null";
168 if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null";
 
 
169 if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
170 /* no-op */
171 }else if( diffFlags & DIFF_DEBUG ){
172 blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight);
173 }else if( diffFlags & DIFF_WEBPAGE ){
174
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -164,10 +164,12 @@
164 ){
165 u64 diffFlags = pCfg->diffFlags;
166 /* Standardize on /dev/null, regardless of platform. */
167 if( pCfg->diffFlags & DIFF_FILE_ADDED ) zLeft = "/dev/null";
168 if( pCfg->diffFlags & DIFF_FILE_DELETED ) zRight = "/dev/null";
169 if( pCfg->azLabel[0] ) zLeft = pCfg->azLabel[0];
170 if( pCfg->azLabel[1] ) zRight = pCfg->azLabel[1];
171 if( diffFlags & (DIFF_BRIEF|DIFF_RAW) ){
172 /* no-op */
173 }else if( diffFlags & DIFF_DEBUG ){
174 blob_appendf(pOut, "FILE-LEFT %s\nFILE-RIGHT %s\n", zLeft, zRight);
175 }else if( diffFlags & DIFF_WEBPAGE ){
176
+70 -4
--- src/merge.c
+++ src/merge.c
@@ -44,10 +44,11 @@
4444
bDebug = find_option("debug",0,0)!=0;
4545
verify_all_options();
4646
4747
blob_zero(&script);
4848
blob_appendf(&script, "set ncontext %d\n", nContext);
49
+ blob_appendf(&script, "set fossilexe {\"%/\"}\n", g.nameOfExe);
4950
blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n",
5051
g.nameOfExe);
5152
blob_appendf(&script, "set filelist [list");
5253
if( g.argc==2 ){
5354
/* No files named on the command-line. Use every file mentioned
@@ -241,10 +242,55 @@
241242
blob_reset(&v1);
242243
blob_reset(&v2);
243244
blob_reset(&out);
244245
db_finalize(&q);
245246
}
247
+
248
+/*
249
+** Respond to one of the options --diff12, --diff13, or --diff23.
250
+**
251
+** The diffMode is one of 12, 13, or 23 according to which option provoked
252
+** this routine. zFile is the name of the file on which to run the
253
+** two-way diff.
254
+**
255
+** This routine constructs a sub-command that runs "fossil diff" to show
256
+** the appropriate two-way diff.
257
+*/
258
+static void merge_two_way_file_diff(
259
+ int diffMode,
260
+ const char *zDiff2,
261
+ int nContext,
262
+ int bDark
263
+){
264
+ int ridLeft; /* RID for the left file */
265
+ int ridRight; /* RID for the right file */
266
+ char *zLeft;
267
+ char *zRight;
268
+ char *zCmd;
269
+
270
+ ridLeft = db_int(0,
271
+ "SELECT iif(%d,ridp,ridv) FROM mergestat"
272
+ " WHERE coalesce(fnr,fn)=%Q",
273
+ diffMode<20, zDiff2
274
+ );
275
+ ridRight = db_int(0,
276
+ "SELECT iif(%d,ridv,ridm) FROM mergestat"
277
+ " WHERE coalesce(fnr,fn)=%Q",
278
+ (diffMode%10)==2, zDiff2
279
+ );
280
+ zLeft = mprintf("%s (%s)", zDiff2, diffMode<20 ? "baseline" : "local");
281
+ zRight = mprintf("%s (%s)", zDiff2,
282
+ (diffMode%10)==2 ? "local" : "merge-in");
283
+ zCmd = mprintf(
284
+ "%!$ fdiff --tk --label %!$ --label %!$ -c %d%s rid:%d rid:%d &",
285
+ g.nameOfExe, zLeft, zRight, nContext,
286
+ bDark ? " -dark" : "",
287
+ ridLeft, ridRight);
288
+ fossil_system(zCmd);
289
+ return;
290
+}
291
+
246292
247293
/*
248294
** COMMAND: merge-info
249295
**
250296
** Usage: %fossil merge-info [OPTIONS]
@@ -257,21 +303,26 @@
257303
** lines are shown
258304
** -c|--context N Show N lines of context around each change,
259305
** with negative N meaning show all content. Only
260306
** meaningful in combination with --tcl or --tk.
261307
** --dark Use dark mode for the Tcl/Tk-based GUI
308
+** --tk Bring up a Tcl/Tk GUI that shows the changes
309
+** associated with the most recent merge.
310
+**
311
+** Options used internally by --tk:
312
+** --diff12 FILE Bring up a separate --tk diff for just the baseline
313
+** and local variants of FILE.
314
+** --diff13 FILE Like --diff12 but for baseline versus merge-in
315
+** --diff23 FILE Like --diff12 but for local versus merge-in
262316
** --tcl FILE Generate (to stdout) a TCL list containing
263317
** information needed to display the changes to
264318
** FILE caused by the most recent merge. FILE must
265319
** be a pathname relative to the root of the check-out.
266
-** --tk Bring up a Tcl/Tk GUI that shows the changes
267
-** associated with the most recent merge.
268320
**
269
-** Additional debugging options available only when --tk is used:
321
+** Debugging options available only when --tk is used:
270322
** --debug Show sub-commands run to implement --tk
271323
** --script FILE Write script used to implement --tk into FILE
272
-
273324
*/
274325
void merge_info_cmd(void){
275326
const char *zCnt;
276327
const char *zTcl;
277328
int bTk;
@@ -279,17 +330,28 @@
279330
int bAll;
280331
int nContext;
281332
Stmt q;
282333
const char *zWhere;
283334
int cnt = 0;
335
+ const char *zDiff2 = 0;
336
+ int diffMode = 0;
284337
285338
db_must_be_within_tree();
286339
zTcl = find_option("tcl", 0, 1);
287340
bTk = find_option("tk", 0, 0)!=0;
288341
zCnt = find_option("context", "c", 1);
289342
bDark = find_option("dark", 0, 0)!=0;
290343
bAll = find_option("all", "a", 0)!=0;
344
+ if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
345
+ diffMode = 12;
346
+ }else
347
+ if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
348
+ diffMode = 13;
349
+ }else
350
+ if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
351
+ diffMode = 23;
352
+ }
291353
if( bTk==0 ){
292354
verify_all_options();
293355
if( g.argc>2 ){
294356
usage("[OPTIONS]");
295357
}
@@ -313,10 +375,14 @@
313375
return;
314376
}
315377
if( zTcl ){
316378
merge_info_tcl(zTcl, nContext);
317379
return;
380
+ }
381
+ if( diffMode ){
382
+ merge_two_way_file_diff(diffMode, zDiff2, nContext, bDark);
383
+ return;
318384
}
319385
if( bAll ){
320386
zWhere = "";
321387
}else{
322388
zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
323389
--- src/merge.c
+++ src/merge.c
@@ -44,10 +44,11 @@
44 bDebug = find_option("debug",0,0)!=0;
45 verify_all_options();
46
47 blob_zero(&script);
48 blob_appendf(&script, "set ncontext %d\n", nContext);
 
49 blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n",
50 g.nameOfExe);
51 blob_appendf(&script, "set filelist [list");
52 if( g.argc==2 ){
53 /* No files named on the command-line. Use every file mentioned
@@ -241,10 +242,55 @@
241 blob_reset(&v1);
242 blob_reset(&v2);
243 blob_reset(&out);
244 db_finalize(&q);
245 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
247 /*
248 ** COMMAND: merge-info
249 **
250 ** Usage: %fossil merge-info [OPTIONS]
@@ -257,21 +303,26 @@
257 ** lines are shown
258 ** -c|--context N Show N lines of context around each change,
259 ** with negative N meaning show all content. Only
260 ** meaningful in combination with --tcl or --tk.
261 ** --dark Use dark mode for the Tcl/Tk-based GUI
 
 
 
 
 
 
 
 
262 ** --tcl FILE Generate (to stdout) a TCL list containing
263 ** information needed to display the changes to
264 ** FILE caused by the most recent merge. FILE must
265 ** be a pathname relative to the root of the check-out.
266 ** --tk Bring up a Tcl/Tk GUI that shows the changes
267 ** associated with the most recent merge.
268 **
269 ** Additional debugging options available only when --tk is used:
270 ** --debug Show sub-commands run to implement --tk
271 ** --script FILE Write script used to implement --tk into FILE
272
273 */
274 void merge_info_cmd(void){
275 const char *zCnt;
276 const char *zTcl;
277 int bTk;
@@ -279,17 +330,28 @@
279 int bAll;
280 int nContext;
281 Stmt q;
282 const char *zWhere;
283 int cnt = 0;
 
 
284
285 db_must_be_within_tree();
286 zTcl = find_option("tcl", 0, 1);
287 bTk = find_option("tk", 0, 0)!=0;
288 zCnt = find_option("context", "c", 1);
289 bDark = find_option("dark", 0, 0)!=0;
290 bAll = find_option("all", "a", 0)!=0;
 
 
 
 
 
 
 
 
 
291 if( bTk==0 ){
292 verify_all_options();
293 if( g.argc>2 ){
294 usage("[OPTIONS]");
295 }
@@ -313,10 +375,14 @@
313 return;
314 }
315 if( zTcl ){
316 merge_info_tcl(zTcl, nContext);
317 return;
 
 
 
 
318 }
319 if( bAll ){
320 zWhere = "";
321 }else{
322 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
323
--- src/merge.c
+++ src/merge.c
@@ -44,10 +44,11 @@
44 bDebug = find_option("debug",0,0)!=0;
45 verify_all_options();
46
47 blob_zero(&script);
48 blob_appendf(&script, "set ncontext %d\n", nContext);
49 blob_appendf(&script, "set fossilexe {\"%/\"}\n", g.nameOfExe);
50 blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n",
51 g.nameOfExe);
52 blob_appendf(&script, "set filelist [list");
53 if( g.argc==2 ){
54 /* No files named on the command-line. Use every file mentioned
@@ -241,10 +242,55 @@
242 blob_reset(&v1);
243 blob_reset(&v2);
244 blob_reset(&out);
245 db_finalize(&q);
246 }
247
248 /*
249 ** Respond to one of the options --diff12, --diff13, or --diff23.
250 **
251 ** The diffMode is one of 12, 13, or 23 according to which option provoked
252 ** this routine. zFile is the name of the file on which to run the
253 ** two-way diff.
254 **
255 ** This routine constructs a sub-command that runs "fossil diff" to show
256 ** the appropriate two-way diff.
257 */
258 static void merge_two_way_file_diff(
259 int diffMode,
260 const char *zDiff2,
261 int nContext,
262 int bDark
263 ){
264 int ridLeft; /* RID for the left file */
265 int ridRight; /* RID for the right file */
266 char *zLeft;
267 char *zRight;
268 char *zCmd;
269
270 ridLeft = db_int(0,
271 "SELECT iif(%d,ridp,ridv) FROM mergestat"
272 " WHERE coalesce(fnr,fn)=%Q",
273 diffMode<20, zDiff2
274 );
275 ridRight = db_int(0,
276 "SELECT iif(%d,ridv,ridm) FROM mergestat"
277 " WHERE coalesce(fnr,fn)=%Q",
278 (diffMode%10)==2, zDiff2
279 );
280 zLeft = mprintf("%s (%s)", zDiff2, diffMode<20 ? "baseline" : "local");
281 zRight = mprintf("%s (%s)", zDiff2,
282 (diffMode%10)==2 ? "local" : "merge-in");
283 zCmd = mprintf(
284 "%!$ fdiff --tk --label %!$ --label %!$ -c %d%s rid:%d rid:%d &",
285 g.nameOfExe, zLeft, zRight, nContext,
286 bDark ? " -dark" : "",
287 ridLeft, ridRight);
288 fossil_system(zCmd);
289 return;
290 }
291
292
293 /*
294 ** COMMAND: merge-info
295 **
296 ** Usage: %fossil merge-info [OPTIONS]
@@ -257,21 +303,26 @@
303 ** lines are shown
304 ** -c|--context N Show N lines of context around each change,
305 ** with negative N meaning show all content. Only
306 ** meaningful in combination with --tcl or --tk.
307 ** --dark Use dark mode for the Tcl/Tk-based GUI
308 ** --tk Bring up a Tcl/Tk GUI that shows the changes
309 ** associated with the most recent merge.
310 **
311 ** Options used internally by --tk:
312 ** --diff12 FILE Bring up a separate --tk diff for just the baseline
313 ** and local variants of FILE.
314 ** --diff13 FILE Like --diff12 but for baseline versus merge-in
315 ** --diff23 FILE Like --diff12 but for local versus merge-in
316 ** --tcl FILE Generate (to stdout) a TCL list containing
317 ** information needed to display the changes to
318 ** FILE caused by the most recent merge. FILE must
319 ** be a pathname relative to the root of the check-out.
 
 
320 **
321 ** Debugging options available only when --tk is used:
322 ** --debug Show sub-commands run to implement --tk
323 ** --script FILE Write script used to implement --tk into FILE
 
324 */
325 void merge_info_cmd(void){
326 const char *zCnt;
327 const char *zTcl;
328 int bTk;
@@ -279,17 +330,28 @@
330 int bAll;
331 int nContext;
332 Stmt q;
333 const char *zWhere;
334 int cnt = 0;
335 const char *zDiff2 = 0;
336 int diffMode = 0;
337
338 db_must_be_within_tree();
339 zTcl = find_option("tcl", 0, 1);
340 bTk = find_option("tk", 0, 0)!=0;
341 zCnt = find_option("context", "c", 1);
342 bDark = find_option("dark", 0, 0)!=0;
343 bAll = find_option("all", "a", 0)!=0;
344 if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
345 diffMode = 12;
346 }else
347 if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
348 diffMode = 13;
349 }else
350 if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
351 diffMode = 23;
352 }
353 if( bTk==0 ){
354 verify_all_options();
355 if( g.argc>2 ){
356 usage("[OPTIONS]");
357 }
@@ -313,10 +375,14 @@
375 return;
376 }
377 if( zTcl ){
378 merge_info_tcl(zTcl, nContext);
379 return;
380 }
381 if( diffMode ){
382 merge_two_way_file_diff(diffMode, zDiff2, nContext, bDark);
383 return;
384 }
385 if( bAll ){
386 zWhere = "";
387 }else{
388 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
389
+43 -11
--- src/merge.tcl
+++ src/merge.tcl
@@ -1,23 +1,27 @@
11
# Show details of a 3-way merge operation. The left-most column is the
22
# common ancestor. The next two columns are edits of that common ancestor.
33
# The right-most column is the result of the merge.
44
#
5
-# There is always a "fossilcmd" variable which tells the script how to
6
-# invoke Fossil to get the information it needs. This script will
7
-# automatically append "-c N" to tell Fossil how much context it wants.
5
+# Several variables will have been initialized:
6
+#
7
+# ncontext The number of lines of context to show on each change
8
+#
9
+# fossilexe Pathname of the fossil program
10
+#
11
+# filelist A list of "merge-type filename" pairs.
12
+#
13
+# darkmode Boolean. True for dark mode
14
+#
15
+# debug Boolean. True for debugging output
816
#
917
# If the "filelist" global variable is defined, then it is a list of
1018
# alternating "merge-type names" (ex: UPDATE, MERGE, CONFLICT, ERROR) and
1119
# filenames. In that case, the initial display shows the changes for
1220
# the first pair on the list and there is a optionmenu that allows the
1321
# user to select other fiels on the list.
1422
#
15
-# There should also be a global variable named "ncontext" which is the
16
-# number of lines of context to display. The value of this variable
17
-# controls the "-c N" argument that is appended to fossilcmd.
18
-#
1923
# This header comment is stripped off by the "mkbuiltin.c" program.
2024
#
2125
package require Tk
2226
2327
array set CFG_light {
@@ -93,19 +97,19 @@
9397
regexp {[a-z]+} $c type
9498
return $type
9599
}
96100
97101
proc readMerge {args} {
98
- global fossilcmd ncontext current_file debug
102
+ global fossilexe ncontext current_file debug
99103
if {$ncontext=="All"} {
100
- set cmd "$fossilcmd -c -1"
104
+ set cmd "| $fossilexe merge-info -c -1"
101105
} else {
102
- set cmd "$fossilcmd -c $ncontext"
106
+ set cmd "| $fossilexe merge-info -c $ncontext"
103107
}
104108
if {[info exists current_file]} {
105109
regsub {^[A-Z]+ } $current_file {} fn
106
- append cmd " -tcl [list $fn]"
110
+ lappend cmd -tcl $fn
107111
}
108112
if {$debug} {
109113
regsub {^\| +} $cmd {} cmd2
110114
puts $cmd2
111115
flush stdout
@@ -342,10 +346,37 @@
342346
bind . <$key> "scroll-$axis $args; break"
343347
bind . <Shift-$key> continue
344348
}
345349
346350
frame .bb
351
+::ttk::menubutton .bb.diff2 -text {2-way diffs} -menu .bb.diff2.m
352
+menu .bb.diff2.m
353
+.bb.diff2.m add command -label {baseline vs. local} -command {two-way 12}
354
+.bb.diff2.m add command -label {baseline vs. merge-in} -command {two-way 13}
355
+.bb.diff2.m add command -label {local vs. merge-in} -command {two-way 23}
356
+
357
+# Bring up a separate two-way diff between a pair of columns
358
+# the argument is one of:
359
+# 12 Baseline versus Local
360
+# 13 Baseline versus Merge-in
361
+# 23 Local versus Merge-in
362
+#
363
+proc two-way {mode} {
364
+ global current_file fossilexe debug darkmode ncontext
365
+ regsub {^[A-Z]+ } $current_file {} fn
366
+ set cmd $fossilexe
367
+ lappend cmd merge-info --diff$mode $fn -c $ncontext
368
+ if {$darkmode} {
369
+ lappend cmd --dark
370
+ }
371
+ if {$debug} {
372
+ puts $cmd
373
+ flush stdout
374
+ }
375
+ exec {*}$cmd &
376
+}
377
+
347378
set useOptionMenu 1
348379
if {[info exists filelist]} {
349380
set current_file "[lindex $filelist 0] [lindex $filelist 1]"
350381
if {[llength $filelist]>2} {
351382
trace add variable current_file write readMerge
@@ -580,10 +611,11 @@
580611
set ::search $w
581612
}
582613
::ttk::button .bb.quit -text {Quit} -command exit
583614
::ttk::button .bb.search -text {Search} -command searchOnOff
584615
pack .bb.quit -side left
616
+pack .bb.diff2 -side left
585617
if {[winfo exists .bb.files]} {
586618
pack .bb.files -side left
587619
}
588620
pack .bb.ctxtag .bb.ctx -side left
589621
pack .bb.search -side left
590622
--- src/merge.tcl
+++ src/merge.tcl
@@ -1,23 +1,27 @@
1 # Show details of a 3-way merge operation. The left-most column is the
2 # common ancestor. The next two columns are edits of that common ancestor.
3 # The right-most column is the result of the merge.
4 #
5 # There is always a "fossilcmd" variable which tells the script how to
6 # invoke Fossil to get the information it needs. This script will
7 # automatically append "-c N" to tell Fossil how much context it wants.
 
 
 
 
 
 
 
 
8 #
9 # If the "filelist" global variable is defined, then it is a list of
10 # alternating "merge-type names" (ex: UPDATE, MERGE, CONFLICT, ERROR) and
11 # filenames. In that case, the initial display shows the changes for
12 # the first pair on the list and there is a optionmenu that allows the
13 # user to select other fiels on the list.
14 #
15 # There should also be a global variable named "ncontext" which is the
16 # number of lines of context to display. The value of this variable
17 # controls the "-c N" argument that is appended to fossilcmd.
18 #
19 # This header comment is stripped off by the "mkbuiltin.c" program.
20 #
21 package require Tk
22
23 array set CFG_light {
@@ -93,19 +97,19 @@
93 regexp {[a-z]+} $c type
94 return $type
95 }
96
97 proc readMerge {args} {
98 global fossilcmd ncontext current_file debug
99 if {$ncontext=="All"} {
100 set cmd "$fossilcmd -c -1"
101 } else {
102 set cmd "$fossilcmd -c $ncontext"
103 }
104 if {[info exists current_file]} {
105 regsub {^[A-Z]+ } $current_file {} fn
106 append cmd " -tcl [list $fn]"
107 }
108 if {$debug} {
109 regsub {^\| +} $cmd {} cmd2
110 puts $cmd2
111 flush stdout
@@ -342,10 +346,37 @@
342 bind . <$key> "scroll-$axis $args; break"
343 bind . <Shift-$key> continue
344 }
345
346 frame .bb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347 set useOptionMenu 1
348 if {[info exists filelist]} {
349 set current_file "[lindex $filelist 0] [lindex $filelist 1]"
350 if {[llength $filelist]>2} {
351 trace add variable current_file write readMerge
@@ -580,10 +611,11 @@
580 set ::search $w
581 }
582 ::ttk::button .bb.quit -text {Quit} -command exit
583 ::ttk::button .bb.search -text {Search} -command searchOnOff
584 pack .bb.quit -side left
 
585 if {[winfo exists .bb.files]} {
586 pack .bb.files -side left
587 }
588 pack .bb.ctxtag .bb.ctx -side left
589 pack .bb.search -side left
590
--- src/merge.tcl
+++ src/merge.tcl
@@ -1,23 +1,27 @@
1 # Show details of a 3-way merge operation. The left-most column is the
2 # common ancestor. The next two columns are edits of that common ancestor.
3 # The right-most column is the result of the merge.
4 #
5 # Several variables will have been initialized:
6 #
7 # ncontext The number of lines of context to show on each change
8 #
9 # fossilexe Pathname of the fossil program
10 #
11 # filelist A list of "merge-type filename" pairs.
12 #
13 # darkmode Boolean. True for dark mode
14 #
15 # debug Boolean. True for debugging output
16 #
17 # If the "filelist" global variable is defined, then it is a list of
18 # alternating "merge-type names" (ex: UPDATE, MERGE, CONFLICT, ERROR) and
19 # filenames. In that case, the initial display shows the changes for
20 # the first pair on the list and there is a optionmenu that allows the
21 # user to select other fiels on the list.
22 #
 
 
 
 
23 # This header comment is stripped off by the "mkbuiltin.c" program.
24 #
25 package require Tk
26
27 array set CFG_light {
@@ -93,19 +97,19 @@
97 regexp {[a-z]+} $c type
98 return $type
99 }
100
101 proc readMerge {args} {
102 global fossilexe ncontext current_file debug
103 if {$ncontext=="All"} {
104 set cmd "| $fossilexe merge-info -c -1"
105 } else {
106 set cmd "| $fossilexe merge-info -c $ncontext"
107 }
108 if {[info exists current_file]} {
109 regsub {^[A-Z]+ } $current_file {} fn
110 lappend cmd -tcl $fn
111 }
112 if {$debug} {
113 regsub {^\| +} $cmd {} cmd2
114 puts $cmd2
115 flush stdout
@@ -342,10 +346,37 @@
346 bind . <$key> "scroll-$axis $args; break"
347 bind . <Shift-$key> continue
348 }
349
350 frame .bb
351 ::ttk::menubutton .bb.diff2 -text {2-way diffs} -menu .bb.diff2.m
352 menu .bb.diff2.m
353 .bb.diff2.m add command -label {baseline vs. local} -command {two-way 12}
354 .bb.diff2.m add command -label {baseline vs. merge-in} -command {two-way 13}
355 .bb.diff2.m add command -label {local vs. merge-in} -command {two-way 23}
356
357 # Bring up a separate two-way diff between a pair of columns
358 # the argument is one of:
359 # 12 Baseline versus Local
360 # 13 Baseline versus Merge-in
361 # 23 Local versus Merge-in
362 #
363 proc two-way {mode} {
364 global current_file fossilexe debug darkmode ncontext
365 regsub {^[A-Z]+ } $current_file {} fn
366 set cmd $fossilexe
367 lappend cmd merge-info --diff$mode $fn -c $ncontext
368 if {$darkmode} {
369 lappend cmd --dark
370 }
371 if {$debug} {
372 puts $cmd
373 flush stdout
374 }
375 exec {*}$cmd &
376 }
377
378 set useOptionMenu 1
379 if {[info exists filelist]} {
380 set current_file "[lindex $filelist 0] [lindex $filelist 1]"
381 if {[llength $filelist]>2} {
382 trace add variable current_file write readMerge
@@ -580,10 +611,11 @@
611 set ::search $w
612 }
613 ::ttk::button .bb.quit -text {Quit} -command exit
614 ::ttk::button .bb.search -text {Search} -command searchOnOff
615 pack .bb.quit -side left
616 pack .bb.diff2 -side left
617 if {[winfo exists .bb.files]} {
618 pack .bb.files -side left
619 }
620 pack .bb.ctxtag .bb.ctx -side left
621 pack .bb.search -side left
622

Keyboard Shortcuts

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