Fossil SCM
The "fossil merge-info --tk" command appears to be working. Probably there are still undiscovered bugs.
Commit
a199d970a551972ef57a26693c1cac8492ae0233a751092f811369c345587625
Parent
cbd24a2594c590a…
2 files changed
+92
-12
+53
-55
+92
-12
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -25,35 +25,112 @@ | ||
| 25 | 25 | |
| 26 | 26 | /* |
| 27 | 27 | ** Bring up a Tcl/Tk GUI to show details of the most recent merge. |
| 28 | 28 | */ |
| 29 | 29 | 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); | |
| 31 | 111 | } |
| 32 | 112 | |
| 33 | 113 | /* |
| 34 | 114 | ** Generate a TCL list on standard output that can be fed into the |
| 35 | 115 | ** 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". | |
| 37 | 118 | ** |
| 38 | 119 | ** When this routine is called, we know that the mergestat table |
| 39 | 120 | ** exists, but we do not know if zFName is mentioned in that table. |
| 40 | 121 | */ |
| 41 | 122 | 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 */ | |
| 45 | 124 | Stmt q; /* To query the MERGESTAT table */ |
| 46 | 125 | MergeBuilder mb; /* The merge builder object */ |
| 47 | 126 | Blob pivot,v1,v2,out; /* Blobs for holding content */ |
| 48 | 127 | const char *zFN; /* A filename */ |
| 49 | 128 | int rid; /* RID value */ |
| 50 | 129 | int sz; /* File size value */ |
| 51 | 130 | |
| 52 | - zFile = mprintf("%/", zFName); | |
| 53 | - file_tree_name(zFile, &fname, 0, 1); | |
| 54 | - zTreename = blob_str(&fname); | |
| 131 | + zTreename = zFName; | |
| 55 | 132 | db_prepare(&q, |
| 56 | 133 | /* 0 1 2 3 4 5 6 7 */ |
| 57 | 134 | "SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr" |
| 58 | 135 | " FROM mergestat" |
| 59 | 136 | " WHERE fnp=%Q OR fnr=%Q", |
| @@ -164,11 +241,12 @@ | ||
| 164 | 241 | ** with negative N meaning show all content. Only |
| 165 | 242 | ** meaningful in combination with --tcl or --tk. |
| 166 | 243 | ** --dark Use dark mode for the Tcl/Tk-based GUI |
| 167 | 244 | ** --tcl FILE Generate (to stdout) a TCL list containing |
| 168 | 245 | ** 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. | |
| 170 | 248 | ** --tk Bring up a Tcl/Tk GUI that shows the changes |
| 171 | 249 | ** associated with the most recent merge. |
| 172 | 250 | ** |
| 173 | 251 | */ |
| 174 | 252 | void merge_info_cmd(void){ |
| @@ -182,13 +260,15 @@ | ||
| 182 | 260 | db_must_be_within_tree(); |
| 183 | 261 | zTcl = find_option("tcl", 0, 1); |
| 184 | 262 | bTk = find_option("tk", 0, 0)!=0; |
| 185 | 263 | zCnt = find_option("context", "c", 1); |
| 186 | 264 | 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 | + } | |
| 190 | 270 | } |
| 191 | 271 | if( zCnt ){ |
| 192 | 272 | nContext = atoi(zCnt); |
| 193 | 273 | if( nContext<0 ) nContext = 0xfffffff; |
| 194 | 274 | }else{ |
| 195 | 275 |
| --- 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 @@ | ||
| 81 | 81 | proc colType {c} { |
| 82 | 82 | regexp {[a-z]+} $c type |
| 83 | 83 | return $type |
| 84 | 84 | } |
| 85 | 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 | 86 | 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 | |
| 102 | 91 | foreach c [cols] { |
| 92 | + $c config -state normal | |
| 103 | 93 | $c delete 1.0 end |
| 104 | 94 | } |
| 105 | 95 | set lnA 1 |
| 106 | 96 | set lnB 1 |
| 107 | 97 | set lnC 1 |
| @@ -318,48 +308,50 @@ | ||
| 318 | 308 | bind . <$key> "scroll-$axis $args; break" |
| 319 | 309 | bind . <Shift-$key> continue |
| 320 | 310 | } |
| 321 | 311 | |
| 322 | 312 | 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 | + | |
| 361 | 353 | |
| 362 | 354 | foreach {side syncCol} {A .txtB B .txtA C .txtC D .txtD} { |
| 363 | 355 | set ln .ln$side |
| 364 | 356 | text $ln |
| 365 | 357 | $ln tag config - -justify right |
| @@ -401,11 +393,15 @@ | ||
| 401 | 393 | ::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal |
| 402 | 394 | ::ttk::scrollbar .sbxC -command {.txtC xview} -orient horizontal |
| 403 | 395 | ::ttk::scrollbar .sbxD -command {.txtD xview} -orient horizontal |
| 404 | 396 | frame .spacer |
| 405 | 397 | |
| 406 | -readMerge $fossilcmd | |
| 398 | +if {[info exists filelist]} { | |
| 399 | + readMerge "$fossilcmd [list [lindex $filelist 0]]" | |
| 400 | +} else { | |
| 401 | + readMerge $fossilcmd | |
| 402 | +} | |
| 407 | 403 | update idletasks |
| 408 | 404 | |
| 409 | 405 | proc searchOnOff {} { |
| 410 | 406 | if {[info exists ::search]} { |
| 411 | 407 | unset ::search |
| @@ -481,11 +477,13 @@ | ||
| 481 | 477 | set ::search $w |
| 482 | 478 | } |
| 483 | 479 | ::ttk::button .bb.quit -text {Quit} -command exit |
| 484 | 480 | ::ttk::button .bb.search -text {Search} -command searchOnOff |
| 485 | 481 | pack .bb.quit -side left |
| 486 | -# pack .bb.files -side left | |
| 482 | +if {[info exists filelist]} { | |
| 483 | + pack .bb.files -side left | |
| 484 | +} | |
| 487 | 485 | pack .bb.search -side left |
| 488 | 486 | grid rowconfigure . 1 -weight 1 |
| 489 | 487 | set rn 0 |
| 490 | 488 | foreach {lnwid txtwid} [cols] { |
| 491 | 489 | grid columnconfigure . $rn -weight 1 -uniform a |
| 492 | 490 |
| --- 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 |