Fossil SCM

Bring the merge-info-html branch up to date with trunk, step 2 of 2.

stephan 2025-02-20 14:46 merge-info-html merge
Commit c2b1c2c9fa3ef699d5087f2c700774e52132e03f325a2fa4097cd763c91363bf
+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
+39 -13
--- src/diff.tcl
+++ src/diff.tcl
@@ -91,12 +91,16 @@
9191
incr ii
9292
return $x
9393
}
9494
9595
proc readDiffs {fossilcmd} {
96
- global difftxt
96
+ global difftxt debug
9797
if {![info exists difftxt]} {
98
+ if {$debug} {
99
+ puts "# [list open $fossilcmd r]"
100
+ flush stdout
101
+ }
98102
set in [open $fossilcmd r]
99103
fconfigure $in -encoding utf-8
100104
set difftxt [split [read $in] \n]
101105
close $in
102106
}
@@ -110,34 +114,56 @@
110114
111115
set fromIndex [lsearch -glob $fossilcmd *-from]
112116
set toIndex [lsearch -glob $fossilcmd *-to]
113117
set branchIndex [lsearch -glob $fossilcmd *-branch]
114118
set checkinIndex [lsearch -glob $fossilcmd *-checkin]
115
- if {[string match *?--external-baseline* $fossilcmd]} {
116
- set fA {external baseline}
119
+ if {[lsearch -glob $fossilcmd *-label]>=0
120
+ || [lsearch {xdiff fdiff merge-info} [lindex $fossilcmd 2]]>=0
121
+ } {
122
+ set fA {}
123
+ set fB {}
117124
} 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
-
125
+ if {[string match *?--external-baseline* $fossilcmd]} {
126
+ set fA {external baseline}
127
+ } else {
128
+ set fA {base check-in}
129
+ }
130
+ set fB {current check-out}
131
+ if {$fromIndex > -1} {
132
+ set fA [lindex $fossilcmd $fromIndex+1]
133
+ }
134
+ if {$toIndex > -1} {
135
+ set fB [lindex $fossilcmd $toIndex+1]
136
+ }
137
+ if {$branchIndex > -1} {
138
+ set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"
139
+ }
140
+ if {$checkinIndex > -1} {
141
+ set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]
142
+ }
143
+ }
126144
127145
while {[set line [getLine $difftxt $N ii]] != -1} {
128146
switch -- [lindex $line 0] {
129147
FILE {
130148
incr nDiffs
131149
foreach wx [list [string length $n1] [string length $n2]] {
132150
if {$wx>$widths(ln)} {set widths(ln) $wx}
133151
}
134152
.lnA insert end \n fn \n -
135
- .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
153
+ if {$fA==""} {
154
+ .txtA insert end "[lindex $line 1]\n" fn \n -
155
+ } else {
156
+ .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
157
+ }
136158
.mkr insert end \n fn \n -
137159
.lnB insert end \n fn \n -
138
- .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
160
+ if {$fB==""} {
161
+ .txtB insert end "[lindex $line 2]\n" fn \n -
162
+ } else {
163
+ .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
164
+ }
139165
.wfiles.lb insert end [lindex $line 2]
140166
set n1 0
141167
set n2 0
142168
}
143169
SKIP {
144170
--- src/diff.tcl
+++ src/diff.tcl
@@ -91,12 +91,16 @@
91 incr ii
92 return $x
93 }
94
95 proc readDiffs {fossilcmd} {
96 global difftxt
97 if {![info exists difftxt]} {
 
 
 
 
98 set in [open $fossilcmd r]
99 fconfigure $in -encoding utf-8
100 set difftxt [split [read $in] \n]
101 close $in
102 }
@@ -110,34 +114,56 @@
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
@@ -91,12 +91,16 @@
91 incr ii
92 return $x
93 }
94
95 proc readDiffs {fossilcmd} {
96 global difftxt debug
97 if {![info exists difftxt]} {
98 if {$debug} {
99 puts "# [list open $fossilcmd r]"
100 flush stdout
101 }
102 set in [open $fossilcmd r]
103 fconfigure $in -encoding utf-8
104 set difftxt [split [read $in] \n]
105 close $in
106 }
@@ -110,34 +114,56 @@
114
115 set fromIndex [lsearch -glob $fossilcmd *-from]
116 set toIndex [lsearch -glob $fossilcmd *-to]
117 set branchIndex [lsearch -glob $fossilcmd *-branch]
118 set checkinIndex [lsearch -glob $fossilcmd *-checkin]
119 if {[lsearch -glob $fossilcmd *-label]>=0
120 || [lsearch {xdiff fdiff merge-info} [lindex $fossilcmd 2]]>=0
121 } {
122 set fA {}
123 set fB {}
124 } else {
125 if {[string match *?--external-baseline* $fossilcmd]} {
126 set fA {external baseline}
127 } else {
128 set fA {base check-in}
129 }
130 set fB {current check-out}
131 if {$fromIndex > -1} {
132 set fA [lindex $fossilcmd $fromIndex+1]
133 }
134 if {$toIndex > -1} {
135 set fB [lindex $fossilcmd $toIndex+1]
136 }
137 if {$branchIndex > -1} {
138 set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'"
139 }
140 if {$checkinIndex > -1} {
141 set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1]
142 }
143 }
144
145 while {[set line [getLine $difftxt $N ii]] != -1} {
146 switch -- [lindex $line 0] {
147 FILE {
148 incr nDiffs
149 foreach wx [list [string length $n1] [string length $n2]] {
150 if {$wx>$widths(ln)} {set widths(ln) $wx}
151 }
152 .lnA insert end \n fn \n -
153 if {$fA==""} {
154 .txtA insert end "[lindex $line 1]\n" fn \n -
155 } else {
156 .txtA insert end "[lindex $line 1] ($fA)\n" fn \n -
157 }
158 .mkr insert end \n fn \n -
159 .lnB insert end \n fn \n -
160 if {$fB==""} {
161 .txtB insert end "[lindex $line 2]\n" fn \n -
162 } else {
163 .txtB insert end "[lindex $line 2] ($fB)\n" fn \n -
164 }
165 .wfiles.lb insert end [lindex $line 2]
166 set n1 0
167 set n2 0
168 }
169 SKIP {
170
--- 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 ){
@@ -1205,12 +1207,19 @@
12051207
int i;
12061208
Blob script;
12071209
const char *zTempFile = 0;
12081210
char *zCmd;
12091211
const char *zTclsh;
1212
+ int bDebug = find_option("tkdebug",0,0)!=0;
12101213
int bDarkMode = find_option("dark",0,0)!=0;
12111214
blob_zero(&script);
1215
+ /* Caution: When this routine is called from the merge-info command,
1216
+ ** the --tcl argument requires an argument. But merge-info does not
1217
+ ** use -i, so we can take -i as that argument. This routine needs to
1218
+ ** always have -i after --tcl.
1219
+ ** CAUTION!
1220
+ ** vvvvvvv */
12121221
blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
12131222
g.nameOfExe, zSubCmd);
12141223
find_option("tcl",0,0);
12151224
find_option("html",0,0);
12161225
find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
12331242
blob_append(&script, " ", 1);
12341243
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
12351244
}
12361245
}
12371246
blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
1247
+ blob_appendf(&script, "set debug %d\n", bDebug);
12381248
blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
12391249
if( zTempFile ){
12401250
blob_write_to_file(&script, zTempFile);
12411251
fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
12421252
}else{
12431253
--- 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 ){
@@ -1205,12 +1207,19 @@
1205 int i;
1206 Blob script;
1207 const char *zTempFile = 0;
1208 char *zCmd;
1209 const char *zTclsh;
 
1210 int bDarkMode = find_option("dark",0,0)!=0;
1211 blob_zero(&script);
 
 
 
 
 
 
1212 blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
1213 g.nameOfExe, zSubCmd);
1214 find_option("tcl",0,0);
1215 find_option("html",0,0);
1216 find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
1233 blob_append(&script, " ", 1);
1234 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1235 }
1236 }
1237 blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
 
