Merge git://git.kernel.org/pub/scm/gitk/gitk
[git/git.git] / gitk
CommitLineData
1db95b00
PM
1#!/bin/sh
2# Tcl ignores the next line -*- tcl -*- \
9e026d39 3exec wish "$0" -- "$@"
1db95b00
PM
4
5# Copyright (C) 2005 Paul Mackerras. All rights reserved.
6# This program is free software; it may be used, copied, modified
7# and distributed under the terms of the GNU General Public Licence,
8# either version 2, or (at your option) any later version.
9
73b6a6cb
JH
10proc gitdir {} {
11 global env
12 if {[info exists env(GIT_DIR)]} {
13 return $env(GIT_DIR)
14 } else {
15 return ".git"
16 }
17}
18
b5c2f306
SV
19proc parse_args {rargs} {
20 global parsed_args
21
418c4c7b 22 if {[catch {
b5c2f306
SV
23 set parse_args [concat --default HEAD $rargs]
24 set parsed_args [split [eval exec git-rev-parse $parse_args] "\n"]
418c4c7b 25 }]} {
b5c2f306
SV
26 # if git-rev-parse failed for some reason...
27 if {$rargs == {}} {
28 set rargs HEAD
29 }
30 set parsed_args $rargs
31 }
32 return $parsed_args
33}
34
38ad0910 35proc start_rev_list {rlargs} {
466e4fdd 36 global startmsecs nextupdate ncmupdate
fd8ccbec 37 global commfd leftover tclencoding
9ccbdfbf 38
9ccbdfbf 39 set startmsecs [clock clicks -milliseconds]
2ed49d54 40 set nextupdate [expr {$startmsecs + 100}]
b664550c 41 set ncmupdate 1
418c4c7b 42 if {[catch {
38ad0910
PM
43 set commfd [open [concat | git-rev-list --header --topo-order \
44 --parents $rlargs] r]
418c4c7b 45 } err]} {
cfb4563c 46 puts stderr "Error executing git-rev-list: $err"
1d10f36d
PM
47 exit 1
48 }
b490a991 49 set leftover {}
fd8ccbec
PM
50 fconfigure $commfd -blocking 0 -translation lf
51 if {$tclencoding != {}} {
52 fconfigure $commfd -encoding $tclencoding
53 }
466e4fdd 54 fileevent $commfd readable [list getcommitlines $commfd]
38ad0910
PM
55 . config -cursor watch
56 settextcursor watch
57}
58
59proc getcommits {rargs} {
60 global oldcommits commits phase canv mainfont env
61
62 # check that we can find a .git directory somewhere...
63 set gitdir [gitdir]
64 if {![file isdirectory $gitdir]} {
65 error_popup "Cannot find the git directory \"$gitdir\"."
66 exit 1
67 }
68 set oldcommits {}
69 set commits {}
70 set phase getcommits
71 start_rev_list [parse_args $rargs]
1d10f36d
PM
72 $canv delete all
73 $canv create text 3 3 -anchor nw -text "Reading commits..." \
74 -font $mainfont -tags textitems
75}
76
b490a991 77proc getcommitlines {commfd} {
b5c2f306 78 global oldcommits commits parents cdate children nchildren
232475d3 79 global commitlisted phase nextupdate
b490a991 80 global stopped redisplaying leftover
b5c2f306 81 global canv
9ccbdfbf 82
b490a991
PM
83 set stuff [read $commfd]
84 if {$stuff == {}} {
1d10f36d 85 if {![eof $commfd]} return
f0654861 86 # set it blocking so we wait for the process to terminate
df3d83b1 87 fconfigure $commfd -blocking 1
1d10f36d 88 if {![catch {close $commfd} err]} {
9ccbdfbf 89 after idle finishcommits
1d10f36d
PM
90 return
91 }
9a40c50c 92 if {[string range $err 0 4] == "usage"} {
9ccbdfbf 93 set err \
2ed49d54
JH
94 "Gitk: error reading commits: bad arguments to git-rev-list.\
95 (Note: arguments to gitk are passed to git-rev-list\
96 to allow selection of commits to be displayed.)"
9a40c50c 97 } else {
df3d83b1 98 set err "Error reading commits: $err"
9a40c50c 99 }
df3d83b1 100 error_popup $err
1d10f36d 101 exit 1
9a40c50c 102 }
b490a991
PM
103 set start 0
104 while 1 {
105 set i [string first "\0" $stuff $start]
106 if {$i < 0} {
7e952e79 107 append leftover [string range $stuff $start end]
b490a991 108 return
9ccbdfbf 109 }
b490a991
PM
110 set cmit [string range $stuff $start [expr {$i - 1}]]
111 if {$start == 0} {
112 set cmit "$leftover$cmit"
7e952e79 113 set leftover {}
b490a991
PM
114 }
115 set start [expr {$i + 1}]
e5ea701b
PM
116 set j [string first "\n" $cmit]
117 set ok 0
118 if {$j >= 0} {
119 set ids [string range $cmit 0 [expr {$j - 1}]]
120 set ok 1
121 foreach id $ids {
122 if {![regexp {^[0-9a-f]{40}$} $id]} {
123 set ok 0
124 break
125 }
126 }
127 }
128 if {!$ok} {
7e952e79
PM
129 set shortcmit $cmit
130 if {[string length $shortcmit] > 80} {
131 set shortcmit "[string range $shortcmit 0 80]..."
132 }
133 error_popup "Can't parse git-rev-list output: {$shortcmit}"
b490a991
PM
134 exit 1
135 }
e5ea701b
PM
136 set id [lindex $ids 0]
137 set olds [lrange $ids 1 end]
138 set cmit [string range $cmit [expr {$j + 1}] end]
b490a991
PM
139 lappend commits $id
140 set commitlisted($id) 1
e5ea701b 141 parsecommit $id $cmit 1 [lrange $ids 1 end]
b5c2f306 142 drawcommit $id 1
b664550c
PM
143 if {[clock clicks -milliseconds] >= $nextupdate} {
144 doupdate 1
b490a991
PM
145 }
146 while {$redisplaying} {
147 set redisplaying 0
148 if {$stopped == 1} {
149 set stopped 0
150 set phase "getcommits"
151 foreach id $commits {
b5c2f306 152 drawcommit $id 1
b490a991 153 if {$stopped} break
b664550c
PM
154 if {[clock clicks -milliseconds] >= $nextupdate} {
155 doupdate 1
b490a991 156 }
9ccbdfbf
PM
157 }
158 }
159 }
160 }
161}
162
b664550c
PM
163proc doupdate {reading} {
164 global commfd nextupdate numcommits ncmupdate
9ccbdfbf 165
b664550c
PM
166 if {$reading} {
167 fileevent $commfd readable {}
168 }
9ccbdfbf 169 update
b664550c
PM
170 set nextupdate [expr {[clock clicks -milliseconds] + 100}]
171 if {$numcommits < 100} {
172 set ncmupdate [expr {$numcommits + 1}]
173 } elseif {$numcommits < 10000} {
174 set ncmupdate [expr {$numcommits + 10}]
175 } else {
176 set ncmupdate [expr {$numcommits + 100}]
177 }
178 if {$reading} {
179 fileevent $commfd readable [list getcommitlines $commfd]
180 }
1db95b00
PM
181}
182
183proc readcommit {id} {
418c4c7b 184 if {[catch {set contents [exec git-cat-file commit $id]}]} return
e5ea701b 185 parsecommit $id $contents 0 {}
b490a991
PM
186}
187
fd8ccbec
PM
188proc updatecommits {rargs} {
189 global commitlisted commfd phase
190 global startmsecs nextupdate ncmupdate
191 global idtags idheads idotherrefs
192 global leftover
193 global parsed_args
194 global canv mainfont
195 global oldcommits commits
196 global parents nchildren children ncleft
197
198 set old_args $parsed_args
199 parse_args $rargs
200
201 if {$phase == "getcommits" || $phase == "incrdraw"} {
202 # havent read all the old commits, just start again from scratch
203 stopfindproc
204 set oldcommits {}
205 set commits {}
206 foreach v {children nchildren parents commitlisted commitinfo
207 selectedline matchinglines treediffs
208 mergefilelist currentid rowtextx} {
209 global $v
210 catch {unset $v}
211 }
212 readrefs
213 if {$phase == "incrdraw"} {
214 allcanvs delete all
215 $canv create text 3 3 -anchor nw -text "Reading commits..." \
216 -font $mainfont -tags textitems
217 set phase getcommits
218 }
219 start_rev_list $parsed_args
220 return
221 }
222
223 foreach id $old_args {
224 if {![regexp {^[0-9a-f]{40}$} $id]} continue
225 if {[info exists oldref($id)]} continue
226 set oldref($id) $id
227 lappend ignoreold "^$id"
228 }
229 foreach id $parsed_args {
230 if {![regexp {^[0-9a-f]{40}$} $id]} continue
231 if {[info exists ref($id)]} continue
232 set ref($id) $id
233 lappend ignorenew "^$id"
234 }
235
236 foreach a $old_args {
237 if {![info exists ref($a)]} {
238 lappend ignorenew $a
239 }
240 }
241
242 set phase updatecommits
243 set oldcommits $commits
244 set commits {}
245 set removed_commits [split [eval exec git-rev-list $ignorenew] "\n" ]
246 if {[llength $removed_commits] > 0} {
247 allcanvs delete all
248 foreach c $removed_commits {
249 set i [lsearch -exact $oldcommits $c]
250 if {$i >= 0} {
251 set oldcommits [lreplace $oldcommits $i $i]
252 unset commitlisted($c)
253 foreach p $parents($c) {
254 if {[info exists nchildren($p)]} {
255 set j [lsearch -exact $children($p) $c]
256 if {$j >= 0} {
257 set children($p) [lreplace $children($p) $j $j]
258 incr nchildren($p) -1
259 }
260 }
261 }
262 }
263 }
264 set phase removecommits
265 }
266
267 set args {}
268 foreach a $parsed_args {
269 if {![info exists oldref($a)]} {
270 lappend args $a
271 }
272 }
273
274 readrefs
275 start_rev_list [concat $ignoreold $args]
276}
277
b5c2f306
SV
278proc updatechildren {id olds} {
279 global children nchildren parents nparents ncleft
9ccbdfbf 280
cfb4563c
PM
281 if {![info exists nchildren($id)]} {
282 set children($id) {}
283 set nchildren($id) 0
9ccbdfbf 284 set ncleft($id) 0
cfb4563c 285 }
e5ea701b
PM
286 set parents($id) $olds
287 set nparents($id) [llength $olds]
288 foreach p $olds {
289 if {![info exists nchildren($p)]} {
290 set children($p) [list $id]
291 set nchildren($p) 1
292 set ncleft($p) 1
293 } elseif {[lsearch -exact $children($p) $id] < 0} {
294 lappend children($p) $id
295 incr nchildren($p)
296 incr ncleft($p)
244edd12
PM
297 }
298 }
b5c2f306
SV
299}
300
301proc parsecommit {id contents listed olds} {
302 global commitinfo cdate
303
304 set inhdr 1
305 set comment {}
306 set headline {}
307 set auname {}
308 set audate {}
309 set comname {}
310 set comdate {}
311 updatechildren $id $olds
232475d3
PM
312 set hdrend [string first "\n\n" $contents]
313 if {$hdrend < 0} {
314 # should never happen...
315 set hdrend [string length $contents]
316 }
317 set header [string range $contents 0 [expr {$hdrend - 1}]]
318 set comment [string range $contents [expr {$hdrend + 2}] end]
319 foreach line [split $header "\n"] {
320 set tag [lindex $line 0]
321 if {$tag == "author"} {
322 set audate [lindex $line end-1]
323 set auname [lrange $line 1 end-2]
324 } elseif {$tag == "committer"} {
325 set comdate [lindex $line end-1]
326 set comname [lrange $line 1 end-2]
1db95b00
PM
327 }
328 }
232475d3
PM
329 set headline {}
330 # take the first line of the comment as the headline
331 set i [string first "\n" $comment]
332 if {$i >= 0} {
333 set headline [string trim [string range $comment 0 $i]]
f6e2869f
PM
334 } else {
335 set headline $comment
232475d3
PM
336 }
337 if {!$listed} {
338 # git-rev-list indents the comment by 4 spaces;
339 # if we got this via git-cat-file, add the indentation
340 set newcomment {}
341 foreach line [split $comment "\n"] {
342 append newcomment " "
343 append newcomment $line
f6e2869f 344 append newcomment "\n"
232475d3
PM
345 }
346 set comment $newcomment
1db95b00
PM
347 }
348 if {$comdate != {}} {
cfb4563c 349 set cdate($id) $comdate
1db95b00 350 }
e5c2d856
PM
351 set commitinfo($id) [list $headline $auname $audate \
352 $comname $comdate $comment]
1db95b00
PM
353}
354
887fe3c4 355proc readrefs {} {
106288cb 356 global tagids idtags headids idheads tagcontents
36a7cad6 357 global otherrefids idotherrefs
106288cb 358
b5c2f306
SV
359 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
360 catch {unset $v}
361 }
36a7cad6
JH
362 set refd [open [list | git-ls-remote [gitdir]] r]
363 while {0 <= [set n [gets $refd line]]} {
364 if {![regexp {^([0-9a-f]{40}) refs/([^^]*)$} $line \
365 match id path]} {
366 continue
c2f6a022 367 }
36a7cad6
JH
368 if {![regexp {^(tags|heads)/(.*)$} $path match type name]} {
369 set type others
370 set name $path
887fe3c4 371 }
36a7cad6
JH
372 if {$type == "tags"} {
373 set tagids($name) $id
374 lappend idtags($id) $name
375 set obj {}
376 set type {}
377 set tag {}
378 catch {
379 set commit [exec git-rev-parse "$id^0"]
380 if {"$commit" != "$id"} {
381 set tagids($name) $commit
382 lappend idtags($commit) $name
383 }
384 }
385 catch {
386 set tagcontents($name) [exec git-cat-file tag "$id"]
f1d83ba3 387 }
36a7cad6
JH
388 } elseif { $type == "heads" } {
389 set headids($name) $id
390 lappend idheads($id) $name
391 } else {
392 set otherrefids($name) $id
393 lappend idotherrefs($id) $name
f1d83ba3
PM
394 }
395 }
36a7cad6 396 close $refd
887fe3c4
PM
397}
398
df3d83b1
PM
399proc error_popup msg {
400 set w .error
401 toplevel $w
402 wm transient $w .
403 message $w.m -text $msg -justify center -aspect 400
404 pack $w.m -side top -fill x -padx 20 -pady 20
405 button $w.ok -text OK -command "destroy $w"
406 pack $w.ok -side bottom -fill x
407 bind $w <Visibility> "grab $w; focus $w"
408 tkwait window $w
409}
410
b5c2f306 411proc makewindow {rargs} {
e5c2d856 412 global canv canv2 canv3 linespc charspc ctext cflist textfont
b74fd579 413 global findtype findtypemenu findloc findstring fstring geometry
887fe3c4 414 global entries sha1entry sha1string sha1but
94a2eede 415 global maincursor textcursor curtextcursor
712fcc08 416 global rowctxmenu mergemax
9a40c50c
PM
417
418 menu .bar
419 .bar add cascade -label "File" -menu .bar.file
420 menu .bar.file
b5c2f306 421 .bar.file add command -label "Update" -command [list updatecommits $rargs]
f1d83ba3 422 .bar.file add command -label "Reread references" -command rereadrefs
1d10f36d 423 .bar.file add command -label "Quit" -command doquit
712fcc08
PM
424 menu .bar.edit
425 .bar add cascade -label "Edit" -menu .bar.edit
426 .bar.edit add command -label "Preferences" -command doprefs
9a40c50c
PM
427 menu .bar.help
428 .bar add cascade -label "Help" -menu .bar.help
429 .bar.help add command -label "About gitk" -command about
430 . configure -menu .bar
431
0fba86b3 432 if {![info exists geometry(canv1)]} {
2ed49d54
JH
433 set geometry(canv1) [expr {45 * $charspc}]
434 set geometry(canv2) [expr {30 * $charspc}]
435 set geometry(canv3) [expr {15 * $charspc}]
436 set geometry(canvh) [expr {25 * $linespc + 4}]
0fba86b3
PM
437 set geometry(ctextw) 80
438 set geometry(ctexth) 30
439 set geometry(cflistw) 30
440 }
0327d27a 441 panedwindow .ctop -orient vertical
0fba86b3
PM
442 if {[info exists geometry(width)]} {
443 .ctop conf -width $geometry(width) -height $geometry(height)
17386066
PM
444 set texth [expr {$geometry(height) - $geometry(canvh) - 56}]
445 set geometry(ctexth) [expr {($texth - 8) /
446 [font metrics $textfont -linespace]}]
0fba86b3 447 }
98f350e5
PM
448 frame .ctop.top
449 frame .ctop.top.bar
450 pack .ctop.top.bar -side bottom -fill x
451 set cscroll .ctop.top.csb
452 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
453 pack $cscroll -side right -fill y
454 panedwindow .ctop.top.clist -orient horizontal -sashpad 0 -handlesize 4
455 pack .ctop.top.clist -side top -fill both -expand 1
456 .ctop add .ctop.top
457 set canv .ctop.top.clist.canv
0fba86b3 458 canvas $canv -height $geometry(canvh) -width $geometry(canv1) \
b5721c72
PM
459 -bg white -bd 0 \
460 -yscrollincr $linespc -yscrollcommand "$cscroll set"
98f350e5
PM
461 .ctop.top.clist add $canv
462 set canv2 .ctop.top.clist.canv2
0fba86b3 463 canvas $canv2 -height $geometry(canvh) -width $geometry(canv2) \
b5721c72 464 -bg white -bd 0 -yscrollincr $linespc
98f350e5
PM
465 .ctop.top.clist add $canv2
466 set canv3 .ctop.top.clist.canv3
0fba86b3 467 canvas $canv3 -height $geometry(canvh) -width $geometry(canv3) \
b5721c72 468 -bg white -bd 0 -yscrollincr $linespc
98f350e5 469 .ctop.top.clist add $canv3
43bddeb4 470 bind .ctop.top.clist <Configure> {resizeclistpanes %W %w}
98f350e5
PM
471
472 set sha1entry .ctop.top.bar.sha1
887fe3c4
PM
473 set entries $sha1entry
474 set sha1but .ctop.top.bar.sha1label
475 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
476 -command gotocommit -width 8
477 $sha1but conf -disabledforeground [$sha1but cget -foreground]
98f350e5 478 pack .ctop.top.bar.sha1label -side left
887fe3c4
PM
479 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
480 trace add variable sha1string write sha1change
98f350e5 481 pack $sha1entry -side left -pady 2
d698206c
PM
482
483 image create bitmap bm-left -data {
484 #define left_width 16
485 #define left_height 16
486 static unsigned char left_bits[] = {
487 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
488 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
489 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
490 }
491 image create bitmap bm-right -data {
492 #define right_width 16
493 #define right_height 16
494 static unsigned char right_bits[] = {
495 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
496 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
497 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
498 }
499 button .ctop.top.bar.leftbut -image bm-left -command goback \
500 -state disabled -width 26
501 pack .ctop.top.bar.leftbut -side left -fill y
502 button .ctop.top.bar.rightbut -image bm-right -command goforw \
503 -state disabled -width 26
504 pack .ctop.top.bar.rightbut -side left -fill y
505
98f350e5
PM
506 button .ctop.top.bar.findbut -text "Find" -command dofind
507 pack .ctop.top.bar.findbut -side left
508 set findstring {}
df3d83b1 509 set fstring .ctop.top.bar.findstring
887fe3c4 510 lappend entries $fstring
df3d83b1 511 entry $fstring -width 30 -font $textfont -textvariable findstring
df3d83b1 512 pack $fstring -side left -expand 1 -fill x
98f350e5 513 set findtype Exact
b74fd579
PM
514 set findtypemenu [tk_optionMenu .ctop.top.bar.findtype \
515 findtype Exact IgnCase Regexp]
98f350e5
PM
516 set findloc "All fields"
517 tk_optionMenu .ctop.top.bar.findloc findloc "All fields" Headline \
b74fd579 518 Comments Author Committer Files Pickaxe
98f350e5
PM
519 pack .ctop.top.bar.findloc -side right
520 pack .ctop.top.bar.findtype -side right
b74fd579
PM
521 # for making sure type==Exact whenever loc==Pickaxe
522 trace add variable findloc write findlocchange
b5721c72 523
5ad588de
PM
524 panedwindow .ctop.cdet -orient horizontal
525 .ctop add .ctop.cdet
d2610d11
PM
526 frame .ctop.cdet.left
527 set ctext .ctop.cdet.left.ctext
0fba86b3
PM
528 text $ctext -bg white -state disabled -font $textfont \
529 -width $geometry(ctextw) -height $geometry(ctexth) \
b1ba39e7 530 -yscrollcommand ".ctop.cdet.left.sb set" -wrap none
d2610d11
PM
531 scrollbar .ctop.cdet.left.sb -command "$ctext yview"
532 pack .ctop.cdet.left.sb -side right -fill y
533 pack $ctext -side left -fill both -expand 1
534 .ctop.cdet add .ctop.cdet.left
535
f0654861 536 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
712fcc08
PM
537 $ctext tag conf hunksep -fore blue
538 $ctext tag conf d0 -fore red
539 $ctext tag conf d1 -fore "#00a000"
540 $ctext tag conf m0 -fore red
541 $ctext tag conf m1 -fore blue
542 $ctext tag conf m2 -fore green
543 $ctext tag conf m3 -fore purple
544 $ctext tag conf m4 -fore brown
b77b0278
PM
545 $ctext tag conf m5 -fore "#009090"
546 $ctext tag conf m6 -fore magenta
547 $ctext tag conf m7 -fore "#808000"
548 $ctext tag conf m8 -fore "#009000"
549 $ctext tag conf m9 -fore "#ff0080"
550 $ctext tag conf m10 -fore cyan
551 $ctext tag conf m11 -fore "#b07070"
552 $ctext tag conf m12 -fore "#70b0f0"
553 $ctext tag conf m13 -fore "#70f0b0"
554 $ctext tag conf m14 -fore "#f0b070"
555 $ctext tag conf m15 -fore "#ff70b0"
712fcc08 556 $ctext tag conf mmax -fore darkgrey
b77b0278 557 set mergemax 16
712fcc08
PM
558 $ctext tag conf mresult -font [concat $textfont bold]
559 $ctext tag conf msep -font [concat $textfont bold]
560 $ctext tag conf found -back yellow
e5c2d856 561
d2610d11
PM
562 frame .ctop.cdet.right
563 set cflist .ctop.cdet.right.cfiles
17386066 564 listbox $cflist -bg white -selectmode extended -width $geometry(cflistw) \
d2610d11
PM
565 -yscrollcommand ".ctop.cdet.right.sb set"
566 scrollbar .ctop.cdet.right.sb -command "$cflist yview"
567 pack .ctop.cdet.right.sb -side right -fill y
568 pack $cflist -side left -fill both -expand 1
569 .ctop.cdet add .ctop.cdet.right
0fba86b3 570 bind .ctop.cdet <Configure> {resizecdetpanes %W %w}
d2610d11 571
0327d27a 572 pack .ctop -side top -fill both -expand 1
1db95b00 573
c8dfbcf9
PM
574 bindall <1> {selcanvline %W %x %y}
575 #bindall <B1-Motion> {selcanvline %W %x %y}
cfb4563c
PM
576 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
577 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
b5721c72
PM
578 bindall <2> "allcanvs scan mark 0 %y"
579 bindall <B2-Motion> "allcanvs scan dragto 0 %y"
17386066
PM
580 bind . <Key-Up> "selnextline -1"
581 bind . <Key-Down> "selnextline 1"
6e2dda35
RS
582 bind . <Key-Right> "goforw"
583 bind . <Key-Left> "goback"
cfb4563c
PM
584 bind . <Key-Prior> "allcanvs yview scroll -1 pages"
585 bind . <Key-Next> "allcanvs yview scroll 1 pages"
586 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
587 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
588 bindkey <Key-space> "$ctext yview scroll 1 pages"
df3d83b1
PM
589 bindkey p "selnextline -1"
590 bindkey n "selnextline 1"
6e2dda35
RS
591 bindkey z "goback"
592 bindkey x "goforw"
593 bindkey i "selnextline -1"
594 bindkey k "selnextline 1"
595 bindkey j "goback"
596 bindkey l "goforw"
cfb4563c
PM
597 bindkey b "$ctext yview scroll -1 pages"
598 bindkey d "$ctext yview scroll 18 units"
599 bindkey u "$ctext yview scroll -18 units"
b74fd579
PM
600 bindkey / {findnext 1}
601 bindkey <Key-Return> {findnext 0}
df3d83b1 602 bindkey ? findprev
39ad8570 603 bindkey f nextfile
1d10f36d 604 bind . <Control-q> doquit
98f350e5 605 bind . <Control-f> dofind
b74fd579 606 bind . <Control-g> {findnext 0}
98f350e5 607 bind . <Control-r> findprev
1d10f36d
PM
608 bind . <Control-equal> {incrfont 1}
609 bind . <Control-KP_Add> {incrfont 1}
610 bind . <Control-minus> {incrfont -1}
611 bind . <Control-KP_Subtract> {incrfont -1}
e5c2d856 612 bind $cflist <<ListboxSelect>> listboxsel
0fba86b3 613 bind . <Destroy> {savestuff %W}
df3d83b1 614 bind . <Button-1> "click %W"
17386066 615 bind $fstring <Key-Return> dofind
887fe3c4 616 bind $sha1entry <Key-Return> gotocommit
ee3dc72e 617 bind $sha1entry <<PasteSelection>> clearsha1
ea13cba1
PM
618
619 set maincursor [. cget -cursor]
620 set textcursor [$ctext cget -cursor]
94a2eede 621 set curtextcursor $textcursor
84ba7345 622
c8dfbcf9
PM
623 set rowctxmenu .rowctxmenu
624 menu $rowctxmenu -tearoff 0
625 $rowctxmenu add command -label "Diff this -> selected" \
626 -command {diffvssel 0}
627 $rowctxmenu add command -label "Diff selected -> this" \
628 -command {diffvssel 1}
74daedb6 629 $rowctxmenu add command -label "Make patch" -command mkpatch
bdbfbe3d 630 $rowctxmenu add command -label "Create tag" -command mktag
4a2139f5 631 $rowctxmenu add command -label "Write commit to file" -command writecommit
df3d83b1
PM
632}
633
634# when we make a key binding for the toplevel, make sure
635# it doesn't get triggered when that key is pressed in the
636# find string entry widget.
637proc bindkey {ev script} {
887fe3c4 638 global entries
df3d83b1
PM
639 bind . $ev $script
640 set escript [bind Entry $ev]
641 if {$escript == {}} {
642 set escript [bind Entry <Key>]
643 }
887fe3c4
PM
644 foreach e $entries {
645 bind $e $ev "$escript; break"
646 }
df3d83b1
PM
647}
648
649# set the focus back to the toplevel for any click outside
887fe3c4 650# the entry widgets
df3d83b1 651proc click {w} {
887fe3c4
PM
652 global entries
653 foreach e $entries {
654 if {$w == $e} return
df3d83b1 655 }
887fe3c4 656 focus .
0fba86b3
PM
657}
658
659proc savestuff {w} {
660 global canv canv2 canv3 ctext cflist mainfont textfont
712fcc08 661 global stuffsaved findmergefiles maxgraphpct
04c13d38 662 global maxwidth
4ef17537 663
0fba86b3 664 if {$stuffsaved} return
df3d83b1 665 if {![winfo viewable .]} return
0fba86b3
PM
666 catch {
667 set f [open "~/.gitk-new" w]
f0654861
PM
668 puts $f [list set mainfont $mainfont]
669 puts $f [list set textfont $textfont]
670 puts $f [list set findmergefiles $findmergefiles]
8d858d1a 671 puts $f [list set maxgraphpct $maxgraphpct]
04c13d38 672 puts $f [list set maxwidth $maxwidth]
0fba86b3
PM
673 puts $f "set geometry(width) [winfo width .ctop]"
674 puts $f "set geometry(height) [winfo height .ctop]"
2ed49d54
JH
675 puts $f "set geometry(canv1) [expr {[winfo width $canv]-2}]"
676 puts $f "set geometry(canv2) [expr {[winfo width $canv2]-2}]"
677 puts $f "set geometry(canv3) [expr {[winfo width $canv3]-2}]"
678 puts $f "set geometry(canvh) [expr {[winfo height $canv]-2}]"
0fba86b3
PM
679 set wid [expr {([winfo width $ctext] - 8) \
680 / [font measure $textfont "0"]}]
0fba86b3 681 puts $f "set geometry(ctextw) $wid"
0fba86b3
PM
682 set wid [expr {([winfo width $cflist] - 11) \
683 / [font measure [$cflist cget -font] "0"]}]
684 puts $f "set geometry(cflistw) $wid"
685 close $f
686 file rename -force "~/.gitk-new" "~/.gitk"
687 }
688 set stuffsaved 1
1db95b00
PM
689}
690
43bddeb4
PM
691proc resizeclistpanes {win w} {
692 global oldwidth
418c4c7b 693 if {[info exists oldwidth($win)]} {
43bddeb4
PM
694 set s0 [$win sash coord 0]
695 set s1 [$win sash coord 1]
696 if {$w < 60} {
697 set sash0 [expr {int($w/2 - 2)}]
698 set sash1 [expr {int($w*5/6 - 2)}]
699 } else {
700 set factor [expr {1.0 * $w / $oldwidth($win)}]
701 set sash0 [expr {int($factor * [lindex $s0 0])}]
702 set sash1 [expr {int($factor * [lindex $s1 0])}]
703 if {$sash0 < 30} {
704 set sash0 30
705 }
706 if {$sash1 < $sash0 + 20} {
2ed49d54 707 set sash1 [expr {$sash0 + 20}]
43bddeb4
PM
708 }
709 if {$sash1 > $w - 10} {
2ed49d54 710 set sash1 [expr {$w - 10}]
43bddeb4 711 if {$sash0 > $sash1 - 20} {
2ed49d54 712 set sash0 [expr {$sash1 - 20}]
43bddeb4
PM
713 }
714 }
715 }
716 $win sash place 0 $sash0 [lindex $s0 1]
717 $win sash place 1 $sash1 [lindex $s1 1]
718 }
719 set oldwidth($win) $w
720}
721
722proc resizecdetpanes {win w} {
723 global oldwidth
418c4c7b 724 if {[info exists oldwidth($win)]} {
43bddeb4
PM
725 set s0 [$win sash coord 0]
726 if {$w < 60} {
727 set sash0 [expr {int($w*3/4 - 2)}]
728 } else {
729 set factor [expr {1.0 * $w / $oldwidth($win)}]
730 set sash0 [expr {int($factor * [lindex $s0 0])}]
731 if {$sash0 < 45} {
732 set sash0 45
733 }
734 if {$sash0 > $w - 15} {
2ed49d54 735 set sash0 [expr {$w - 15}]
43bddeb4
PM
736 }
737 }
738 $win sash place 0 $sash0 [lindex $s0 1]
739 }
740 set oldwidth($win) $w
741}
742
b5721c72
PM
743proc allcanvs args {
744 global canv canv2 canv3
745 eval $canv $args
746 eval $canv2 $args
747 eval $canv3 $args
748}
749
750proc bindall {event action} {
751 global canv canv2 canv3
752 bind $canv $event $action
753 bind $canv2 $event $action
754 bind $canv3 $event $action
755}
756
9a40c50c
PM
757proc about {} {
758 set w .about
759 if {[winfo exists $w]} {
760 raise $w
761 return
762 }
763 toplevel $w
764 wm title $w "About gitk"
765 message $w.m -text {
c8dfbcf9 766Gitk version 1.2
9a40c50c
PM
767
768