Fossil SCM

The "fossil merge-info --tk" command appears to be working. Probably there are still undiscovered bugs.

drh 2024-12-03 20:37 merge-enhancements
Commit a199d970a551972ef57a26693c1cac8492ae0233a751092f811369c345587625
2 files changed +92 -12 +53 -55
+92 -12
--- src/merge.c
+++ src/merge.c
@@ -25,35 +25,112 @@
2525
2626
/*
2727
** Bring up a Tcl/Tk GUI to show details of the most recent merge.
2828
*/
2929
static void merge_info_tk(int bDark, int nContext){
30
- fossil_fatal("Not yet implemented");
30
+ int i;
31
+ Blob script;
32
+ const char *zTempFile = 0;
33
+ char *zCmd;
34
+ const char *zTclsh;
35
+ zTclsh = find_option("tclsh",0,1);
36
+ if( zTclsh==0 ){
37
+ zTclsh = db_get("tclsh",0);
38
+ }
39
+ /* The undocumented --script FILENAME option causes the Tk script to
40
+ ** be written into the FILENAME instead of being run. This is used
41
+ ** for testing and debugging. */
42
+ zTempFile = find_option("script",0,1);
43
+ verify_all_options();
44
+
45
+ blob_zero(&script);
46
+ blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info -tcl }\n",
47
+ g.nameOfExe);
48
+ blob_appendf(&script, "set filelist [list");
49
+ if( g.argc==2 ){
50
+ /* No files named on the command-line. Use every file mentioned
51
+ ** in the MERGESTAT table to generate the file list. */
52
+ Stmt q;
53
+ db_prepare(&q,
54
+ "SELECT coalesce(fnr,fn) FROM mergestat ORDER BY 1"
55
+ );
56
+ while( db_step(&q)==SQLITE_ROW ){
57
+ blob_append_char(&script, ' ');
58
+ blob_append_tcl_literal(&script, db_column_text(&q,0),
59
+ db_column_bytes(&q,0));
60
+ }
61
+ }else{
62
+ /* Use only files named on the command-line in the file list.
63
+ ** But verify each file named is actually found in the MERGESTAT
64
+ ** table first. */
65
+ for(i=2; i<g.argc; i++){
66
+ char *zFile; /* Input filename */
67
+ char *zTreename; /* Name of the file in the tree */
68
+ Blob fname; /* Filename relative to root */
69
+ zFile = mprintf("%/", g.argv[i]);
70
+ file_tree_name(zFile, &fname, 0, 1);
71
+ zTreename = blob_str(&fname);
72
+ if( !db_exists("SELECT 1 FROM mergestat WHERE fn=%Q OR fnr=%Q",
73
+ zTreename, zTreename) ){
74
+ fossil_fatal("file \"%s\" is not part of the most recent merge",
75
+ g.argv[i]);
76
+ }
77
+ blob_append_char(&script, ' ');
78
+ fossil_free(zFile);
79
+ blob_append_tcl_literal(&script, zTreename, (int)strlen(zTreename));
80
+ blob_reset(&fname);
81
+ }
82
+ }
83
+ blob_appendf(&script, "]\n");
84
+ blob_appendf(&script, "set darkmode %d\n", bDark!=0);
85
+ blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
86
+ if( zTempFile ){
87
+ blob_write_to_file(&script, zTempFile);
88
+ fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
89
+ }else{
90
+#if defined(FOSSIL_ENABLE_TCL)
91
+ Th_FossilInit(TH_INIT_DEFAULT);
92
+ if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
93
+ blob_size(&script), 1, 1, 0)==TCL_OK ){
94
+ blob_reset(&script);
95
+ return;
96
+ }
97
+ /*
98
+ * If evaluation of the Tcl script fails, the reason may be that Tk
99
+ * could not be found by the loaded Tcl, or that Tcl cannot be loaded
100
+ * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
101
+ * to using the external "tclsh", if available.
102
+ */
103
+#endif
104
+ zTempFile = write_blob_to_temp_file(&script);
105
+ zCmd = mprintf("%$ %$", zTclsh, zTempFile);
106
+ fossil_system(zCmd);
107
+ file_delete(zTempFile);
108
+ fossil_free(zCmd);
109
+ }
110
+ blob_reset(&script);
31111
}
32112
33113
/*
34114
** Generate a TCL list on standard output that can be fed into the
35115
** merge.tcl script to show the details of the most recent merge
36
-** command associated with file "zFName".
116
+** command associated with file "zFName". zFName must be the filename
117
+** relative to the root of the check-in - in other words a "tree name".
37118
**
38119
** When this routine is called, we know that the mergestat table
39120
** exists, but we do not know if zFName is mentioned in that table.
40121
*/
41122
static void merge_info_tcl(const char *zFName, int nContext){
42
- char *zFile; /* Normalized filename */
43
- char *zTreename; /* Name of the file in the tree */
44
- Blob fname; /* Filename relative to root */
123
+ const char *zTreename;/* Name of the file in the tree */
45124
Stmt q; /* To query the MERGESTAT table */
46125
MergeBuilder mb; /* The merge builder object */
47126
Blob pivot,v1,v2,out; /* Blobs for holding content */
48127
const char *zFN; /* A filename */
49128
int rid; /* RID value */
50129
int sz; /* File size value */
51130
52
- zFile = mprintf("%/", zFName);
53
- file_tree_name(zFile, &fname, 0, 1);
54
- zTreename = blob_str(&fname);
131
+ zTreename = zFName;
55132
db_prepare(&q,
56133
/* 0 1 2 3 4 5 6 7 */
57134
"SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr"
58135
" FROM mergestat"
59136
" WHERE fnp=%Q OR fnr=%Q",
@@ -164,11 +241,12 @@
164241
** with negative N meaning show all content. Only
165242
** meaningful in combination with --tcl or --tk.
166243
** --dark Use dark mode for the Tcl/Tk-based GUI
167244
** --tcl FILE Generate (to stdout) a TCL list containing
168245
** information needed to display the changes to
169
-** FILE caused by the most recent merge.
246
+** FILE caused by the most recent merge. FILE must
247
+** be a pathname relative to the root of the check-out.
170248
** --tk Bring up a Tcl/Tk GUI that shows the changes
171249
** associated with the most recent merge.
172250
**
173251
*/
174252
void merge_info_cmd(void){
@@ -182,13 +260,15 @@
182260
db_must_be_within_tree();
183261
zTcl = find_option("tcl", 0, 1);
184262
bTk = find_option("tk", 0, 0)!=0;
185263
zCnt = find_option("context", "c", 1);
186264
bDark = find_option("dark", 0, 0)!=0;
187
- verify_all_options();
188
- if( g.argc>2 ){
189
- usage("[OPTIONS]");
265
+ if( bTk==0 ){
266
+ verify_all_options();
267
+ if( g.argc>2 ){
268
+ usage("[OPTIONS]");
269
+ }
190270
}
191271
if( zCnt ){
192272
nContext = atoi(zCnt);
193273
if( nContext<0 ) nContext = 0xfffffff;
194274
}else{
195275
--- src/merge.c
+++ src/merge.c
@@ -25,35 +25,112 @@
25
26 /*
27 ** Bring up a Tcl/Tk GUI to show details of the most recent merge.
28 */
29 static void merge_info_tk(int bDark, int nContext){
30 fossil_fatal("Not yet implemented");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31 }
32
33 /*
34 ** Generate a TCL list on standard output that can be fed into the
35 ** merge.tcl script to show the details of the most recent merge
36 ** command associated with file "zFName".
 
37 **
38 ** When this routine is called, we know that the mergestat table
39 ** exists, but we do not know if zFName is mentioned in that table.
40 */
41 static void merge_info_tcl(const char *zFName, int nContext){
42 char *zFile; /* Normalized filename */
43 char *zTreename; /* Name of the file in the tree */
44 Blob fname; /* Filename relative to root */
45 Stmt q; /* To query the MERGESTAT table */
46 MergeBuilder mb; /* The merge builder object */
47 Blob pivot,v1,v2,out; /* Blobs for holding content */
48 const char *zFN; /* A filename */
49 int rid; /* RID value */
50 int sz; /* File size value */
51
52 zFile = mprintf("%/", zFName);
53 file_tree_name(zFile, &fname, 0, 1);
54 zTreename = blob_str(&fname);
55 db_prepare(&q,
56 /* 0 1 2 3 4 5 6 7 */
57 "SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr"
58 " FROM mergestat"
59 " WHERE fnp=%Q OR fnr=%Q",
@@ -164,11 +241,12 @@
164 ** with negative N meaning show all content. Only
165 ** meaningful in combination with --tcl or --tk.
166 ** --dark Use dark mode for the Tcl/Tk-based GUI
167 ** --tcl FILE Generate (to stdout) a TCL list containing
168 ** information needed to display the changes to
169 ** FILE caused by the most recent merge.
 
170 ** --tk Bring up a Tcl/Tk GUI that shows the changes
171 ** associated with the most recent merge.
172 **
173 */
174 void merge_info_cmd(void){
@@ -182,13 +260,15 @@
182 db_must_be_within_tree();
183 zTcl = find_option("tcl", 0, 1);
184 bTk = find_option("tk", 0, 0)!=0;
185 zCnt = find_option("context", "c", 1);
186 bDark = find_option("dark", 0, 0)!=0;
187 verify_all_options();
188 if( g.argc>2 ){
189 usage("[OPTIONS]");
 
 
190 }
191 if( zCnt ){
192 nContext = atoi(zCnt);
193 if( nContext<0 ) nContext = 0xfffffff;
194 }else{
195
--- src/merge.c
+++ src/merge.c
@@ -25,35 +25,112 @@
25
26 /*
27 ** Bring up a Tcl/Tk GUI to show details of the most recent merge.
28 */
29 static void merge_info_tk(int bDark, int nContext){
30 int i;
31 Blob script;
32 const char *zTempFile = 0;
33 char *zCmd;
34 const char *zTclsh;
35 zTclsh = find_option("tclsh",0,1);
36 if( zTclsh==0 ){
37 zTclsh = db_get("tclsh",0);
38 }
39 /* The undocumented --script FILENAME option causes the Tk script to
40 ** be written into the FILENAME instead of being run. This is used
41 ** for testing and debugging. */
42 zTempFile = find_option("script",0,1);
43 verify_all_options();
44
45 blob_zero(&script);
46 blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info -tcl }\n",
47 g.nameOfExe);
48 blob_appendf(&script, "set filelist [list");
49 if( g.argc==2 ){
50 /* No files named on the command-line. Use every file mentioned
51 ** in the MERGESTAT table to generate the file list. */
52 Stmt q;
53 db_prepare(&q,
54 "SELECT coalesce(fnr,fn) FROM mergestat ORDER BY 1"
55 );
56 while( db_step(&q)==SQLITE_ROW ){
57 blob_append_char(&script, ' ');
58 blob_append_tcl_literal(&script, db_column_text(&q,0),
59 db_column_bytes(&q,0));
60 }
61 }else{
62 /* Use only files named on the command-line in the file list.
63 ** But verify each file named is actually found in the MERGESTAT
64 ** table first. */
65 for(i=2; i<g.argc; i++){
66 char *zFile; /* Input filename */
67 char *zTreename; /* Name of the file in the tree */
68 Blob fname; /* Filename relative to root */
69 zFile = mprintf("%/", g.argv[i]);
70 file_tree_name(zFile, &fname, 0, 1);
71 zTreename = blob_str(&fname);
72 if( !db_exists("SELECT 1 FROM mergestat WHERE fn=%Q OR fnr=%Q",
73 zTreename, zTreename) ){
74 fossil_fatal("file \"%s\" is not part of the most recent merge",
75 g.argv[i]);
76 }
77 blob_append_char(&script, ' ');
78 fossil_free(zFile);
79 blob_append_tcl_literal(&script, zTreename, (int)strlen(zTreename));
80 blob_reset(&fname);
81 }
82 }
83 blob_appendf(&script, "]\n");
84 blob_appendf(&script, "set darkmode %d\n", bDark!=0);
85 blob_appendf(&script, "%s", builtin_file("merge.tcl", 0));
86 if( zTempFile ){
87 blob_write_to_file(&script, zTempFile);
88 fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile);
89 }else{
90 #if defined(FOSSIL_ENABLE_TCL)
91 Th_FossilInit(TH_INIT_DEFAULT);
92 if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script),
93 blob_size(&script), 1, 1, 0)==TCL_OK ){
94 blob_reset(&script);
95 return;
96 }
97 /*
98 * If evaluation of the Tcl script fails, the reason may be that Tk
99 * could not be found by the loaded Tcl, or that Tcl cannot be loaded
100 * dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback
101 * to using the external "tclsh", if available.
102 */
103 #endif
104 zTempFile = write_blob_to_temp_file(&script);
105 zCmd = mprintf("%$ %$", zTclsh, zTempFile);
106 fossil_system(zCmd);
107 file_delete(zTempFile);
108 fossil_free(zCmd);
109 }
110 blob_reset(&script);
111 }
112
113 /*
114 ** Generate a TCL list on standard output that can be fed into the
115 ** merge.tcl script to show the details of the most recent merge
116 ** command associated with file "zFName". zFName must be the filename
117 ** relative to the root of the check-in - in other words a "tree name".
118 **
119 ** When this routine is called, we know that the mergestat table
120 ** exists, but we do not know if zFName is mentioned in that table.
121 */
122 static void merge_info_tcl(const char *zFName, int nContext){
123 const char *zTreename;/* Name of the file in the tree */
 
 
124 Stmt q; /* To query the MERGESTAT table */
125 MergeBuilder mb; /* The merge builder object */
126 Blob pivot,v1,v2,out; /* Blobs for holding content */
127 const char *zFN; /* A filename */
128 int rid; /* RID value */
129 int sz; /* File size value */
130
131 zTreename = zFName;
 
 
132 db_prepare(&q,
133 /* 0 1 2 3 4 5 6 7 */
134 "SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr"
135 " FROM mergestat"
136 " WHERE fnp=%Q OR fnr=%Q",
@@ -164,11 +241,12 @@
241 ** with negative N meaning show all content. Only
242 ** meaningful in combination with --tcl or --tk.
243 ** --dark Use dark mode for the Tcl/Tk-based GUI
244 ** --tcl FILE Generate (to stdout) a TCL list containing
245 ** information needed to display the changes to
246 ** FILE caused by the most recent merge. FILE must
247 ** be a pathname relative to the root of the check-out.
248 ** --tk Bring up a Tcl/Tk GUI that shows the changes
249 ** associated with the most recent merge.
250 **
251 */
252 void merge_info_cmd(void){
@@ -182,13 +260,15 @@
260 db_must_be_within_tree();
261 zTcl = find_option("tcl", 0, 1);
262 bTk = find_option("tk", 0, 0)!=0;
263 zCnt = find_option("context", "c", 1);
264 bDark = find_option("dark", 0, 0)!=0;
265 if( bTk==0 ){
266 verify_all_options();
267 if( g.argc>2 ){
268 usage("[OPTIONS]");
269 }
270 }
271 if( zCnt ){
272 nContext = atoi(zCnt);
273 if( nContext<0 ) nContext = 0xfffffff;
274 }else{
275
+53 -55
--- src/merge.tcl
+++ src/merge.tcl
@@ -81,27 +81,17 @@
8181
proc colType {c} {
8282
regexp {[a-z]+} $c type
8383
return $type
8484
}
8585
86
-proc getLine {mergetxt N iivar} {
87
- upvar $iivar ii
88
- if {$ii>=$N} {return -1}
89
- set x [lindex $mergetxt $ii]
90
- incr ii
91
- return $x
92
-}
93
-
9486
proc readMerge {fossilcmd} {
95
- global mergetxt
96
- if {![info exists mergetxt]} {
97
- set in [open $fossilcmd r]
98
- fconfigure $in -encoding utf-8
99
- set mergetxt [read $in]
100
- close $in
101
- }
87
+ set in [open $fossilcmd r]
88
+ fconfigure $in -encoding utf-8
89
+ set mergetxt [read $in]
90
+ close $in
10291
foreach c [cols] {
92
+ $c config -state normal
10393
$c delete 1.0 end
10494
}
10595
set lnA 1
10696
set lnB 1
10797
set lnC 1
@@ -318,48 +308,50 @@
318308
bind . <$key> "scroll-$axis $args; break"
319309
bind . <Shift-$key> continue
320310
}
321311
322312
frame .bb
323
-::ttk::menubutton .bb.files -text "Files"
324
-if {[tk windowingsystem] eq "win32"} {
325
- ::ttk::style theme use winnative
326
- .bb.files configure -padding {20 1 10 2}
327
-}
328
-toplevel .wfiles
329
-wm withdraw .wfiles
330
-update idletasks
331
-wm transient .wfiles .
332
-wm overrideredirect .wfiles 1
333
-listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \
334
- -yscroll {.wfiles.sb set}
335
-::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
336
-grid .wfiles.lb .wfiles.sb -sticky ns
337
-bind .bb.files <1> {
338
- set x [winfo rootx %W]
339
- set y [expr {[winfo rooty %W]+[winfo height %W]}]
340
- wm geometry .wfiles +$x+$y
341
- wm deiconify .wfiles
342
- focus .wfiles.lb
343
-}
344
-bind .wfiles <FocusOut> {wm withdraw .wfiles}
345
-bind .wfiles <Escape> {focus .}
346
-foreach evt {1 Return} {
347
- bind .wfiles.lb <$evt> {
348
- catch {
349
- set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]]
350
- viewDiff $idx
351
- }
352
- focus .
353
- break
354
- }
355
-}
356
-bind .wfiles.lb <Motion> {
357
- %W selection clear 0 end
358
- %W selection set @%x,%y
359
-}
360
-
313
+if {[info exists filelist]} {
314
+ ::ttk::menubutton .bb.files -text "Files"
315
+ if {[tk windowingsystem] eq "win32"} {
316
+ ::ttk::style theme use winnative
317
+ .bb.files configure -padding {20 1 10 2}
318
+ }
319
+ toplevel .wfiles
320
+ wm withdraw .wfiles
321
+ update idletasks
322
+ wm transient .wfiles .
323
+ wm overrideredirect .wfiles 1
324
+ set ht [llength $filelist]
325
+ if {$ht>$CFG(LB_HEIGHT)} {set ht $CFG(LB_HEIGHT)}
326
+ listbox .wfiles.lb -width 0 -height $ht -activestyle none \
327
+ -yscroll {.wfiles.sb set}
328
+ .wfiles.lb insert end {*}$filelist
329
+ ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
330
+ grid .wfiles.lb .wfiles.sb -sticky ns
331
+ bind .bb.files <1> {
332
+ set x [winfo rootx %W]
333
+ set y [expr {[winfo rooty %W]+[winfo height %W]}]
334
+ wm geometry .wfiles +$x+$y
335
+ wm deiconify .wfiles
336
+ focus .wfiles.lb
337
+ }
338
+ bind .wfiles <FocusOut> {wm withdraw .wfiles}
339
+ bind .wfiles <Escape> {focus .}
340
+ foreach evt {1 Return} {
341
+ bind .wfiles.lb <$evt> {
342
+ readMerge "$::fossilcmd [list [lindex $::filelist [%W curselection]]]"
343
+ focus .
344
+ break
345
+ }
346
+ }
347
+ bind .wfiles.lb <Motion> {
348
+ %W selection clear 0 end
349
+ %W selection set @%x,%y
350
+ }
351
+}
352
+
361353
362354
foreach {side syncCol} {A .txtB B .txtA C .txtC D .txtD} {
363355
set ln .ln$side
364356
text $ln
365357
$ln tag config - -justify right
@@ -401,11 +393,15 @@
401393
::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
402394
::ttk::scrollbar .sbxC -command {.txtC xview} -orient horizontal
403395
::ttk::scrollbar .sbxD -command {.txtD xview} -orient horizontal
404396
frame .spacer
405397
406
-readMerge $fossilcmd
398
+if {[info exists filelist]} {
399
+ readMerge "$fossilcmd [list [lindex $filelist 0]]"
400
+} else {
401
+ readMerge $fossilcmd
402
+}
407403
update idletasks
408404
409405
proc searchOnOff {} {
410406
if {[info exists ::search]} {
411407
unset ::search
@@ -481,11 +477,13 @@
481477
set ::search $w
482478
}
483479
::ttk::button .bb.quit -text {Quit} -command exit
484480
::ttk::button .bb.search -text {Search} -command searchOnOff
485481
pack .bb.quit -side left
486
-# pack .bb.files -side left
482
+if {[info exists filelist]} {
483
+ pack .bb.files -side left
484
+}
487485
pack .bb.search -side left
488486
grid rowconfigure . 1 -weight 1
489487
set rn 0
490488
foreach {lnwid txtwid} [cols] {
491489
grid columnconfigure . $rn -weight 1 -uniform a
492490
--- src/merge.tcl
+++ src/merge.tcl
@@ -81,27 +81,17 @@
81 proc colType {c} {
82 regexp {[a-z]+} $c type
83 return $type
84 }
85
86 proc getLine {mergetxt N iivar} {
87 upvar $iivar ii
88 if {$ii>=$N} {return -1}
89 set x [lindex $mergetxt $ii]
90 incr ii
91 return $x
92 }
93
94 proc readMerge {fossilcmd} {
95 global mergetxt
96 if {![info exists mergetxt]} {
97 set in [open $fossilcmd r]
98 fconfigure $in -encoding utf-8
99 set mergetxt [read $in]
100 close $in
101 }
102 foreach c [cols] {
 
103 $c delete 1.0 end
104 }
105 set lnA 1
106 set lnB 1
107 set lnC 1
@@ -318,48 +308,50 @@
318 bind . <$key> "scroll-$axis $args; break"
319 bind . <Shift-$key> continue
320 }
321
322 frame .bb
323 ::ttk::menubutton .bb.files -text "Files"
324 if {[tk windowingsystem] eq "win32"} {
325 ::ttk::style theme use winnative
326 .bb.files configure -padding {20 1 10 2}
327 }
328 toplevel .wfiles
329 wm withdraw .wfiles
330 update idletasks
331 wm transient .wfiles .
332 wm overrideredirect .wfiles 1
333 listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \
334 -yscroll {.wfiles.sb set}
335 ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
336 grid .wfiles.lb .wfiles.sb -sticky ns
337 bind .bb.files <1> {
338 set x [winfo rootx %W]
339 set y [expr {[winfo rooty %W]+[winfo height %W]}]
340 wm geometry .wfiles +$x+$y
341 wm deiconify .wfiles
342 focus .wfiles.lb
343 }
344 bind .wfiles <FocusOut> {wm withdraw .wfiles}
345 bind .wfiles <Escape> {focus .}
346 foreach evt {1 Return} {
347 bind .wfiles.lb <$evt> {
348 catch {
349 set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]]
350 viewDiff $idx
351 }
352 focus .
353 break
354 }
355 }
356 bind .wfiles.lb <Motion> {
357 %W selection clear 0 end
358 %W selection set @%x,%y
359 }
360
 
 
361
362 foreach {side syncCol} {A .txtB B .txtA C .txtC D .txtD} {
363 set ln .ln$side
364 text $ln
365 $ln tag config - -justify right
@@ -401,11 +393,15 @@
401 ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
402 ::ttk::scrollbar .sbxC -command {.txtC xview} -orient horizontal
403 ::ttk::scrollbar .sbxD -command {.txtD xview} -orient horizontal
404 frame .spacer
405
406 readMerge $fossilcmd
 
 
 
 
407 update idletasks
408
409 proc searchOnOff {} {
410 if {[info exists ::search]} {
411 unset ::search
@@ -481,11 +477,13 @@
481 set ::search $w
482 }
483 ::ttk::button .bb.quit -text {Quit} -command exit
484 ::ttk::button .bb.search -text {Search} -command searchOnOff
485 pack .bb.quit -side left
486 # pack .bb.files -side left
 
 
487 pack .bb.search -side left
488 grid rowconfigure . 1 -weight 1
489 set rn 0
490 foreach {lnwid txtwid} [cols] {
491 grid columnconfigure . $rn -weight 1 -uniform a
492
--- src/merge.tcl
+++ src/merge.tcl
@@ -81,27 +81,17 @@
81 proc colType {c} {
82 regexp {[a-z]+} $c type
83 return $type
84 }
85
 
 
 
 
 
 
 
 
86 proc readMerge {fossilcmd} {
87 set in [open $fossilcmd r]
88 fconfigure $in -encoding utf-8
89 set mergetxt [read $in]
90 close $in
 
 
 
91 foreach c [cols] {
92 $c config -state normal
93 $c delete 1.0 end
94 }
95 set lnA 1
96 set lnB 1
97 set lnC 1
@@ -318,48 +308,50 @@
308 bind . <$key> "scroll-$axis $args; break"
309 bind . <Shift-$key> continue
310 }
311
312 frame .bb
313 if {[info exists filelist]} {
314 ::ttk::menubutton .bb.files -text "Files"
315 if {[tk windowingsystem] eq "win32"} {
316 ::ttk::style theme use winnative
317 .bb.files configure -padding {20 1 10 2}
318 }
319 toplevel .wfiles
320 wm withdraw .wfiles
321 update idletasks
322 wm transient .wfiles .
323 wm overrideredirect .wfiles 1
324 set ht [llength $filelist]
325 if {$ht>$CFG(LB_HEIGHT)} {set ht $CFG(LB_HEIGHT)}
326 listbox .wfiles.lb -width 0 -height $ht -activestyle none \
327 -yscroll {.wfiles.sb set}
328 .wfiles.lb insert end {*}$filelist
329 ::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview}
330 grid .wfiles.lb .wfiles.sb -sticky ns
331 bind .bb.files <1> {
332 set x [winfo rootx %W]
333 set y [expr {[winfo rooty %W]+[winfo height %W]}]
334 wm geometry .wfiles +$x+$y
335 wm deiconify .wfiles
336 focus .wfiles.lb
337 }
338 bind .wfiles <FocusOut> {wm withdraw .wfiles}
339 bind .wfiles <Escape> {focus .}
340 foreach evt {1 Return} {
341 bind .wfiles.lb <$evt> {
342 readMerge "$::fossilcmd [list [lindex $::filelist [%W curselection]]]"
343 focus .
344 break
345 }
346 }
347 bind .wfiles.lb <Motion> {
348 %W selection clear 0 end
349 %W selection set @%x,%y
350 }
351 }
352
353
354 foreach {side syncCol} {A .txtB B .txtA C .txtC D .txtD} {
355 set ln .ln$side
356 text $ln
357 $ln tag config - -justify right
@@ -401,11 +393,15 @@
393 ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal
394 ::ttk::scrollbar .sbxC -command {.txtC xview} -orient horizontal
395 ::ttk::scrollbar .sbxD -command {.txtD xview} -orient horizontal
396 frame .spacer
397
398 if {[info exists filelist]} {
399 readMerge "$fossilcmd [list [lindex $filelist 0]]"
400 } else {
401 readMerge $fossilcmd
402 }
403 update idletasks
404
405 proc searchOnOff {} {
406 if {[info exists ::search]} {
407 unset ::search
@@ -481,11 +477,13 @@
477 set ::search $w
478 }
479 ::ttk::button .bb.quit -text {Quit} -command exit
480 ::ttk::button .bb.search -text {Search} -command searchOnOff
481 pack .bb.quit -side left
482 if {[info exists filelist]} {
483 pack .bb.files -side left
484 }
485 pack .bb.search -side left
486 grid rowconfigure . 1 -weight 1
487 set rn 0
488 foreach {lnwid txtwid} [cols] {
489 grid columnconfigure . $rn -weight 1 -uniform a
490

Keyboard Shortcuts

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