|
1
|
# The "diff --tk" command outputs prepends a "set fossilcmd {...}" line |
|
2
|
# to this file, then runs this file using "tclsh" in order to display the |
|
3
|
# graphical diff in a separate window. A typical "set fossilcmd" line |
|
4
|
# looks like this: |
|
5
|
# |
|
6
|
# set fossilcmd {| "./fossil" diff --tcl -i -v} |
|
7
|
# |
|
8
|
# This header comment is stripped off by the "mkbuiltin.c" program. |
|
9
|
# |
|
10
|
set prog { |
|
11
|
package require Tk |
|
12
|
|
|
13
|
array set CFG_light { |
|
14
|
TITLE {Fossil Diff} |
|
15
|
LN_COL_BG #dddddd |
|
16
|
LN_COL_FG #444444 |
|
17
|
TXT_COL_BG #ffffff |
|
18
|
TXT_COL_FG #000000 |
|
19
|
MKR_COL_BG #444444 |
|
20
|
MKR_COL_FG #dddddd |
|
21
|
CHNG_BG #d0d0ff |
|
22
|
ADD_BG #c0ffc0 |
|
23
|
RM_BG #ffc0c0 |
|
24
|
HR_FG #444444 |
|
25
|
HR_PAD_TOP 4 |
|
26
|
HR_PAD_BTM 8 |
|
27
|
FN_BG #444444 |
|
28
|
FN_FG #ffffff |
|
29
|
FN_PAD 5 |
|
30
|
ERR_FG #ee0000 |
|
31
|
PADX 5 |
|
32
|
WIDTH 80 |
|
33
|
HEIGHT 45 |
|
34
|
LB_HEIGHT 25 |
|
35
|
} |
|
36
|
|
|
37
|
array set CFG_dark { |
|
38
|
TITLE {Fossil Diff} |
|
39
|
LN_COL_BG #dddddd |
|
40
|
LN_COL_FG #444444 |
|
41
|
TXT_COL_BG #3f3f3f |
|
42
|
TXT_COL_FG #dcdccc |
|
43
|
MKR_COL_BG #444444 |
|
44
|
MKR_COL_FG #dddddd |
|
45
|
CHNG_BG #6a6afc |
|
46
|
ADD_BG #57934c |
|
47
|
RM_BG #ef6767 |
|
48
|
HR_FG #444444 |
|
49
|
HR_PAD_TOP 4 |
|
50
|
HR_PAD_BTM 8 |
|
51
|
FN_BG #5e5e5e |
|
52
|
FN_FG #ffffff |
|
53
|
FN_PAD 5 |
|
54
|
ERR_FG #ee0000 |
|
55
|
PADX 5 |
|
56
|
WIDTH 80 |
|
57
|
HEIGHT 45 |
|
58
|
LB_HEIGHT 25 |
|
59
|
} |
|
60
|
|
|
61
|
array set CFG_arr { |
|
62
|
0 CFG_light |
|
63
|
1 CFG_dark |
|
64
|
} |
|
65
|
|
|
66
|
array set CFG [array get $CFG_arr($darkmode)] |
|
67
|
|
|
68
|
if {![namespace exists ttk]} { |
|
69
|
interp alias {} ::ttk::scrollbar {} ::scrollbar |
|
70
|
interp alias {} ::ttk::menubutton {} ::menubutton |
|
71
|
} |
|
72
|
|
|
73
|
proc dehtml {x} { |
|
74
|
set x [regsub -all {<[^>]*>} $x {}] |
|
75
|
return [string map {& & < < > > ' ' " \"} $x] |
|
76
|
} |
|
77
|
|
|
78
|
proc cols {} { |
|
79
|
return [list .lnA .txtA .mkr .lnB .txtB] |
|
80
|
} |
|
81
|
|
|
82
|
proc colType {c} { |
|
83
|
regexp {[a-z]+} $c type |
|
84
|
return $type |
|
85
|
} |
|
86
|
|
|
87
|
proc getLine {difftxt N iivar} { |
|
88
|
upvar $iivar ii |
|
89
|
if {$ii>=$N} {return -1} |
|
90
|
set x [lindex $difftxt $ii] |
|
91
|
incr ii |
|
92
|
return $x |
|
93
|
} |
|
94
|
|
|
95
|
proc reloadDiff {} { |
|
96
|
global fossilcmd difftxt |
|
97
|
unset -nocomplain difftxt |
|
98
|
set idx [.txtA index @0,0] |
|
99
|
readDiffs $fossilcmd 1 |
|
100
|
update |
|
101
|
viewDiff $idx |
|
102
|
} |
|
103
|
|
|
104
|
proc readDiffs {fossilcmd redo} { |
|
105
|
global difftxt debug |
|
106
|
if {![info exists difftxt]} { |
|
107
|
if {$debug} { |
|
108
|
puts "# [list open $fossilcmd r]" |
|
109
|
flush stdout |
|
110
|
} |
|
111
|
if {[catch { |
|
112
|
set in [open $fossilcmd r] |
|
113
|
fconfigure $in -encoding utf-8 |
|
114
|
set difftxt [split [read $in] \n] |
|
115
|
close $in |
|
116
|
} msg]} { |
|
117
|
if {$redo} { |
|
118
|
tk_messageBox -type ok -title Error -message "Unable to refresh:\n$msg" |
|
119
|
return 0 |
|
120
|
} else { |
|
121
|
puts $msg |
|
122
|
exit 1 |
|
123
|
} |
|
124
|
} |
|
125
|
} |
|
126
|
set N [llength $difftxt] |
|
127
|
set ii 0 |
|
128
|
set nDiffs 0 |
|
129
|
set n1 0 |
|
130
|
set n2 0 |
|
131
|
array set widths {txt 3 ln 3 mkr 1} |
|
132
|
if {$redo} { |
|
133
|
foreach c [cols] {$c config -state normal} |
|
134
|
.lnA delete 1.0 end |
|
135
|
.txtA delete 1.0 end |
|
136
|
.lnB delete 1.0 end |
|
137
|
.txtB delete 1.0 end |
|
138
|
.mkr delete 1.0 end |
|
139
|
.wfiles.lb delete 0 end |
|
140
|
} |
|
141
|
|
|
142
|
|
|
143
|
set fromIndex [lsearch -glob $fossilcmd *-from] |
|
144
|
set toIndex [lsearch -glob $fossilcmd *-to] |
|
145
|
set branchIndex [lsearch -glob $fossilcmd *-branch] |
|
146
|
set checkinIndex [lsearch -glob $fossilcmd *-checkin] |
|
147
|
if {[lsearch -glob $fossilcmd *-label]>=0 |
|
148
|
|| [lsearch {xdiff fdiff merge-info} [lindex $fossilcmd 2]]>=0 |
|
149
|
} { |
|
150
|
set fA {} |
|
151
|
set fB {} |
|
152
|
} else { |
|
153
|
if {[string match *?--external-baseline* $fossilcmd]} { |
|
154
|
set fA {external baseline} |
|
155
|
} else { |
|
156
|
set fA {base check-in} |
|
157
|
} |
|
158
|
set fB {current check-out} |
|
159
|
if {$fromIndex > -1} { |
|
160
|
set fA [lindex $fossilcmd $fromIndex+1] |
|
161
|
} |
|
162
|
if {$toIndex > -1} { |
|
163
|
set fB [lindex $fossilcmd $toIndex+1] |
|
164
|
} |
|
165
|
if {$branchIndex > -1} { |
|
166
|
set fA "branch point"; set fB "leaf of branch '[lindex $fossilcmd $branchIndex+1]'" |
|
167
|
} |
|
168
|
if {$checkinIndex > -1} { |
|
169
|
set fA "primary parent"; set fB [lindex $fossilcmd $checkinIndex+1] |
|
170
|
} |
|
171
|
} |
|
172
|
|
|
173
|
while {[set line [getLine $difftxt $N ii]] != -1} { |
|
174
|
switch -- [lindex $line 0] { |
|
175
|
FILE { |
|
176
|
incr nDiffs |
|
177
|
foreach wx [list [string length $n1] [string length $n2]] { |
|
178
|
if {$wx>$widths(ln)} {set widths(ln) $wx} |
|
179
|
} |
|
180
|
.lnA insert end \n fn \n - |
|
181
|
if {$fA==""} { |
|
182
|
.txtA insert end "[lindex $line 1]\n" fn \n - |
|
183
|
} else { |
|
184
|
.txtA insert end "[lindex $line 1] ($fA)\n" fn \n - |
|
185
|
} |
|
186
|
.mkr insert end \n fn \n - |
|
187
|
.lnB insert end \n fn \n - |
|
188
|
if {$fB==""} { |
|
189
|
.txtB insert end "[lindex $line 2]\n" fn \n - |
|
190
|
} else { |
|
191
|
.txtB insert end "[lindex $line 2] ($fB)\n" fn \n - |
|
192
|
} |
|
193
|
.wfiles.lb insert end [lindex $line 2] |
|
194
|
set n1 0 |
|
195
|
set n2 0 |
|
196
|
} |
|
197
|
SKIP { |
|
198
|
set n [lindex $line 1] |
|
199
|
incr n1 $n |
|
200
|
incr n2 $n |
|
201
|
.lnA insert end ...\n hrln |
|
202
|
.txtA insert end [string repeat . 30]\n hrtxt |
|
203
|
.mkr insert end \n hrln |
|
204
|
.lnB insert end ...\n hrln |
|
205
|
.txtB insert end [string repeat . 30]\n hrtxt |
|
206
|
} |
|
207
|
COM { |
|
208
|
set x [lindex $line 1] |
|
209
|
incr n1 |
|
210
|
incr n2 |
|
211
|
.lnA insert end $n1\n - |
|
212
|
.txtA insert end $x\n - |
|
213
|
.mkr insert end \n - |
|
214
|
.lnB insert end $n2\n - |
|
215
|
.txtB insert end $x\n - |
|
216
|
} |
|
217
|
INS { |
|
218
|
set x [lindex $line 1] |
|
219
|
incr n2 |
|
220
|
.lnA insert end \n - |
|
221
|
.txtA insert end \n - |
|
222
|
.mkr insert end >\n - |
|
223
|
.lnB insert end $n2\n - |
|
224
|
.txtB insert end $x add \n - |
|
225
|
} |
|
226
|
DEL { |
|
227
|
set x [lindex $line 1] |
|
228
|
incr n1 |
|
229
|
.lnA insert end $n1\n - |
|
230
|
.txtA insert end $x rm \n - |
|
231
|
.mkr insert end <\n - |
|
232
|
.lnB insert end \n - |
|
233
|
.txtB insert end \n - |
|
234
|
} |
|
235
|
EDIT { |
|
236
|
incr n1 |
|
237
|
incr n2 |
|
238
|
.lnA insert end $n1\n - |
|
239
|
.lnB insert end $n2\n - |
|
240
|
.mkr insert end |\n - |
|
241
|
set nn [llength $line] |
|
242
|
for {set i 1} {$i<$nn} {incr i 3} { |
|
243
|
set x [lindex $line $i] |
|
244
|
if {$x ne ""} { |
|
245
|
.txtA insert end $x - |
|
246
|
.txtB insert end $x - |
|
247
|
} |
|
248
|
if {$i+2<$nn} { |
|
249
|
set x1 [lindex $line [expr {$i+1}]] |
|
250
|
set x2 [lindex $line [expr {$i+2}]] |
|
251
|
if {"$x1" eq ""} { |
|
252
|
.txtB insert end $x2 add |
|
253
|
} elseif {"$x2" eq ""} { |
|
254
|
.txtA insert end $x1 rm |
|
255
|
} else { |
|
256
|
.txtA insert end $x1 chng |
|
257
|
.txtB insert end $x2 chng |
|
258
|
} |
|
259
|
} |
|
260
|
} |
|
261
|
.txtA insert end \n - |
|
262
|
.txtB insert end \n - |
|
263
|
} |
|
264
|
"" { |
|
265
|
foreach wx [list [string length $n1] [string length $n2]] { |
|
266
|
if {$wx>$widths(ln)} {set widths(ln) $wx} |
|
267
|
} |
|
268
|
} |
|
269
|
default { |
|
270
|
.lnA insert end \n - |
|
271
|
.txtA insert end $line\n err |
|
272
|
.mkr insert end \n - |
|
273
|
.lnB insert end \n - |
|
274
|
.txtB insert end $line\n err |
|
275
|
} |
|
276
|
} |
|
277
|
} |
|
278
|
|
|
279
|
foreach c [cols] { |
|
280
|
set type [colType $c] |
|
281
|
if {$type ne "txt"} { |
|
282
|
$c config -width $widths($type) |
|
283
|
} |
|
284
|
$c config -state disabled |
|
285
|
} |
|
286
|
.wfiles.lb config -height $nDiffs |
|
287
|
if {$nDiffs <= [.wfiles.lb cget -height]} { |
|
288
|
grid remove .wfiles.sb |
|
289
|
} |
|
290
|
|
|
291
|
return $nDiffs |
|
292
|
} |
|
293
|
|
|
294
|
proc viewDiff {idx} { |
|
295
|
.txtA yview $idx |
|
296
|
.txtA xview moveto 0 |
|
297
|
} |
|
298
|
|
|
299
|
proc cycleDiffs {{reverse 0}} { |
|
300
|
if {$reverse} { |
|
301
|
set range [.txtA tag prevrange fn @0,0 1.0] |
|
302
|
if {$range eq ""} { |
|
303
|
viewDiff {fn.last -1c} |
|
304
|
} else { |
|
305
|
viewDiff [lindex $range 0] |
|
306
|
} |
|
307
|
} else { |
|
308
|
set range [.txtA tag nextrange fn {@0,0 +1c} end] |
|
309
|
if {$range eq "" || [lindex [.txtA yview] 1] == 1} { |
|
310
|
viewDiff fn.first |
|
311
|
} else { |
|
312
|
viewDiff [lindex $range 0] |
|
313
|
} |
|
314
|
} |
|
315
|
} |
|
316
|
|
|
317
|
proc xvis {col} { |
|
318
|
set view [$col xview] |
|
319
|
return [expr {[lindex $view 1]-[lindex $view 0]}] |
|
320
|
} |
|
321
|
|
|
322
|
proc scroll-x {args} { |
|
323
|
set c .txt[expr {[xvis .txtA] < [xvis .txtB] ? "A" : "B"}] |
|
324
|
eval $c xview $args |
|
325
|
} |
|
326
|
|
|
327
|
interp alias {} scroll-y {} .txtA yview |
|
328
|
|
|
329
|
proc noop {args} {} |
|
330
|
|
|
331
|
proc enableSync {axis} { |
|
332
|
update idletasks |
|
333
|
interp alias {} sync-$axis {} |
|
334
|
rename _sync-$axis sync-$axis |
|
335
|
} |
|
336
|
|
|
337
|
proc disableSync {axis} { |
|
338
|
rename sync-$axis _sync-$axis |
|
339
|
interp alias {} sync-$axis {} noop |
|
340
|
} |
|
341
|
|
|
342
|
proc sync-x {col first last} { |
|
343
|
disableSync x |
|
344
|
$col xview moveto [expr {$first*[xvis $col]/($last-$first)}] |
|
345
|
foreach side {A B} { |
|
346
|
set sb .sbx$side |
|
347
|
set xview [.txt$side xview] |
|
348
|
if {[lindex $xview 0] > 0 || [lindex $xview 1] < 1} { |
|
349
|
grid $sb |
|
350
|
eval $sb set $xview |
|
351
|
} else { |
|
352
|
grid remove $sb |
|
353
|
} |
|
354
|
} |
|
355
|
enableSync x |
|
356
|
} |
|
357
|
|
|
358
|
proc sync-y {first last} { |
|
359
|
disableSync y |
|
360
|
foreach c [cols] { |
|
361
|
$c yview moveto $first |
|
362
|
} |
|
363
|
if {$first > 0 || $last < 1} { |
|
364
|
grid .sby |
|
365
|
.sby set $first $last |
|
366
|
} else { |
|
367
|
grid remove .sby |
|
368
|
} |
|
369
|
enableSync y |
|
370
|
} |
|
371
|
|
|
372
|
wm withdraw . |
|
373
|
wm title . $CFG(TITLE) |
|
374
|
wm iconname . $CFG(TITLE) |
|
375
|
# Keystroke bindings for on the top-level window for navigation and |
|
376
|
# control also fire when those same keystrokes are pressed in the |
|
377
|
# Search entry box. Disable them, to prevent the diff screen from |
|
378
|
# disappearing abruptly and unexpectedly when searching for "q". |
|
379
|
# |
|
380
|
bind . <Control-q> exit |
|
381
|
bind . <Control-p> {catch searchPrev; break} |
|
382
|
bind . <Control-n> {catch searchNext; break} |
|
383
|
bind . <Escape><Escape> exit |
|
384
|
bind . <Destroy> {after 0 exit} |
|
385
|
bind . <Tab> {cycleDiffs; break} |
|
386
|
bind . <<PrevWindow>> {cycleDiffs 1; break} |
|
387
|
bind . <Control-f> {searchOnOff; break} |
|
388
|
bind . <Control-g> {catch searchNext; break} |
|
389
|
bind . <Return> { |
|
390
|
event generate .bb.files <1> |
|
391
|
event generate .bb.files <ButtonRelease-1> |
|
392
|
break |
|
393
|
} |
|
394
|
foreach {key axis args} { |
|
395
|
Up y {scroll -5 units} |
|
396
|
k y {scroll -5 units} |
|
397
|
Down y {scroll 5 units} |
|
398
|
j y {scroll 5 units} |
|
399
|
Left x {scroll -5 units} |
|
400
|
h x {scroll -5 units} |
|
401
|
Right x {scroll 5 units} |
|
402
|
l x {scroll 5 units} |
|
403
|
Prior y {scroll -1 page} |
|
404
|
b y {scroll -1 page} |
|
405
|
Next y {scroll 1 page} |
|
406
|
space y {scroll 1 page} |
|
407
|
Home y {moveto 0} |
|
408
|
g y {moveto 0} |
|
409
|
End y {moveto 1} |
|
410
|
} { |
|
411
|
bind . <$key> "scroll-$axis $args; break" |
|
412
|
bind . <Shift-$key> continue |
|
413
|
} |
|
414
|
|
|
415
|
frame .bb |
|
416
|
::ttk::menubutton .bb.files -text "Files" |
|
417
|
if {[tk windowingsystem] eq "win32"} { |
|
418
|
::ttk::style theme use winnative |
|
419
|
.bb.files configure -padding {20 1 10 2} |
|
420
|
} |
|
421
|
toplevel .wfiles |
|
422
|
wm withdraw .wfiles |
|
423
|
update idletasks |
|
424
|
wm transient .wfiles . |
|
425
|
wm overrideredirect .wfiles 1 |
|
426
|
listbox .wfiles.lb -width 0 -height $CFG(LB_HEIGHT) -activestyle none \ |
|
427
|
-yscroll {.wfiles.sb set} |
|
428
|
::ttk::scrollbar .wfiles.sb -command {.wfiles.lb yview} |
|
429
|
grid .wfiles.lb .wfiles.sb -sticky ns |
|
430
|
bind .bb.files <1> { |
|
431
|
set x [winfo rootx %W] |
|
432
|
set y [expr {[winfo rooty %W]+[winfo height %W]}] |
|
433
|
wm geometry .wfiles +$x+$y |
|
434
|
wm deiconify .wfiles |
|
435
|
focus .wfiles.lb |
|
436
|
} |
|
437
|
bind .wfiles <FocusOut> {wm withdraw .wfiles} |
|
438
|
bind .wfiles <Escape> {focus .} |
|
439
|
foreach evt {1 Return} { |
|
440
|
bind .wfiles.lb <$evt> { |
|
441
|
catch { |
|
442
|
set idx [lindex [.txtA tag ranges fn] [expr {[%W curselection]*2}]] |
|
443
|
viewDiff $idx |
|
444
|
} |
|
445
|
focus . |
|
446
|
break |
|
447
|
} |
|
448
|
} |
|
449
|
bind .wfiles.lb <Motion> { |
|
450
|
%W selection clear 0 end |
|
451
|
%W selection set @%x,%y |
|
452
|
} |
|
453
|
|
|
454
|
foreach {side syncCol} {A .txtB B .txtA} { |
|
455
|
set ln .ln$side |
|
456
|
text $ln |
|
457
|
$ln tag config - -justify right |
|
458
|
|
|
459
|
set txt .txt$side |
|
460
|
text $txt -width $CFG(WIDTH) -height $CFG(HEIGHT) -wrap none \ |
|
461
|
-xscroll "sync-x $syncCol" |
|
462
|
catch {$txt config -tabstyle wordprocessor} ;# Required for Tk>=8.5 |
|
463
|
foreach tag {add rm chng} { |
|
464
|
$txt tag config $tag -background $CFG([string toupper $tag]_BG) |
|
465
|
$txt tag lower $tag |
|
466
|
} |
|
467
|
$txt tag config fn -background $CFG(FN_BG) -foreground $CFG(FN_FG) \ |
|
468
|
-justify center |
|
469
|
$txt tag config err -foreground $CFG(ERR_FG) |
|
470
|
} |
|
471
|
text .mkr |
|
472
|
|
|
473
|
foreach c [cols] { |
|
474
|
set keyPrefix [string toupper [colType $c]]_COL_ |
|
475
|
if {[tk windowingsystem] eq "win32"} {$c config -font {courier 9}} |
|
476
|
$c config -bg $CFG(${keyPrefix}BG) -fg $CFG(${keyPrefix}FG) -borderwidth 0 \ |
|
477
|
-padx $CFG(PADX) -yscroll sync-y |
|
478
|
$c tag config hrln -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \ |
|
479
|
-foreground $CFG(HR_FG) -justify right |
|
480
|
$c tag config hrtxt -spacing1 $CFG(HR_PAD_TOP) -spacing3 $CFG(HR_PAD_BTM) \ |
|
481
|
-foreground $CFG(HR_FG) -justify center |
|
482
|
$c tag config fn -spacing1 $CFG(FN_PAD) -spacing3 $CFG(FN_PAD) |
|
483
|
bindtags $c ". $c Text all" |
|
484
|
bind $c <1> {focus %W} |
|
485
|
} |
|
486
|
|
|
487
|
::ttk::scrollbar .sby -command {.txtA yview} -orient vertical |
|
488
|
::ttk::scrollbar .sbxA -command {.txtA xview} -orient horizontal |
|
489
|
::ttk::scrollbar .sbxB -command {.txtB xview} -orient horizontal |
|
490
|
frame .spacer |
|
491
|
|
|
492
|
if {[readDiffs $fossilcmd 0] == 0} { |
|
493
|
tk_messageBox -type ok -title $CFG(TITLE) -message "No changes" |
|
494
|
exit |
|
495
|
} |
|
496
|
update idletasks |
|
497
|
|
|
498
|
proc saveDiff {} { |
|
499
|
set fn [tk_getSaveFile] |
|
500
|
if {$fn==""} return |
|
501
|
set out [open $fn wb] |
|
502
|
puts $out "#!/usr/bin/tclsh\n#\n# Run this script using 'tclsh' or 'wish'" |
|
503
|
puts $out "# to see the graphical diff.\n#" |
|
504
|
puts $out "set fossilcmd {}" |
|
505
|
puts $out "set darkmode $::darkmode" |
|
506
|
puts $out "set debug $::debug" |
|
507
|
puts $out "set prog [list $::prog]" |
|
508
|
puts $out "set difftxt \173" |
|
509
|
foreach e $::difftxt {puts $out [list $e]} |
|
510
|
puts $out "\175" |
|
511
|
puts $out "eval \$prog" |
|
512
|
close $out |
|
513
|
} |
|
514
|
proc invertDiff {} { |
|
515
|
global CFG |
|
516
|
array set x [grid info .txtA] |
|
517
|
if {$x(-column)==1} { |
|
518
|
grid config .lnB -column 0 |
|
519
|
grid config .txtB -column 1 |
|
520
|
.txtB tag config add -background $CFG(RM_BG) |
|
521
|
grid config .lnA -column 3 |
|
522
|
grid config .txtA -column 4 |
|
523
|
.txtA tag config rm -background $CFG(ADD_BG) |
|
524
|
.bb.invert config -text Uninvert |
|
525
|
} else { |
|
526
|
grid config .lnA -column 0 |
|
527
|
grid config .txtA -column 1 |
|
528
|
.txtA tag config rm -background $CFG(RM_BG) |
|
529
|
grid config .lnB -column 3 |
|
530
|
grid config .txtB -column 4 |
|
531
|
.txtB tag config add -background $CFG(ADD_BG) |
|
532
|
.bb.invert config -text Invert |
|
533
|
} |
|
534
|
.mkr config -state normal |
|
535
|
set clt [.mkr search -all < 1.0 end] |
|
536
|
set cgt [.mkr search -all > 1.0 end] |
|
537
|
foreach c $clt {.mkr replace $c "$c +1 chars" >} |
|
538
|
foreach c $cgt {.mkr replace $c "$c +1 chars" <} |
|
539
|
.mkr config -state disabled |
|
540
|
} |
|
541
|
proc searchOnOff {} { |
|
542
|
if {[info exists ::search]} { |
|
543
|
unset ::search |
|
544
|
.txtA tag remove search 1.0 end |
|
545
|
.txtB tag remove search 1.0 end |
|
546
|
pack forget .bb.sframe |
|
547
|
focus . |
|
548
|
} else { |
|
549
|
set ::search .txtA |
|
550
|
if {![winfo exists .bb.sframe]} { |
|
551
|
frame .bb.sframe |
|
552
|
::ttk::entry .bb.sframe.e -width 10 |
|
553
|
pack .bb.sframe.e -side left -fill y -expand 1 |
|
554
|
bind .bb.sframe.e <Return> {searchNext; break} |
|
555
|
::ttk::button .bb.sframe.nx -text \u2193 -width 1 -command searchNext |
|
556
|
::ttk::button .bb.sframe.pv -text \u2191 -width 1 -command searchPrev |
|
557
|
tk_optionMenu .bb.sframe.typ ::search_type \ |
|
558
|
Exact {No Case} {RegExp} {Whole Word} |
|
559
|
.bb.sframe.typ config -width 10 |
|
560
|
set ::search_type Exact |
|
561
|
pack .bb.sframe.nx .bb.sframe.pv .bb.sframe.typ -side left |
|
562
|
} |
|
563
|
pack .bb.sframe -side left |
|
564
|
after idle {focus .bb.sframe.e} |
|
565
|
} |
|
566
|
} |
|
567
|
proc searchNext {} {searchStep -forwards +1 1.0 end} |
|
568
|
proc searchPrev {} {searchStep -backwards -1 end 1.0} |
|
569
|
proc searchStep {direction incr start stop} { |
|
570
|
set pattern [.bb.sframe.e get] |
|
571
|
if {$pattern==""} return |
|
572
|
set count 0 |
|
573
|
set w $::search |
|
574
|
if {"$w"==".txtA"} {set other .txtB} {set other .txtA} |
|
575
|
if {[lsearch [$w mark names] search]<0} { |
|
576
|
$w mark set search $start |
|
577
|
} |
|
578
|
switch $::search_type { |
|
579
|
Exact {set st -exact} |
|
580
|
{No Case} {set st -nocase} |
|
581
|
{RegExp} {set st -regexp} |
|
582
|
{Whole Word} {set st -regexp; set pattern \\y$pattern\\y} |
|
583
|
} |
|
584
|
set idx [$w search -count count $direction $st -- \ |
|
585
|
$pattern "search $incr chars" $stop] |
|
586
|
if {"$idx"==""} { |
|
587
|
set idx [$other search -count count $direction $st -- $pattern $start $stop] |
|
588
|
if {"$idx"!=""} { |
|
589
|
set this $w |
|
590
|
set w $other |
|
591
|
set other $this |
|
592
|
} else { |
|
593
|
set idx [$w search -count count $direction $st -- $pattern $start $stop] |
|
594
|
} |
|
595
|
} |
|
596
|
$w tag remove search 1.0 end |
|
597
|
$w mark unset search |
|
598
|
$other tag remove search 1.0 end |
|
599
|
$other mark unset search |
|
600
|
if {"$idx"!=""} { |
|
601
|
$w mark set search $idx |
|
602
|
$w yview -pickplace $idx |
|
603
|
$w tag add search search "$idx +$count chars" |
|
604
|
$w tag config search -background {#fcc000} |
|
605
|
} |
|
606
|
set ::search $w |
|
607
|
} |
|
608
|
::ttk::button .bb.quit -text {Quit} -command exit |
|
609
|
::ttk::button .bb.reload -text {Reload} -command reloadDiff |
|
610
|
::ttk::button .bb.invert -text {Invert} -command invertDiff |
|
611
|
::ttk::button .bb.save -text {Save As...} -command saveDiff |
|
612
|
::ttk::button .bb.search -text {Search} -command searchOnOff |
|
613
|
pack .bb.quit -side left |
|
614
|
if {$fossilcmd ne ""} { |
|
615
|
pack .bb.reload -side left |
|
616
|
} |
|
617
|
pack .bb.invert -side left |
|
618
|
if {$fossilcmd!=""} {pack .bb.save -side left} |
|
619
|
pack .bb.files .bb.search -side left |
|
620
|
grid rowconfigure . 1 -weight 1 |
|
621
|
grid columnconfigure . 1 -weight 1 |
|
622
|
grid columnconfigure . 4 -weight 1 |
|
623
|
grid .bb -row 0 -columnspan 6 |
|
624
|
eval grid [cols] -row 1 -sticky nsew |
|
625
|
grid .sby -row 1 -column 5 -sticky ns |
|
626
|
grid .sbxA -row 2 -columnspan 2 -sticky ew |
|
627
|
grid .spacer -row 2 -column 2 |
|
628
|
grid .sbxB -row 2 -column 3 -columnspan 2 -sticky ew |
|
629
|
|
|
630
|
.spacer config -height [winfo height .sbxA] |
|
631
|
wm deiconify . |
|
632
|
} |
|
633
|
eval $prog |
|
634
|
|