1238 blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
1239 if( zTempFile ){
1240 blob_write_to_file(&script, zTempFile);
1241 fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
1242 }else{
1243
--- 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 ){
@@ -1205,12 +1207,19 @@
1207 int i;
1208 Blob script;
1209 const char *zTempFile = 0;
1210 char *zCmd;
1211 const char *zTclsh;
1212 int bDebug = find_option("tkdebug",0,0)!=0;
1213 int bDarkMode = find_option("dark",0,0)!=0;
1214 blob_zero(&script);
1215 /* Caution: When this routine is called from the merge-info command,
1216 ** the --tcl argument requires an argument. But merge-info does not
1217 ** use -i, so we can take -i as that argument. This routine needs to
1218 ** always have -i after --tcl.
1219 ** CAUTION!
1220 ** vvvvvvv */
1221 blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
1222 g.nameOfExe, zSubCmd);
1223 find_option("tcl",0,0);
1224 find_option("html",0,0);
1225 find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
1242 blob_append(&script, " ", 1);
1243 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1244 }
1245 }
1246 blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
1247 blob_appendf(&script, "set debug %d\n", bDebug);
1248 blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
1249 if( zTempFile ){
1250 blob_write_to_file(&script, zTempFile);
1251 fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
1252 }else{
1253
--- 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 ){
@@ -1205,12 +1207,19 @@
12051207
int i;
12061208
Blob script;
12071209
const char *zTempFile = 0;
12081210
char *zCmd;
12091211
const char *zTclsh;
1212
+ int bDebug = find_option("tkdebug",0,0)!=0;
12101213
int bDarkMode = find_option("dark",0,0)!=0;
12111214
blob_zero(&script);
1215
+ /* Caution: When this routine is called from the merge-info command,
1216
+ ** the --tcl argument requires an argument. But merge-info does not
1217
+ ** use -i, so we can take -i as that argument. This routine needs to
1218
+ ** always have -i after --tcl.
1219
+ ** CAUTION!
1220
+ ** vvvvvvv */
12121221
blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
12131222
g.nameOfExe, zSubCmd);
12141223
find_option("tcl",0,0);
12151224
find_option("html",0,0);
12161225
find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
12331242
blob_append(&script, " ", 1);
12341243
for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
12351244
}
12361245
}
12371246
blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
1247
+ blob_appendf(&script, "set debug %d\n", bDebug);
12381248
blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
12391249
if( zTempFile ){
12401250
blob_write_to_file(&script, zTempFile);
12411251
fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
12421252
}else{
12431253
--- 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 ){
@@ -1205,12 +1207,19 @@
1205 int i;
1206 Blob script;
1207 const char *zTempFile = 0;
1208 char *zCmd;
1209 const char *zTclsh;
 
1210 int bDarkMode = find_option("dark",0,0)!=0;
1211 blob_zero(&script);
 
 
 
 
 
 
1212 blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
1213 g.nameOfExe, zSubCmd);
1214 find_option("tcl",0,0);
1215 find_option("html",0,0);
1216 find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
1233 blob_append(&script, " ", 1);
1234 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1235 }
1236 }
1237 blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
 
1238 blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
1239 if( zTempFile ){
1240 blob_write_to_file(&script, zTempFile);
1241 fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
1242 }else{
1243
--- 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 ){
@@ -1205,12 +1207,19 @@
1207 int i;
1208 Blob script;
1209 const char *zTempFile = 0;
1210 char *zCmd;
1211 const char *zTclsh;
1212 int bDebug = find_option("tkdebug",0,0)!=0;
1213 int bDarkMode = find_option("dark",0,0)!=0;
1214 blob_zero(&script);
1215 /* Caution: When this routine is called from the merge-info command,
1216 ** the --tcl argument requires an argument. But merge-info does not
1217 ** use -i, so we can take -i as that argument. This routine needs to
1218 ** always have -i after --tcl.
1219 ** CAUTION!
1220 ** vvvvvvv */
1221 blob_appendf(&script, "set fossilcmd {| \"%/\" %s -tcl -i -v",
1222 g.nameOfExe, zSubCmd);
1223 find_option("tcl",0,0);
1224 find_option("html",0,0);
1225 find_option("side-by-side","y",0);
@@ -1233,10 +1242,11 @@
1242 blob_append(&script, " ", 1);
1243 for(j=0; z[j]; j++) blob_appendf(&script, "\\%03o", (unsigned char)z[j]);
1244 }
1245 }
1246 blob_appendf(&script, "}\nset darkmode %d\n", bDarkMode);
1247 blob_appendf(&script, "set debug %d\n", bDebug);
1248 blob_appendf(&script, "%s", builtin_file("diff.tcl", 0));
1249 if( zTempFile ){
1250 blob_write_to_file(&script, zTempFile);
1251 fossil_print("To see diff, run: %s \"%s\"\n", zTclsh, zTempFile);
1252 }else{
1253
+156 -79
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
3939
}
4040
/* The undocumented --script FILENAME option causes the Tk script to
4141
** be written into the FILENAME instead of being run. This is used
4242
** for testing and debugging. */
4343
zTempFile = find_option("script",0,1);
44
- bDebug = find_option("debug",0,0)!=0;
44
+ bDebug = find_option("tkdebug",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
@@ -136,12 +137,19 @@
136137
** command associated with file "zFName". zFName must be the filename
137138
** relative to the root of the check-in - in other words a "tree name".
138139
**
139140
** When this routine is called, we know that the mergestat table
140141
** exists, but we do not know if zFName is mentioned in that table.
142
+**
143
+** The diffMode variable has these values:
144
+**
145
+** 0 Standard 3-way diff
146
+** 12 2-way diff between baseline and local
147
+** 13 2-way diff between baseline and merge-in
148
+** 23 2-way diff between local and merge-in
141149
*/
142
-static void merge_info_tcl(const char *zFName, int nContext){
150
+static void merge_info_tcl(const char *zFName, int nContext, int diffMode){
143151
const char *zTreename;/* Name of the file in the tree */
144152
Stmt q; /* To query the MERGESTAT table */
145153
MergeBuilder mb; /* The merge builder object */
146154
Blob pivot,v1,v2,out; /* Blobs for holding content */
147155
const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
162170
return;
163171
}
164172
mergebuilder_init_tcl(&mb);
165173
mb.nContext = nContext;
166174
167
- /* Set up the pivot */
168
- zFN = db_column_text(&q, 0);
169
- if( zFN==0 ){
170
- /* No pivot because the file was added */
171
- mb.zPivot = "(no baseline)";
172
- blob_zero(&pivot);
173
- }else{
174
- mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
175
- rid = db_column_int(&q, 1);
176
- content_get(rid, &pivot);
177
- }
178
- mb.pPivot = &pivot;
179
-
180
- /* Set up the merge-in as V2 */
181
- zFN = db_column_text(&q, 5);
182
- if( zFN==0 ){
183
- /* File deleted in the merged-in branch */
184
- mb.zV2 = "(deleted file)";
185
- blob_zero(&v2);
186
- }else{
187
- mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
188
- rid = db_column_int(&q, 6);
189
- content_get(rid, &v2);
190
- }
191
- mb.pV2 = &v2;
192
-
193
- /* Set up the local content as V1 */
194
- zFN = db_column_text(&q, 2);
195
- if( zFN==0 ){
196
- /* File added by merge */
197
- mb.zV1 = "(no original)";
198
- blob_zero(&v1);
199
- }else{
200
- mb.zV1 = mprintf("%s (local)", file_tail(zFN));
201
- rid = db_column_int(&q, 3);
202
- sz = db_column_int(&q, 4);
203
- if( rid==0 && sz>0 ){
204
- /* The origin file had been edited so we'll have to pull its
205
- ** original content out of the undo buffer */
206
- Stmt q2;
207
- db_prepare(&q2,
208
- "SELECT content FROM undo"
209
- " WHERE pathname=%Q AND octet_length(content)=%d",
210
- zFN, sz
211
- );
212
- blob_zero(&v1);
213
- if( db_step(&q2)==SQLITE_ROW ){
214
- db_column_blob(&q2, 0, &v1);
215
- }else{
216
- mb.zV1 = "(local content missing)";
217
- }
218
- db_finalize(&q2);
219
- }else{
220
- /* The origin file was unchanged when the merge first occurred */
221
- content_get(rid, &v1);
222
- }
223
- }
224
- mb.pV1 = &v1;
225
-
226
- /* Set up the output */
227
- zFN = db_column_text(&q, 7);
228
- if( zFN==0 ){
229
- mb.zOut = "(Merge Result)";
230
- }else{
231
- mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
232
- }
233
- blob_zero(&out);
234
- mb.pOut = &out;
235
-
236
- merge_three_blobs(&mb);
175
+ blob_zero(&pivot);
176
+ if( diffMode!=23 ){
177
+ /* Set up the pivot or baseline */
178
+ zFN = db_column_text(&q, 0);
179
+ if( zFN==0 ){
180
+ /* No pivot because the file was added */
181
+ mb.zPivot = "(no baseline)";
182
+ }else{
183
+ mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
184
+ rid = db_column_int(&q, 1);
185
+ content_get(rid, &pivot);
186
+ }
187
+ mb.pPivot = &pivot;
188
+ }
189
+
190
+ blob_zero(&v2);
191
+ if( diffMode!=12 ){
192
+ /* Set up the merge-in as V2 */
193
+ zFN = db_column_text(&q, 5);
194
+ if( zFN==0 ){
195
+ /* File deleted in the merged-in branch */
196
+ mb.zV2 = "(deleted file)";
197
+ }else{
198
+ mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
199
+ rid = db_column_int(&q, 6);
200
+ content_get(rid, &v2);
201
+ }
202
+ mb.pV2 = &v2;
203
+ }
204
+
205
+ blob_zero(&v1);
206
+ if( diffMode!=13 ){
207
+ /* Set up the local content as V1 */
208
+ zFN = db_column_text(&q, 2);
209
+ if( zFN==0 ){
210
+ /* File added by merge */
211
+ mb.zV1 = "(no original)";
212
+ }else{
213
+ mb.zV1 = mprintf("%s (local)", file_tail(zFN));
214
+ rid = db_column_int(&q, 3);
215
+ sz = db_column_int(&q, 4);
216
+ if( rid==0 && sz>0 ){
217
+ /* The origin file had been edited so we'll have to pull its
218
+ ** original content out of the undo buffer */
219
+ Stmt q2;
220
+ db_prepare(&q2,
221
+ "SELECT content FROM undo"
222
+ " WHERE pathname=%Q AND octet_length(content)=%d",
223
+ zFN, sz
224
+ );
225
+ blob_zero(&v1);
226
+ if( db_step(&q2)==SQLITE_ROW ){
227
+ db_column_blob(&q2, 0, &v1);
228
+ }else{
229
+ mb.zV1 = "(local content missing)";
230
+ }
231
+ db_finalize(&q2);
232
+ }else{
233
+ /* The origin file was unchanged when the merge first occurred */
234
+ content_get(rid, &v1);
235
+ }
236
+ }
237
+ mb.pV1 = &v1;
238
+ }
239
+
240
+ blob_zero(&out);
241
+ if( diffMode==0 ){
242
+ /* Set up the output and do a 3-way diff */
243
+ zFN = db_column_text(&q, 7);
244
+ if( zFN==0 ){
245
+ mb.zOut = "(Merge Result)";
246
+ }else{
247
+ mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
248
+ }
249
+ mb.pOut = &out;
250
+ merge_three_blobs(&mb);
251
+ }else{
252
+ /* Set up to do a two-way diff */
253
+ Blob *pLeft, *pRight;
254
+ const char *zTagLeft, *zTagRight;
255
+ DiffConfig cfg;
256
+ memset(&cfg, 0, sizeof(cfg));
257
+ cfg.diffFlags = DIFF_TCL;
258
+ cfg.nContext = mb.nContext;
259
+ if( diffMode==12 || diffMode==13 ){
260
+ pLeft = &pivot;
261
+ zTagLeft = "baseline";
262
+ }else{
263
+ pLeft = &v1;
264
+ zTagLeft = "local";
265
+ }
266
+ if( diffMode==12 ){
267
+ pRight = &v1;
268
+ zTagRight = "local";
269
+ }else{
270
+ pRight = &v2;
271
+ zTagRight = "merge-in";
272
+ }
273
+ cfg.azLabel[0] = mprintf("%s (%s)", zFName, zTagLeft);
274
+ cfg.azLabel[1] = mprintf("%s (%s)", zFName, zTagRight);
275
+ diff_print_filenames("", "", &cfg, &out);
276
+ text_diff(pLeft, pRight, &out, &cfg);
277
+ fossil_free((char*)cfg.azLabel[0]);
278
+ fossil_free((char*)cfg.azLabel[1]);
279
+ }
280
+
237281
blob_write_to_file(&out, "-");
238282
239283
mb.xDestroy(&mb);
240284
blob_reset(&pivot);
241285
blob_reset(&v1);
@@ -487,22 +531,27 @@
487531
** lines are shown.
488532
** -c|--context N Show N lines of context around each change,
489533
** with negative N meaning show all content. Only
490534
** meaningful in combination with --tcl or --tk.
491535
** --dark Use dark mode for the Tcl/Tk/HTML output modes.
536
+** --tk Bring up a Tcl/Tk GUI that shows the changes
537
+** associated with the most recent merge.
538
+**
539
+** Options used internally by --tk:
540
+** --diff12 FILE Bring up a separate --tk diff for just the baseline
541
+** and local variants of FILE.
542
+** --diff13 FILE Like --diff12 but for baseline versus merge-in
543
+** --diff23 FILE Like --diff12 but for local versus merge-in
492544
** --tcl FILE Generate (to stdout) a TCL list containing
493545
** information needed to display the changes to
494546
** FILE caused by the most recent merge. FILE must
495547
** be a pathname relative to the root of the check-out.
496
-** --tk Bring up a Tcl/Tk GUI that shows the changes
497
-** associated with the most recent merge.
498548
** --html Like --tk but emits HTML to stdout.
499549
** -b|--browser Like --html but show the result in a web browser.
500
-** Additional debugging options available only when --tk is used:
501
-** --debug Show sub-commands run to implement --tk
550
+** Debugging options available only when --tk is used:
551
+** --tkdebug Show sub-commands run to implement --tk
502552
** --script FILE Write script used to implement --tk into FILE
503
-
504553
*/
505554
void merge_info_cmd(void){
506555
const char *zCnt;
507556
const char *zTcl;
508557
int bTk;
@@ -512,25 +561,38 @@
512561
int bAll;
513562
int nContext;
514563
Stmt q;
515564
const char *zWhere;
516565
int cnt = 0;
566
+ const char *zDiff2 = 0;
567
+ int diffMode = 0;
517568
518569
db_must_be_within_tree();
519
- zTcl = find_option("tcl", 0, 1);
520570
bTk = find_option("tk", 0, 0)!=0;
521571
bBrowser = find_option("browser", "b", 0)!=0;
522572
bHtml = find_option("html", 0, 0)!=0 || bBrowser;
573
+ zTcl = find_option("tcl", 0, 1);
523574
zCnt = find_option("context", "c", 1);
524575
bDark = find_option("dark", 0, 0)!=0;
525576
bAll = find_option("all", "a", 0)!=0;
577
+
578
+ if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
579
+ diffMode = 12;
580
+ }else
581
+ if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
582
+ diffMode = 13;
583
+ }else
584
+ if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
585
+ diffMode = 23;
586
+ }
526587
if( (bTk + bHtml)==0 ){
527588
verify_all_options();
528589
if( g.argc>2 ){
529590
usage("[OPTIONS]");
530591
}
531592
}
593
+
532594
if( zCnt ){
533595
nContext = atoi(zCnt);
534596
if( nContext<0 ) nContext = 0xfffffff;
535597
}else{
536598
nContext = 6;
@@ -548,13 +610,28 @@
548610
return;
549611
}else if( bHtml ){
550612
merge_info_html(bBrowser, bDark, bAll, nContext);
551613
return;
552614
}else if( zTcl ){
553
- merge_info_tcl(zTcl, nContext);
615
+ if( diffMode ) zTcl = zDiff2;
616
+ merge_info_tcl(zTcl, nContext, diffMode);
617
+ return;
618
+ }
619
+ if( diffMode ){
620
+ char *zCmd;
621
+ zCmd = mprintf("merge-info --diff%d %!$ -c %d%s",
622
+ diffMode, zDiff2, nContext, bDark ? " --dark" : "");
623
+ diff_tk(zCmd, g.argc);
624
+ fossil_free(zCmd);
554625
return;
555626
}
627
+
628
+ verify_all_options();
629
+ if( g.argc>2 ){
630
+ usage("[OPTIONS]");
631
+ }
632
+
556633
if( bAll ){
557634
zWhere = "";
558635
}else{
559636
zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
560637
}
561638
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
39 }
40 /* The undocumented --script FILENAME option causes the Tk script to
41 ** be written into the FILENAME instead of being run. This is used
42 ** for testing and debugging. */
43 zTempFile = find_option("script",0,1);
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
@@ -136,12 +137,19 @@
136 ** command associated with file "zFName". zFName must be the filename
137 ** relative to the root of the check-in - in other words a "tree name".
138 **
139 ** When this routine is called, we know that the mergestat table
140 ** exists, but we do not know if zFName is mentioned in that table.
 
 
 
 
 
 
 
141 */
142 static void merge_info_tcl(const char *zFName, int nContext){
143 const char *zTreename;/* Name of the file in the tree */
144 Stmt q; /* To query the MERGESTAT table */
145 MergeBuilder mb; /* The merge builder object */
146 Blob pivot,v1,v2,out; /* Blobs for holding content */
147 const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
162 return;
163 }
164 mergebuilder_init_tcl(&mb);
165 mb.nContext = nContext;
166
167 /* Set up the pivot */
168 zFN = db_column_text(&q, 0);
169 if( zFN==0 ){
170 /* No pivot because the file was added */
171 mb.zPivot = "(no baseline)";
172 blob_zero(&pivot);
173 }else{
174 mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
175 rid = db_column_int(&q, 1);
176 content_get(rid, &pivot);
177 }
178 mb.pPivot = &pivot;
179
180 /* Set up the merge-in as V2 */
181 zFN = db_column_text(&q, 5);
182 if( zFN==0 ){
183 /* File deleted in the merged-in branch */
184 mb.zV2 = "(deleted file)";
185 blob_zero(&v2);
186 }else{
187 mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
188 rid = db_column_int(&q, 6);
189 content_get(rid, &v2);
190 }
191 mb.pV2 = &v2;
192
193 /* Set up the local content as V1 */
194 zFN = db_column_text(&q, 2);
195 if( zFN==0 ){
196 /* File added by merge */
197 mb.zV1 = "(no original)";
198 blob_zero(&v1);
199 }else{
200 mb.zV1 = mprintf("%s (local)", file_tail(zFN));
201 rid = db_column_int(&q, 3);
202 sz = db_column_int(&q, 4);
203 if( rid==0 && sz>0 ){
204 /* The origin file had been edited so we'll have to pull its
205 ** original content out of the undo buffer */
206 Stmt q2;
207 db_prepare(&q2,
208 "SELECT content FROM undo"
209 " WHERE pathname=%Q AND octet_length(content)=%d",
210 zFN, sz
211 );
212 blob_zero(&v1);
213 if( db_step(&q2)==SQLITE_ROW ){
214 db_column_blob(&q2, 0, &v1);
215 }else{
216 mb.zV1 = "(local content missing)";
217 }
218 db_finalize(&q2);
219 }else{
220 /* The origin file was unchanged when the merge first occurred */
221 content_get(rid, &v1);
222 }
223 }
224 mb.pV1 = &v1;
225
226 /* Set up the output */
227 zFN = db_column_text(&q, 7);
228 if( zFN==0 ){
229 mb.zOut = "(Merge Result)";
230 }else{
231 mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
232 }
233 blob_zero(&out);
234 mb.pOut = &out;
235
236 merge_three_blobs(&mb);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237 blob_write_to_file(&out, "-");
238
239 mb.xDestroy(&mb);
240 blob_reset(&pivot);
241 blob_reset(&v1);
@@ -487,22 +531,27 @@
487 ** lines are shown.
488 ** -c|--context N Show N lines of context around each change,
489 ** with negative N meaning show all content. Only
490 ** meaningful in combination with --tcl or --tk.
491 ** --dark Use dark mode for the Tcl/Tk/HTML output modes.
 
 
 
 
 
 
 
 
492 ** --tcl FILE Generate (to stdout) a TCL list containing
493 ** information needed to display the changes to
494 ** FILE caused by the most recent merge. FILE must
495 ** be a pathname relative to the root of the check-out.
496 ** --tk Bring up a Tcl/Tk GUI that shows the changes
497 ** associated with the most recent merge.
498 ** --html Like --tk but emits HTML to stdout.
499 ** -b|--browser Like --html but show the result in a web browser.
500 ** Additional debugging options available only when --tk is used:
501 ** --debug Show sub-commands run to implement --tk
502 ** --script FILE Write script used to implement --tk into FILE
503
504 */
505 void merge_info_cmd(void){
506 const char *zCnt;
507 const char *zTcl;
508 int bTk;
@@ -512,25 +561,38 @@
512 int bAll;
513 int nContext;
514 Stmt q;
515 const char *zWhere;
516 int cnt = 0;
 
 
517
518 db_must_be_within_tree();
519 zTcl = find_option("tcl", 0, 1);
520 bTk = find_option("tk", 0, 0)!=0;
521 bBrowser = find_option("browser", "b", 0)!=0;
522 bHtml = find_option("html", 0, 0)!=0 || bBrowser;
 
523 zCnt = find_option("context", "c", 1);
524 bDark = find_option("dark", 0, 0)!=0;
525 bAll = find_option("all", "a", 0)!=0;
 
 
 
 
 
 
 
 
 
 
526 if( (bTk + bHtml)==0 ){
527 verify_all_options();
528 if( g.argc>2 ){
529 usage("[OPTIONS]");
530 }
531 }
 
532 if( zCnt ){
533 nContext = atoi(zCnt);
534 if( nContext<0 ) nContext = 0xfffffff;
535 }else{
536 nContext = 6;
@@ -548,13 +610,28 @@
548 return;
549 }else if( bHtml ){
550 merge_info_html(bBrowser, bDark, bAll, nContext);
551 return;
552 }else if( zTcl ){
553 merge_info_tcl(zTcl, nContext);
 
 
 
 
 
 
 
 
 
554 return;
555 }
 
 
 
 
 
 
556 if( bAll ){
557 zWhere = "";
558 }else{
559 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
560 }
561
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
39 }
40 /* The undocumented --script FILENAME option causes the Tk script to
41 ** be written into the FILENAME instead of being run. This is used
42 ** for testing and debugging. */
43 zTempFile = find_option("script",0,1);
44 bDebug = find_option("tkdebug",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
@@ -136,12 +137,19 @@
137 ** command associated with file "zFName". zFName must be the filename
138 ** relative to the root of the check-in - in other words a "tree name".
139 **
140 ** When this routine is called, we know that the mergestat table
141 ** exists, but we do not know if zFName is mentioned in that table.
142 **
143 ** The diffMode variable has these values:
144 **
145 ** 0 Standard 3-way diff
146 ** 12 2-way diff between baseline and local
147 ** 13 2-way diff between baseline and merge-in
148 ** 23 2-way diff between local and merge-in
149 */
150 static void merge_info_tcl(const char *zFName, int nContext, int diffMode){
151 const char *zTreename;/* Name of the file in the tree */
152 Stmt q; /* To query the MERGESTAT table */
153 MergeBuilder mb; /* The merge builder object */
154 Blob pivot,v1,v2,out; /* Blobs for holding content */
155 const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
170 return;
171 }
172 mergebuilder_init_tcl(&mb);
173 mb.nContext = nContext;
174
175 blob_zero(&pivot);
176 if( diffMode!=23 ){
177 /* Set up the pivot or baseline */
178 zFN = db_column_text(&q, 0);
179 if( zFN==0 ){
180 /* No pivot because the file was added */
181 mb.zPivot = "(no baseline)";
182 }else{
183 mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
184 rid = db_column_int(&q, 1);
185 content_get(rid, &pivot);
186 }
187 mb.pPivot = &pivot;
188 }
189
190 blob_zero(&v2);
191 if( diffMode!=12 ){
192 /* Set up the merge-in as V2 */
193 zFN = db_column_text(&q, 5);
194 if( zFN==0 ){
195 /* File deleted in the merged-in branch */
196 mb.zV2 = "(deleted file)";
197 }else{
198 mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
199 rid = db_column_int(&q, 6);
200 content_get(rid, &v2);
201 }
202 mb.pV2 = &v2;
203 }
204
205 blob_zero(&v1);
206 if( diffMode!=13 ){
207 /* Set up the local content as V1 */
208 zFN = db_column_text(&q, 2);
209 if( zFN==0 ){
210 /* File added by merge */
211 mb.zV1 = "(no original)";
212 }else{
213 mb.zV1 = mprintf("%s (local)", file_tail(zFN));
214 rid = db_column_int(&q, 3);
215 sz = db_column_int(&q, 4);
216 if( rid==0 && sz>0 ){
217 /* The origin file had been edited so we'll have to pull its
218 ** original content out of the undo buffer */
219 Stmt q2;
220 db_prepare(&q2,
221 "SELECT content FROM undo"
222 " WHERE pathname=%Q AND octet_length(content)=%d",
223 zFN, sz
224 );
225 blob_zero(&v1);
226 if( db_step(&q2)==SQLITE_ROW ){
227 db_column_blob(&q2, 0, &v1);
228 }else{
229 mb.zV1 = "(local content missing)";
230 }
231 db_finalize(&q2);
232 }else{
233 /* The origin file was unchanged when the merge first occurred */
234 content_get(rid, &v1);
235 }
236 }
237 mb.pV1 = &v1;
238 }
239
240 blob_zero(&out);
241 if( diffMode==0 ){
242 /* Set up the output and do a 3-way diff */
243 zFN = db_column_text(&q, 7);
244 if( zFN==0 ){
245 mb.zOut = "(Merge Result)";
246 }else{
247 mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
248 }
249 mb.pOut = &out;
250 merge_three_blobs(&mb);
251 }else{
252 /* Set up to do a two-way diff */
253 Blob *pLeft, *pRight;
254 const char *zTagLeft, *zTagRight;
255 DiffConfig cfg;
256 memset(&cfg, 0, sizeof(cfg));
257 cfg.diffFlags = DIFF_TCL;
258 cfg.nContext = mb.nContext;
259 if( diffMode==12 || diffMode==13 ){
260 pLeft = &pivot;
261 zTagLeft = "baseline";
262 }else{
263 pLeft = &v1;
264 zTagLeft = "local";
265 }
266 if( diffMode==12 ){
267 pRight = &v1;
268 zTagRight = "local";
269 }else{
270 pRight = &v2;
271 zTagRight = "merge-in";
272 }
273 cfg.azLabel[0] = mprintf("%s (%s)", zFName, zTagLeft);
274 cfg.azLabel[1] = mprintf("%s (%s)", zFName, zTagRight);
275 diff_print_filenames("", "", &cfg, &out);
276 text_diff(pLeft, pRight, &out, &cfg);
277 fossil_free((char*)cfg.azLabel[0]);
278 fossil_free((char*)cfg.azLabel[1]);
279 }
280
281 blob_write_to_file(&out, "-");
282
283 mb.xDestroy(&mb);
284 blob_reset(&pivot);
285 blob_reset(&v1);
@@ -487,22 +531,27 @@
531 ** lines are shown.
532 ** -c|--context N Show N lines of context around each change,
533 ** with negative N meaning show all content. Only
534 ** meaningful in combination with --tcl or --tk.
535 ** --dark Use dark mode for the Tcl/Tk/HTML output modes.
536 ** --tk Bring up a Tcl/Tk GUI that shows the changes
537 ** associated with the most recent merge.
538 **
539 ** Options used internally by --tk:
540 ** --diff12 FILE Bring up a separate --tk diff for just the baseline
541 ** and local variants of FILE.
542 ** --diff13 FILE Like --diff12 but for baseline versus merge-in
543 ** --diff23 FILE Like --diff12 but for local versus merge-in
544 ** --tcl FILE Generate (to stdout) a TCL list containing
545 ** information needed to display the changes to
546 ** FILE caused by the most recent merge. FILE must
547 ** be a pathname relative to the root of the check-out.
 
 
548 ** --html Like --tk but emits HTML to stdout.
549 ** -b|--browser Like --html but show the result in a web browser.
550 ** Debugging options available only when --tk is used:
551 ** --tkdebug Show sub-commands run to implement --tk
552 ** --script FILE Write script used to implement --tk into FILE
 
553 */
554 void merge_info_cmd(void){
555 const char *zCnt;
556 const char *zTcl;
557 int bTk;
@@ -512,25 +561,38 @@
561 int bAll;
562 int nContext;
563 Stmt q;
564 const char *zWhere;
565 int cnt = 0;
566 const char *zDiff2 = 0;
567 int diffMode = 0;
568
569 db_must_be_within_tree();
 
570 bTk = find_option("tk", 0, 0)!=0;
571 bBrowser = find_option("browser", "b", 0)!=0;
572 bHtml = find_option("html", 0, 0)!=0 || bBrowser;
573 zTcl = find_option("tcl", 0, 1);
574 zCnt = find_option("context", "c", 1);
575 bDark = find_option("dark", 0, 0)!=0;
576 bAll = find_option("all", "a", 0)!=0;
577
578 if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
579 diffMode = 12;
580 }else
581 if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
582 diffMode = 13;
583 }else
584 if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
585 diffMode = 23;
586 }
587 if( (bTk + bHtml)==0 ){
588 verify_all_options();
589 if( g.argc>2 ){
590 usage("[OPTIONS]");
591 }
592 }
593
594 if( zCnt ){
595 nContext = atoi(zCnt);
596 if( nContext<0 ) nContext = 0xfffffff;
597 }else{
598 nContext = 6;
@@ -548,13 +610,28 @@
610 return;
611 }else if( bHtml ){
612 merge_info_html(bBrowser, bDark, bAll, nContext);
613 return;
614 }else if( zTcl ){
615 if( diffMode ) zTcl = zDiff2;
616 merge_info_tcl(zTcl, nContext, diffMode);
617 return;
618 }
619 if( diffMode ){
620 char *zCmd;
621 zCmd = mprintf("merge-info --diff%d %!$ -c %d%s",
622 diffMode, zDiff2, nContext, bDark ? " --dark" : "");
623 diff_tk(zCmd, g.argc);
624 fossil_free(zCmd);
625 return;
626 }
627
628 verify_all_options();
629 if( g.argc>2 ){
630 usage("[OPTIONS]");
631 }
632
633 if( bAll ){
634 zWhere = "";
635 }else{
636 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
637 }
638
+156 -79
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
3939
}
4040
/* The undocumented --script FILENAME option causes the Tk script to
4141
** be written into the FILENAME instead of being run. This is used
4242
** for testing and debugging. */
4343
zTempFile = find_option("script",0,1);
44
- bDebug = find_option("debug",0,0)!=0;
44
+ bDebug = find_option("tkdebug",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
@@ -136,12 +137,19 @@
136137
** command associated with file "zFName". zFName must be the filename
137138
** relative to the root of the check-in - in other words a "tree name".
138139
**
139140
** When this routine is called, we know that the mergestat table
140141
** exists, but we do not know if zFName is mentioned in that table.
142
+**
143
+** The diffMode variable has these values:
144
+**
145
+** 0 Standard 3-way diff
146
+** 12 2-way diff between baseline and local
147
+** 13 2-way diff between baseline and merge-in
148
+** 23 2-way diff between local and merge-in
141149
*/
142
-static void merge_info_tcl(const char *zFName, int nContext){
150
+static void merge_info_tcl(const char *zFName, int nContext, int diffMode){
143151
const char *zTreename;/* Name of the file in the tree */
144152
Stmt q; /* To query the MERGESTAT table */
145153
MergeBuilder mb; /* The merge builder object */
146154
Blob pivot,v1,v2,out; /* Blobs for holding content */
147155
const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
162170
return;
163171
}
164172
mergebuilder_init_tcl(&mb);
165173
mb.nContext = nContext;
166174
167
- /* Set up the pivot */
168
- zFN = db_column_text(&q, 0);
169
- if( zFN==0 ){
170
- /* No pivot because the file was added */
171
- mb.zPivot = "(no baseline)";
172
- blob_zero(&pivot);
173
- }else{
174
- mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
175
- rid = db_column_int(&q, 1);
176
- content_get(rid, &pivot);
177
- }
178
- mb.pPivot = &pivot;
179
-
180
- /* Set up the merge-in as V2 */
181
- zFN = db_column_text(&q, 5);
182
- if( zFN==0 ){
183
- /* File deleted in the merged-in branch */
184
- mb.zV2 = "(deleted file)";
185
- blob_zero(&v2);
186
- }else{
187
- mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
188
- rid = db_column_int(&q, 6);
189
- content_get(rid, &v2);
190
- }
191
- mb.pV2 = &v2;
192
-
193
- /* Set up the local content as V1 */
194
- zFN = db_column_text(&q, 2);
195
- if( zFN==0 ){
196
- /* File added by merge */
197
- mb.zV1 = "(no original)";
198
- blob_zero(&v1);
199
- }else{
200
- mb.zV1 = mprintf("%s (local)", file_tail(zFN));
201
- rid = db_column_int(&q, 3);
202
- sz = db_column_int(&q, 4);
203
- if( rid==0 && sz>0 ){
204
- /* The origin file had been edited so we'll have to pull its
205
- ** original content out of the undo buffer */
206
- Stmt q2;
207
- db_prepare(&q2,
208
- "SELECT content FROM undo"
209
- " WHERE pathname=%Q AND octet_length(content)=%d",
210
- zFN, sz
211
- );
212
- blob_zero(&v1);
213
- if( db_step(&q2)==SQLITE_ROW ){
214
- db_column_blob(&q2, 0, &v1);
215
- }else{
216
- mb.zV1 = "(local content missing)";
217
- }
218
- db_finalize(&q2);
219
- }else{
220
- /* The origin file was unchanged when the merge first occurred */
221
- content_get(rid, &v1);
222
- }
223
- }
224
- mb.pV1 = &v1;
225
-
226
- /* Set up the output */
227
- zFN = db_column_text(&q, 7);
228
- if( zFN==0 ){
229
- mb.zOut = "(Merge Result)";
230
- }else{
231
- mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
232
- }
233
- blob_zero(&out);
234
- mb.pOut = &out;
235
-
236
- merge_three_blobs(&mb);
175
+ blob_zero(&pivot);
176
+ if( diffMode!=23 ){
177
+ /* Set up the pivot or baseline */
178
+ zFN = db_column_text(&q, 0);
179
+ if( zFN==0 ){
180
+ /* No pivot because the file was added */
181
+ mb.zPivot = "(no baseline)";
182
+ }else{
183
+ mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
184
+ rid = db_column_int(&q, 1);
185
+ content_get(rid, &pivot);
186
+ }
187
+ mb.pPivot = &pivot;
188
+ }
189
+
190
+ blob_zero(&v2);
191
+ if( diffMode!=12 ){
192
+ /* Set up the merge-in as V2 */
193
+ zFN = db_column_text(&q, 5);
194
+ if( zFN==0 ){
195
+ /* File deleted in the merged-in branch */
196
+ mb.zV2 = "(deleted file)";
197
+ }else{
198
+ mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
199
+ rid = db_column_int(&q, 6);
200
+ content_get(rid, &v2);
201
+ }
202
+ mb.pV2 = &v2;
203
+ }
204
+
205
+ blob_zero(&v1);
206
+ if( diffMode!=13 ){
207
+ /* Set up the local content as V1 */
208
+ zFN = db_column_text(&q, 2);
209
+ if( zFN==0 ){
210
+ /* File added by merge */
211
+ mb.zV1 = "(no original)";
212
+ }else{
213
+ mb.zV1 = mprintf("%s (local)", file_tail(zFN));
214
+ rid = db_column_int(&q, 3);
215
+ sz = db_column_int(&q, 4);
216
+ if( rid==0 && sz>0 ){
217
+ /* The origin file had been edited so we'll have to pull its
218
+ ** original content out of the undo buffer */
219
+ Stmt q2;
220
+ db_prepare(&q2,
221
+ "SELECT content FROM undo"
222
+ " WHERE pathname=%Q AND octet_length(content)=%d",
223
+ zFN, sz
224
+ );
225
+ blob_zero(&v1);
226
+ if( db_step(&q2)==SQLITE_ROW ){
227
+ db_column_blob(&q2, 0, &v1);
228
+ }else{
229
+ mb.zV1 = "(local content missing)";
230
+ }
231
+ db_finalize(&q2);
232
+ }else{
233
+ /* The origin file was unchanged when the merge first occurred */
234
+ content_get(rid, &v1);
235
+ }
236
+ }
237
+ mb.pV1 = &v1;
238
+ }
239
+
240
+ blob_zero(&out);
241
+ if( diffMode==0 ){
242
+ /* Set up the output and do a 3-way diff */
243
+ zFN = db_column_text(&q, 7);
244
+ if( zFN==0 ){
245
+ mb.zOut = "(Merge Result)";
246
+ }else{
247
+ mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
248
+ }
249
+ mb.pOut = &out;
250
+ merge_three_blobs(&mb);
251
+ }else{
252
+ /* Set up to do a two-way diff */
253
+ Blob *pLeft, *pRight;
254
+ const char *zTagLeft, *zTagRight;
255
+ DiffConfig cfg;
256
+ memset(&cfg, 0, sizeof(cfg));
257
+ cfg.diffFlags = DIFF_TCL;
258
+ cfg.nContext = mb.nContext;
259
+ if( diffMode==12 || diffMode==13 ){
260
+ pLeft = &pivot;
261
+ zTagLeft = "baseline";
262
+ }else{
263
+ pLeft = &v1;
264
+ zTagLeft = "local";
265
+ }
266
+ if( diffMode==12 ){
267
+ pRight = &v1;
268
+ zTagRight = "local";
269
+ }else{
270
+ pRight = &v2;
271
+ zTagRight = "merge-in";
272
+ }
273
+ cfg.azLabel[0] = mprintf("%s (%s)", zFName, zTagLeft);
274
+ cfg.azLabel[1] = mprintf("%s (%s)", zFName, zTagRight);
275
+ diff_print_filenames("", "", &cfg, &out);
276
+ text_diff(pLeft, pRight, &out, &cfg);
277
+ fossil_free((char*)cfg.azLabel[0]);
278
+ fossil_free((char*)cfg.azLabel[1]);
279
+ }
280
+
237281
blob_write_to_file(&out, "-");
238282
239283
mb.xDestroy(&mb);
240284
blob_reset(&pivot);
241285
blob_reset(&v1);
@@ -487,22 +531,27 @@
487531
** lines are shown.
488532
** -c|--context N Show N lines of context around each change,
489533
** with negative N meaning show all content. Only
490534
** meaningful in combination with --tcl or --tk.
491535
** --dark Use dark mode for the Tcl/Tk/HTML output modes.
536
+** --tk Bring up a Tcl/Tk GUI that shows the changes
537
+** associated with the most recent merge.
538
+**
539
+** Options used internally by --tk:
540
+** --diff12 FILE Bring up a separate --tk diff for just the baseline
541
+** and local variants of FILE.
542
+** --diff13 FILE Like --diff12 but for baseline versus merge-in
543
+** --diff23 FILE Like --diff12 but for local versus merge-in
492544
** --tcl FILE Generate (to stdout) a TCL list containing
493545
** information needed to display the changes to
494546
** FILE caused by the most recent merge. FILE must
495547
** be a pathname relative to the root of the check-out.
496
-** --tk Bring up a Tcl/Tk GUI that shows the changes
497
-** associated with the most recent merge.
498548
** --html Like --tk but emits HTML to stdout.
499549
** -b|--browser Like --html but show the result in a web browser.
500
-** Additional debugging options available only when --tk is used:
501
-** --debug Show sub-commands run to implement --tk
550
+** Debugging options available only when --tk is used:
551
+** --tkdebug Show sub-commands run to implement --tk
502552
** --script FILE Write script used to implement --tk into FILE
503
-
504553
*/
505554
void merge_info_cmd(void){
506555
const char *zCnt;
507556
const char *zTcl;
508557
int bTk;
@@ -512,25 +561,38 @@
512561
int bAll;
513562
int nContext;
514563
Stmt q;
515564
const char *zWhere;
516565
int cnt = 0;
566
+ const char *zDiff2 = 0;
567
+ int diffMode = 0;
517568
518569
db_must_be_within_tree();
519
- zTcl = find_option("tcl", 0, 1);
520570
bTk = find_option("tk", 0, 0)!=0;
521571
bBrowser = find_option("browser", "b", 0)!=0;
522572
bHtml = find_option("html", 0, 0)!=0 || bBrowser;
573
+ zTcl = find_option("tcl", 0, 1);
523574
zCnt = find_option("context", "c", 1);
524575
bDark = find_option("dark", 0, 0)!=0;
525576
bAll = find_option("all", "a", 0)!=0;
577
+
578
+ if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
579
+ diffMode = 12;
580
+ }else
581
+ if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
582
+ diffMode = 13;
583
+ }else
584
+ if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
585
+ diffMode = 23;
586
+ }
526587
if( (bTk + bHtml)==0 ){
527588
verify_all_options();
528589
if( g.argc>2 ){
529590
usage("[OPTIONS]");
530591
}
531592
}
593
+
532594
if( zCnt ){
533595
nContext = atoi(zCnt);
534596
if( nContext<0 ) nContext = 0xfffffff;
535597
}else{
536598
nContext = 6;
@@ -548,13 +610,28 @@
548610
return;
549611
}else if( bHtml ){
550612
merge_info_html(bBrowser, bDark, bAll, nContext);
551613
return;
552614
}else if( zTcl ){
553
- merge_info_tcl(zTcl, nContext);
615
+ if( diffMode ) zTcl = zDiff2;
616
+ merge_info_tcl(zTcl, nContext, diffMode);
617
+ return;
618
+ }
619
+ if( diffMode ){
620
+ char *zCmd;
621
+ zCmd = mprintf("merge-info --diff%d %!$ -c %d%s",
622
+ diffMode, zDiff2, nContext, bDark ? " --dark" : "");
623
+ diff_tk(zCmd, g.argc);
624
+ fossil_free(zCmd);
554625
return;
555626
}
627
+
628
+ verify_all_options();
629
+ if( g.argc>2 ){
630
+ usage("[OPTIONS]");
631
+ }
632
+
556633
if( bAll ){
557634
zWhere = "";
558635
}else{
559636
zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
560637
}
561638
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
39 }
40 /* The undocumented --script FILENAME option causes the Tk script to
41 ** be written into the FILENAME instead of being run. This is used
42 ** for testing and debugging. */
43 zTempFile = find_option("script",0,1);
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
@@ -136,12 +137,19 @@
136 ** command associated with file "zFName". zFName must be the filename
137 ** relative to the root of the check-in - in other words a "tree name".
138 **
139 ** When this routine is called, we know that the mergestat table
140 ** exists, but we do not know if zFName is mentioned in that table.
 
 
 
 
 
 
 
141 */
142 static void merge_info_tcl(const char *zFName, int nContext){
143 const char *zTreename;/* Name of the file in the tree */
144 Stmt q; /* To query the MERGESTAT table */
145 MergeBuilder mb; /* The merge builder object */
146 Blob pivot,v1,v2,out; /* Blobs for holding content */
147 const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
162 return;
163 }
164 mergebuilder_init_tcl(&mb);
165 mb.nContext = nContext;
166
167 /* Set up the pivot */
168 zFN = db_column_text(&q, 0);
169 if( zFN==0 ){
170 /* No pivot because the file was added */
171 mb.zPivot = "(no baseline)";
172 blob_zero(&pivot);
173 }else{
174 mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
175 rid = db_column_int(&q, 1);
176 content_get(rid, &pivot);
177 }
178 mb.pPivot = &pivot;
179
180 /* Set up the merge-in as V2 */
181 zFN = db_column_text(&q, 5);
182 if( zFN==0 ){
183 /* File deleted in the merged-in branch */
184 mb.zV2 = "(deleted file)";
185 blob_zero(&v2);
186 }else{
187 mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
188 rid = db_column_int(&q, 6);
189 content_get(rid, &v2);
190 }
191 mb.pV2 = &v2;
192
193 /* Set up the local content as V1 */
194 zFN = db_column_text(&q, 2);
195 if( zFN==0 ){
196 /* File added by merge */
197 mb.zV1 = "(no original)";
198 blob_zero(&v1);
199 }else{
200 mb.zV1 = mprintf("%s (local)", file_tail(zFN));
201 rid = db_column_int(&q, 3);
202 sz = db_column_int(&q, 4);
203 if( rid==0 && sz>0 ){
204 /* The origin file had been edited so we'll have to pull its
205 ** original content out of the undo buffer */
206 Stmt q2;
207 db_prepare(&q2,
208 "SELECT content FROM undo"
209 " WHERE pathname=%Q AND octet_length(content)=%d",
210 zFN, sz
211 );
212 blob_zero(&v1);
213 if( db_step(&q2)==SQLITE_ROW ){
214 db_column_blob(&q2, 0, &v1);
215 }else{
216 mb.zV1 = "(local content missing)";
217 }
218 db_finalize(&q2);
219 }else{
220 /* The origin file was unchanged when the merge first occurred */
221 content_get(rid, &v1);
222 }
223 }
224 mb.pV1 = &v1;
225
226 /* Set up the output */
227 zFN = db_column_text(&q, 7);
228 if( zFN==0 ){
229 mb.zOut = "(Merge Result)";
230 }else{
231 mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
232 }
233 blob_zero(&out);
234 mb.pOut = &out;
235
236 merge_three_blobs(&mb);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237 blob_write_to_file(&out, "-");
238
239 mb.xDestroy(&mb);
240 blob_reset(&pivot);
241 blob_reset(&v1);
@@ -487,22 +531,27 @@
487 ** lines are shown.
488 ** -c|--context N Show N lines of context around each change,
489 ** with negative N meaning show all content. Only
490 ** meaningful in combination with --tcl or --tk.
491 ** --dark Use dark mode for the Tcl/Tk/HTML output modes.
 
 
 
 
 
 
 
 
492 ** --tcl FILE Generate (to stdout) a TCL list containing
493 ** information needed to display the changes to
494 ** FILE caused by the most recent merge. FILE must
495 ** be a pathname relative to the root of the check-out.
496 ** --tk Bring up a Tcl/Tk GUI that shows the changes
497 ** associated with the most recent merge.
498 ** --html Like --tk but emits HTML to stdout.
499 ** -b|--browser Like --html but show the result in a web browser.
500 ** Additional debugging options available only when --tk is used:
501 ** --debug Show sub-commands run to implement --tk
502 ** --script FILE Write script used to implement --tk into FILE
503
504 */
505 void merge_info_cmd(void){
506 const char *zCnt;
507 const char *zTcl;
508 int bTk;
@@ -512,25 +561,38 @@
512 int bAll;
513 int nContext;
514 Stmt q;
515 const char *zWhere;
516 int cnt = 0;
 
 
517
518 db_must_be_within_tree();
519 zTcl = find_option("tcl", 0, 1);
520 bTk = find_option("tk", 0, 0)!=0;
521 bBrowser = find_option("browser", "b", 0)!=0;
522 bHtml = find_option("html", 0, 0)!=0 || bBrowser;
 
523 zCnt = find_option("context", "c", 1);
524 bDark = find_option("dark", 0, 0)!=0;
525 bAll = find_option("all", "a", 0)!=0;
 
 
 
 
 
 
 
 
 
 
526 if( (bTk + bHtml)==0 ){
527 verify_all_options();
528 if( g.argc>2 ){
529 usage("[OPTIONS]");
530 }
531 }
 
532 if( zCnt ){
533 nContext = atoi(zCnt);
534 if( nContext<0 ) nContext = 0xfffffff;
535 }else{
536 nContext = 6;
@@ -548,13 +610,28 @@
548 return;
549 }else if( bHtml ){
550 merge_info_html(bBrowser, bDark, bAll, nContext);
551 return;
552 }else if( zTcl ){
553 merge_info_tcl(zTcl, nContext);
 
 
 
 
 
 
 
 
 
554 return;
555 }
 
 
 
 
 
 
556 if( bAll ){
557 zWhere = "";
558 }else{
559 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
560 }
561
--- src/merge.c
+++ src/merge.c
@@ -39,15 +39,16 @@
39 }
40 /* The undocumented --script FILENAME option causes the Tk script to
41 ** be written into the FILENAME instead of being run. This is used
42 ** for testing and debugging. */
43 zTempFile = find_option("script",0,1);
44 bDebug = find_option("tkdebug",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
@@ -136,12 +137,19 @@
137 ** command associated with file "zFName". zFName must be the filename
138 ** relative to the root of the check-in - in other words a "tree name".
139 **
140 ** When this routine is called, we know that the mergestat table
141 ** exists, but we do not know if zFName is mentioned in that table.
142 **
143 ** The diffMode variable has these values:
144 **
145 ** 0 Standard 3-way diff
146 ** 12 2-way diff between baseline and local
147 ** 13 2-way diff between baseline and merge-in
148 ** 23 2-way diff between local and merge-in
149 */
150 static void merge_info_tcl(const char *zFName, int nContext, int diffMode){
151 const char *zTreename;/* Name of the file in the tree */
152 Stmt q; /* To query the MERGESTAT table */
153 MergeBuilder mb; /* The merge builder object */
154 Blob pivot,v1,v2,out; /* Blobs for holding content */
155 const char *zFN; /* A filename */
@@ -162,80 +170,116 @@
170 return;
171 }
172 mergebuilder_init_tcl(&mb);
173 mb.nContext = nContext;
174
175 blob_zero(&pivot);
176 if( diffMode!=23 ){
177 /* Set up the pivot or baseline */
178 zFN = db_column_text(&q, 0);
179 if( zFN==0 ){
180 /* No pivot because the file was added */
181 mb.zPivot = "(no baseline)";
182 }else{
183 mb.zPivot = mprintf("%s (baseline)", file_tail(zFN));
184 rid = db_column_int(&q, 1);
185 content_get(rid, &pivot);
186 }
187 mb.pPivot = &pivot;
188 }
189
190 blob_zero(&v2);
191 if( diffMode!=12 ){
192 /* Set up the merge-in as V2 */
193 zFN = db_column_text(&q, 5);
194 if( zFN==0 ){
195 /* File deleted in the merged-in branch */
196 mb.zV2 = "(deleted file)";
197 }else{
198 mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN));
199 rid = db_column_int(&q, 6);
200 content_get(rid, &v2);
201 }
202 mb.pV2 = &v2;
203 }
204
205 blob_zero(&v1);
206 if( diffMode!=13 ){
207 /* Set up the local content as V1 */
208 zFN = db_column_text(&q, 2);
209 if( zFN==0 ){
210 /* File added by merge */
211 mb.zV1 = "(no original)";
212 }else{
213 mb.zV1 = mprintf("%s (local)", file_tail(zFN));
214 rid = db_column_int(&q, 3);
215 sz = db_column_int(&q, 4);
216 if( rid==0 && sz>0 ){
217 /* The origin file had been edited so we'll have to pull its
218 ** original content out of the undo buffer */
219 Stmt q2;
220 db_prepare(&q2,
221 "SELECT content FROM undo"
222 " WHERE pathname=%Q AND octet_length(content)=%d",
223 zFN, sz
224 );
225 blob_zero(&v1);
226 if( db_step(&q2)==SQLITE_ROW ){
227 db_column_blob(&q2, 0, &v1);
228 }else{
229 mb.zV1 = "(local content missing)";
230 }
231 db_finalize(&q2);
232 }else{
233 /* The origin file was unchanged when the merge first occurred */
234 content_get(rid, &v1);
235 }
236 }
237 mb.pV1 = &v1;
238 }
239
240 blob_zero(&out);
241 if( diffMode==0 ){
242 /* Set up the output and do a 3-way diff */
243 zFN = db_column_text(&q, 7);
244 if( zFN==0 ){
245 mb.zOut = "(Merge Result)";
246 }else{
247 mb.zOut = mprintf("%s (after merge)", file_tail(zFN));
248 }
249 mb.pOut = &out;
250 merge_three_blobs(&mb);
251 }else{
252 /* Set up to do a two-way diff */
253 Blob *pLeft, *pRight;
254 const char *zTagLeft, *zTagRight;
255 DiffConfig cfg;
256 memset(&cfg, 0, sizeof(cfg));
257 cfg.diffFlags = DIFF_TCL;
258 cfg.nContext = mb.nContext;
259 if( diffMode==12 || diffMode==13 ){
260 pLeft = &pivot;
261 zTagLeft = "baseline";
262 }else{
263 pLeft = &v1;
264 zTagLeft = "local";
265 }
266 if( diffMode==12 ){
267 pRight = &v1;
268 zTagRight = "local";
269 }else{
270 pRight = &v2;
271 zTagRight = "merge-in";
272 }
273 cfg.azLabel[0] = mprintf("%s (%s)", zFName, zTagLeft);
274 cfg.azLabel[1] = mprintf("%s (%s)", zFName, zTagRight);
275 diff_print_filenames("", "", &cfg, &out);
276 text_diff(pLeft, pRight, &out, &cfg);
277 fossil_free((char*)cfg.azLabel[0]);
278 fossil_free((char*)cfg.azLabel[1]);
279 }
280
281 blob_write_to_file(&out, "-");
282
283 mb.xDestroy(&mb);
284 blob_reset(&pivot);
285 blob_reset(&v1);
@@ -487,22 +531,27 @@
531 ** lines are shown.
532 ** -c|--context N Show N lines of context around each change,
533 ** with negative N meaning show all content. Only
534 ** meaningful in combination with --tcl or --tk.
535 ** --dark Use dark mode for the Tcl/Tk/HTML output modes.
536 ** --tk Bring up a Tcl/Tk GUI that shows the changes
537 ** associated with the most recent merge.
538 **
539 ** Options used internally by --tk:
540 ** --diff12 FILE Bring up a separate --tk diff for just the baseline
541 ** and local variants of FILE.
542 ** --diff13 FILE Like --diff12 but for baseline versus merge-in
543 ** --diff23 FILE Like --diff12 but for local versus merge-in
544 ** --tcl FILE Generate (to stdout) a TCL list containing
545 ** information needed to display the changes to
546 ** FILE caused by the most recent merge. FILE must
547 ** be a pathname relative to the root of the check-out.
 
 
548 ** --html Like --tk but emits HTML to stdout.
549 ** -b|--browser Like --html but show the result in a web browser.
550 ** Debugging options available only when --tk is used:
551 ** --tkdebug Show sub-commands run to implement --tk
552 ** --script FILE Write script used to implement --tk into FILE
 
553 */
554 void merge_info_cmd(void){
555 const char *zCnt;
556 const char *zTcl;
557 int bTk;
@@ -512,25 +561,38 @@
561 int bAll;
562 int nContext;
563 Stmt q;
564 const char *zWhere;
565 int cnt = 0;
566 const char *zDiff2 = 0;
567 int diffMode = 0;
568
569 db_must_be_within_tree();
 
570 bTk = find_option("tk", 0, 0)!=0;
571 bBrowser = find_option("browser", "b", 0)!=0;
572 bHtml = find_option("html", 0, 0)!=0 || bBrowser;
573 zTcl = find_option("tcl", 0, 1);
574 zCnt = find_option("context", "c", 1);
575 bDark = find_option("dark", 0, 0)!=0;
576 bAll = find_option("all", "a", 0)!=0;
577
578 if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){
579 diffMode = 12;
580 }else
581 if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){
582 diffMode = 13;
583 }else
584 if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){
585 diffMode = 23;
586 }
587 if( (bTk + bHtml)==0 ){
588 verify_all_options();
589 if( g.argc>2 ){
590 usage("[OPTIONS]");
591 }
592 }
593
594 if( zCnt ){
595 nContext = atoi(zCnt);
596 if( nContext<0 ) nContext = 0xfffffff;
597 }else{
598 nContext = 6;
@@ -548,13 +610,28 @@
610 return;
611 }else if( bHtml ){
612 merge_info_html(bBrowser, bDark, bAll, nContext);
613 return;
614 }else if( zTcl ){
615 if( diffMode ) zTcl = zDiff2;
616 merge_info_tcl(zTcl, nContext, diffMode);
617 return;
618 }
619 if( diffMode ){
620 char *zCmd;
621 zCmd = mprintf("merge-info --diff%d %!$ -c %d%s",
622 diffMode, zDiff2, nContext, bDark ? " --dark" : "");
623 diff_tk(zCmd, g.argc);
624 fossil_free(zCmd);
625 return;
626 }
627
628 verify_all_options();
629 if( g.argc>2 ){
630 usage("[OPTIONS]");
631 }
632
633 if( bAll ){
634 zWhere = "";
635 }else{
636 zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')";
637 }
638
+48 -15
--- 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,38 @@
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 diff} -menu .bb.diff2.m
352
+menu .bb.diff2.m -tearoff 0
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
+ lappend cmd --tkdebug
373
+ puts $cmd
374
+ flush stdout
375
+ }
376
+ exec {*}$cmd &
377
+}
378
+
347379
set useOptionMenu 1
348380
if {[info exists filelist]} {
349381
set current_file "[lindex $filelist 0] [lindex $filelist 1]"
350382
if {[llength $filelist]>2} {
351383
trace add variable current_file write readMerge
@@ -579,16 +611,17 @@
579611
}
580612
set ::search $w
581613
}
582614
::ttk::button .bb.quit -text {Quit} -command exit
583615
::ttk::button .bb.search -text {Search} -command searchOnOff
584
-pack .bb.quit -side left
616
+pack .bb.quit -side left -fill y
617
+pack .bb.diff2 -side left -fill y
585618
if {[winfo exists .bb.files]} {
586
- pack .bb.files -side left
619
+ pack .bb.files -side left -fill y
587620
}
588
-pack .bb.ctxtag .bb.ctx -side left
589
-pack .bb.search -side left
621
+pack .bb.ctxtag .bb.ctx -side left -fill y
622
+pack .bb.search -side left -fill y
590623
grid rowconfigure . 1 -weight 1 -minsize [winfo reqheight .nameA]
591624
grid rowconfigure . 2 -weight 100
592625
readMerge
593626
grid .bb -row 0 -columnspan 8
594627
grid .nameA -row 1 -column 1 -sticky ew
595628
--- 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,38 @@
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
@@ -579,16 +611,17 @@
579 }
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 grid rowconfigure . 1 -weight 1 -minsize [winfo reqheight .nameA]
591 grid rowconfigure . 2 -weight 100
592 readMerge
593 grid .bb -row 0 -columnspan 8
594 grid .nameA -row 1 -column 1 -sticky ew
595
--- 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,38 @@
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 diff} -menu .bb.diff2.m
352 menu .bb.diff2.m -tearoff 0
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 lappend cmd --tkdebug
373 puts $cmd
374 flush stdout
375 }
376 exec {*}$cmd &
377 }
378
379 set useOptionMenu 1
380 if {[info exists filelist]} {
381 set current_file "[lindex $filelist 0] [lindex $filelist 1]"
382 if {[llength $filelist]>2} {
383 trace add variable current_file write readMerge
@@ -579,16 +611,17 @@
611 }
612 set ::search $w
613 }
614 ::ttk::button .bb.quit -text {Quit} -command exit
615 ::ttk::button .bb.search -text {Search} -command searchOnOff
616 pack .bb.quit -side left -fill y
617 pack .bb.diff2 -side left -fill y
618 if {[winfo exists .bb.files]} {
619 pack .bb.files -side left -fill y
620 }
621 pack .bb.ctxtag .bb.ctx -side left -fill y
622 pack .bb.search -side left -fill y
623 grid rowconfigure . 1 -weight 1 -minsize [winfo reqheight .nameA]
624 grid rowconfigure . 2 -weight 100
625 readMerge
626 grid .bb -row 0 -columnspan 8
627 grid .nameA -row 1 -column 1 -sticky ew
628

Keyboard Shortcuts

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