]> git.ipfire.org Git - thirdparty/git.git/blame - gitk
Handle format.subjectprefix for every command which accepts --pretty
[thirdparty/git.git] / gitk
CommitLineData
1db95b00
PM
1#!/bin/sh
2# Tcl ignores the next line -*- tcl -*- \
9e026d39 3exec wish "$0" -- "$@"
1db95b00 4
e1a7c81f 5# Copyright (C) 2005-2006 Paul Mackerras. All rights reserved.
1db95b00
PM
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 {
5024baa4 15 return [exec git rev-parse --git-dir]
73b6a6cb
JH
16 }
17}
18
7eb3cb9c
PM
19# A simple scheduler for compute-intensive stuff.
20# The aim is to make sure that event handlers for GUI actions can
21# run at least every 50-100 ms. Unfortunately fileevent handlers are
22# run before X event handlers, so reading from a fast source can
23# make the GUI completely unresponsive.
24proc run args {
25 global isonrunq runq
26
27 set script $args
28 if {[info exists isonrunq($script)]} return
29 if {$runq eq {}} {
30 after idle dorunq
31 }
32 lappend runq [list {} $script]
33 set isonrunq($script) 1
34}
35
36proc filerun {fd script} {
37 fileevent $fd readable [list filereadable $fd $script]
38}
39
40proc filereadable {fd script} {
41 global runq
42
43 fileevent $fd readable {}
44 if {$runq eq {}} {
45 after idle dorunq
46 }
47 lappend runq [list $fd $script]
48}
49
50proc dorunq {} {
51 global isonrunq runq
52
53 set tstart [clock clicks -milliseconds]
54 set t0 $tstart
55 while {$runq ne {}} {
56 set fd [lindex $runq 0 0]
57 set script [lindex $runq 0 1]
58 set repeat [eval $script]
59 set t1 [clock clicks -milliseconds]
60 set t [expr {$t1 - $t0}]
61 set runq [lrange $runq 1 end]
62 if {$repeat ne {} && $repeat} {
63 if {$fd eq {} || $repeat == 2} {
64 # script returns 1 if it wants to be readded
65 # file readers return 2 if they could do more straight away
66 lappend runq [list $fd $script]
67 } else {
68 fileevent $fd readable [list filereadable $fd $script]
69 }
70 } elseif {$fd eq {}} {
71 unset isonrunq($script)
72 }
73 set t0 $t1
74 if {$t1 - $tstart >= 80} break
75 }
76 if {$runq ne {}} {
77 after idle dorunq
78 }
79}
80
81# Start off a git rev-list process and arrange to read its output
da7c24dd 82proc start_rev_list {view} {
7eb3cb9c 83 global startmsecs
9f1afe05 84 global commfd leftover tclencoding datemode
098dd8a3 85 global viewargs viewfiles commitidx
219ea3a9 86 global lookingforhead showlocalchanges
9ccbdfbf 87
9ccbdfbf 88 set startmsecs [clock clicks -milliseconds]
da7c24dd 89 set commitidx($view) 0
098dd8a3 90 set args $viewargs($view)
da7c24dd
PM
91 if {$viewfiles($view) ne {}} {
92 set args [concat $args "--" $viewfiles($view)]
a8aaf19c 93 }
9f1afe05
PM
94 set order "--topo-order"
95 if {$datemode} {
96 set order "--date-order"
97 }
418c4c7b 98 if {[catch {
8974c6f9 99 set fd [open [concat | git rev-list --header $order \
da7c24dd 100 --parents --boundary --default HEAD $args] r]
418c4c7b 101 } err]} {
8974c6f9 102 puts stderr "Error executing git rev-list: $err"
1d10f36d
PM
103 exit 1
104 }
da7c24dd
PM
105 set commfd($view) $fd
106 set leftover($view) {}
219ea3a9 107 set lookingforhead $showlocalchanges
da7c24dd 108 fconfigure $fd -blocking 0 -translation lf
fd8ccbec 109 if {$tclencoding != {}} {
da7c24dd 110 fconfigure $fd -encoding $tclencoding
fd8ccbec 111 }
7eb3cb9c 112 filerun $fd [list getcommitlines $fd $view]
da7c24dd 113 nowbusy $view
38ad0910
PM
114}
115
22626ef4 116proc stop_rev_list {} {
da7c24dd 117 global commfd curview
22626ef4 118
da7c24dd
PM
119 if {![info exists commfd($curview)]} return
120 set fd $commfd($curview)
22626ef4 121 catch {
da7c24dd 122 set pid [pid $fd]
22626ef4
PM
123 exec kill $pid
124 }
da7c24dd
PM
125 catch {close $fd}
126 unset commfd($curview)
22626ef4
PM
127}
128
a8aaf19c 129proc getcommits {} {
da7c24dd 130 global phase canv mainfont curview
38ad0910 131
38ad0910 132 set phase getcommits
da7c24dd
PM
133 initlayout
134 start_rev_list $curview
098dd8a3 135 show_status "Reading commits..."
1d10f36d
PM
136}
137
da7c24dd 138proc getcommitlines {fd view} {
7eb3cb9c 139 global commitlisted
da7c24dd 140 global leftover commfd
8ed16484 141 global displayorder commitidx commitrow commitdata
6a90bff1
PM
142 global parentlist children curview hlview
143 global vparentlist vdisporder vcmitlisted
9ccbdfbf 144
d1e46756 145 set stuff [read $fd 500000]
b490a991 146 if {$stuff == {}} {
7eb3cb9c
PM
147 if {![eof $fd]} {
148 return 1
149 }
098dd8a3 150 global viewname
da7c24dd 151 unset commfd($view)
098dd8a3 152 notbusy $view
f0654861 153 # set it blocking so we wait for the process to terminate
da7c24dd 154 fconfigure $fd -blocking 1
098dd8a3
PM
155 if {[catch {close $fd} err]} {
156 set fv {}
157 if {$view != $curview} {
158 set fv " for the \"$viewname($view)\" view"
da7c24dd 159 }
098dd8a3
PM
160 if {[string range $err 0 4] == "usage"} {
161 set err "Gitk: error reading commits$fv:\
8974c6f9 162 bad arguments to git rev-list."
098dd8a3
PM
163 if {$viewname($view) eq "Command line"} {
164 append err \
8974c6f9 165 " (Note: arguments to gitk are passed to git rev-list\
098dd8a3
PM
166 to allow selection of commits to be displayed.)"
167 }
168 } else {
169 set err "Error reading commits$fv: $err"
170 }
171 error_popup $err
1d10f36d 172 }
098dd8a3 173 if {$view == $curview} {
7eb3cb9c 174 run chewcommits $view
9a40c50c 175 }
7eb3cb9c 176 return 0
9a40c50c 177 }
b490a991 178 set start 0
8f7d0cec 179 set gotsome 0
b490a991
PM
180 while 1 {
181 set i [string first "\0" $stuff $start]
182 if {$i < 0} {
da7c24dd 183 append leftover($view) [string range $stuff $start end]
9f1afe05 184 break
9ccbdfbf 185 }
b490a991 186 if {$start == 0} {
da7c24dd 187 set cmit $leftover($view)
8f7d0cec 188 append cmit [string range $stuff 0 [expr {$i - 1}]]
da7c24dd 189 set leftover($view) {}
8f7d0cec
PM
190 } else {
191 set cmit [string range $stuff $start [expr {$i - 1}]]
b490a991
PM
192 }
193 set start [expr {$i + 1}]
e5ea701b
PM
194 set j [string first "\n" $cmit]
195 set ok 0
16c1ff96 196 set listed 1
e5ea701b
PM
197 if {$j >= 0} {
198 set ids [string range $cmit 0 [expr {$j - 1}]]
16c1ff96
PM
199 if {[string range $ids 0 0] == "-"} {
200 set listed 0
201 set ids [string range $ids 1 end]
202 }
e5ea701b
PM
203 set ok 1
204 foreach id $ids {
8f7d0cec 205 if {[string length $id] != 40} {
e5ea701b
PM
206 set ok 0
207 break
208 }
209 }
210 }
211 if {!$ok} {
7e952e79
PM
212 set shortcmit $cmit
213 if {[string length $shortcmit] > 80} {
214 set shortcmit "[string range $shortcmit 0 80]..."
215 }
8974c6f9 216 error_popup "Can't parse git rev-list output: {$shortcmit}"
b490a991
PM
217 exit 1
218 }
e5ea701b 219 set id [lindex $ids 0]
16c1ff96
PM
220 if {$listed} {
221 set olds [lrange $ids 1 end]
50b44ece 222 set i 0
79b2c75e 223 foreach p $olds {
50b44ece 224 if {$i == 0 || [lsearch -exact $olds $p] >= $i} {
da7c24dd 225 lappend children($view,$p) $id
50b44ece
PM
226 }
227 incr i
79b2c75e 228 }
16c1ff96
PM
229 } else {
230 set olds {}
231 }
da7c24dd
PM
232 if {![info exists children($view,$id)]} {
233 set children($view,$id) {}
79b2c75e 234 }
f7a3e8d2 235 set commitdata($id) [string range $cmit [expr {$j + 1}] end]
da7c24dd
PM
236 set commitrow($view,$id) $commitidx($view)
237 incr commitidx($view)
238 if {$view == $curview} {
239 lappend parentlist $olds
da7c24dd
PM
240 lappend displayorder $id
241 lappend commitlisted $listed
242 } else {
243 lappend vparentlist($view) $olds
da7c24dd
PM
244 lappend vdisporder($view) $id
245 lappend vcmitlisted($view) $listed
246 }
8f7d0cec
PM
247 set gotsome 1
248 }
249 if {$gotsome} {
7eb3cb9c 250 run chewcommits $view
9ccbdfbf 251 }
7eb3cb9c 252 return 2
9ccbdfbf
PM
253}
254
7eb3cb9c
PM
255proc chewcommits {view} {
256 global curview hlview commfd
257 global selectedline pending_select
258
259 set more 0
260 if {$view == $curview} {
261 set allread [expr {![info exists commfd($view)]}]
262 set tlimit [expr {[clock clicks -milliseconds] + 50}]
263 set more [layoutmore $tlimit $allread]
264 if {$allread && !$more} {
219ea3a9 265 global displayorder nullid commitidx phase
7eb3cb9c 266 global numcommits startmsecs
9ccbdfbf 267
7eb3cb9c
PM
268 if {[info exists pending_select]} {
269 set row [expr {[lindex $displayorder 0] eq $nullid}]
270 selectline $row 1
271 }
272 if {$commitidx($curview) > 0} {
273 #set ms [expr {[clock clicks -milliseconds] - $startmsecs}]
274 #puts "overall $ms ms for $numcommits commits"
275 } else {
276 show_status "No commits selected"
277 }
278 notbusy layout
279 set phase {}
280 }
b664550c 281 }
7eb3cb9c
PM
282 if {[info exists hlview] && $view == $hlview} {
283 vhighlightmore
b664550c 284 }
7eb3cb9c 285 return $more
1db95b00
PM
286}
287
288proc readcommit {id} {
8974c6f9 289 if {[catch {set contents [exec git cat-file commit $id]}]} return
8f7d0cec 290 parsecommit $id $contents 0
b490a991
PM
291}
292
50b44ece 293proc updatecommits {} {
098dd8a3 294 global viewdata curview phase displayorder
908c3585 295 global children commitrow selectedline thickerline
50b44ece 296
22626ef4
PM
297 if {$phase ne {}} {
298 stop_rev_list
299 set phase {}
fd8ccbec 300 }
d94f8cd6 301 set n $curview
da7c24dd
PM
302 foreach id $displayorder {
303 catch {unset children($n,$id)}
304 catch {unset commitrow($n,$id)}
305 }
d94f8cd6 306 set curview -1
908c3585
PM
307 catch {unset selectedline}
308 catch {unset thickerline}
d94f8cd6 309 catch {unset viewdata($n)}
fd8ccbec 310 readrefs
e11f1233
PM
311 changedrefs
312 regetallcommits
d94f8cd6 313 showview $n
fd8ccbec
PM
314}
315
8f7d0cec 316proc parsecommit {id contents listed} {
b5c2f306
SV
317 global commitinfo cdate
318
319 set inhdr 1
320 set comment {}
321 set headline {}
322 set auname {}
323 set audate {}
324 set comname {}
325 set comdate {}
232475d3
PM
326 set hdrend [string first "\n\n" $contents]
327 if {$hdrend < 0} {
328 # should never happen...
329 set hdrend [string length $contents]
330 }
331 set header [string range $contents 0 [expr {$hdrend - 1}]]
332 set comment [string range $contents [expr {$hdrend + 2}] end]
333 foreach line [split $header "\n"] {
334 set tag [lindex $line 0]
335 if {$tag == "author"} {
336 set audate [lindex $line end-1]
337 set auname [lrange $line 1 end-2]
338 } elseif {$tag == "committer"} {
339 set comdate [lindex $line end-1]
340 set comname [lrange $line 1 end-2]
1db95b00
PM
341 }
342 }
232475d3 343 set headline {}
43c25074
PM
344 # take the first non-blank line of the comment as the headline
345 set headline [string trimleft $comment]
346 set i [string first "\n" $headline]
232475d3 347 if {$i >= 0} {
43c25074
PM
348 set headline [string range $headline 0 $i]
349 }
350 set headline [string trimright $headline]
351 set i [string first "\r" $headline]
352 if {$i >= 0} {
353 set headline [string trimright [string range $headline 0 $i]]
232475d3
PM
354 }
355 if {!$listed} {
8974c6f9
TH
356 # git rev-list indents the comment by 4 spaces;
357 # if we got this via git cat-file, add the indentation
232475d3
PM
358 set newcomment {}
359 foreach line [split $comment "\n"] {
360 append newcomment " "
361 append newcomment $line
f6e2869f 362 append newcomment "\n"
232475d3
PM
363 }
364 set comment $newcomment
1db95b00
PM
365 }
366 if {$comdate != {}} {
cfb4563c 367 set cdate($id) $comdate
1db95b00 368 }
e5c2d856
PM
369 set commitinfo($id) [list $headline $auname $audate \
370 $comname $comdate $comment]
1db95b00
PM
371}
372
f7a3e8d2 373proc getcommit {id} {
79b2c75e 374 global commitdata commitinfo
8ed16484 375
f7a3e8d2
PM
376 if {[info exists commitdata($id)]} {
377 parsecommit $id $commitdata($id) 1
8ed16484
PM
378 } else {
379 readcommit $id
380 if {![info exists commitinfo($id)]} {
381 set commitinfo($id) {"No commit information available"}
8ed16484
PM
382 }
383 }
384 return 1
385}
386
887fe3c4 387proc readrefs {} {
62d3ea65 388 global tagids idtags headids idheads tagobjid
219ea3a9 389 global otherrefids idotherrefs mainhead mainheadid
106288cb 390
b5c2f306
SV
391 foreach v {tagids idtags headids idheads otherrefids idotherrefs} {
392 catch {unset $v}
393 }
62d3ea65
PM
394 set refd [open [list | git show-ref -d] r]
395 while {[gets $refd line] >= 0} {
396 if {[string index $line 40] ne " "} continue
397 set id [string range $line 0 39]
398 set ref [string range $line 41 end]
399 if {![string match "refs/*" $ref]} continue
400 set name [string range $ref 5 end]
401 if {[string match "remotes/*" $name]} {
402 if {![string match "*/HEAD" $name]} {
403 set headids($name) $id
404 lappend idheads($id) $name
f1d83ba3 405 }
62d3ea65
PM
406 } elseif {[string match "heads/*" $name]} {
407 set name [string range $name 6 end]
36a7cad6
JH
408 set headids($name) $id
409 lappend idheads($id) $name
62d3ea65
PM
410 } elseif {[string match "tags/*" $name]} {
411 # this lets refs/tags/foo^{} overwrite refs/tags/foo,
412 # which is what we want since the former is the commit ID
413 set name [string range $name 5 end]
414 if {[string match "*^{}" $name]} {
415 set name [string range $name 0 end-3]
416 } else {
417 set tagobjid($name) $id
418 }
419 set tagids($name) $id
420 lappend idtags($id) $name
36a7cad6
JH
421 } else {
422 set otherrefids($name) $id
423 lappend idotherrefs($id) $name
f1d83ba3
PM
424 }
425 }
36a7cad6 426 close $refd
8a48571c 427 set mainhead {}
219ea3a9 428 set mainheadid {}
8a48571c
PM
429 catch {
430 set thehead [exec git symbolic-ref HEAD]
431 if {[string match "refs/heads/*" $thehead]} {
432 set mainhead [string range $thehead 11 end]
219ea3a9
PM
433 if {[info exists headids($mainhead)]} {
434 set mainheadid $headids($mainhead)
435 }
8a48571c
PM
436 }
437 }
887fe3c4
PM
438}
439
e11f1233
PM
440# update things for a head moved to a child of its previous location
441proc movehead {id name} {
442 global headids idheads
443
444 removehead $headids($name) $name
445 set headids($name) $id
446 lappend idheads($id) $name
447}
448
449# update things when a head has been removed
450proc removehead {id name} {
451 global headids idheads
452
453 if {$idheads($id) eq $name} {
454 unset idheads($id)
455 } else {
456 set i [lsearch -exact $idheads($id) $name]
457 if {$i >= 0} {
458 set idheads($id) [lreplace $idheads($id) $i $i]
459 }
460 }
461 unset headids($name)
462}
463
e54be9e3 464proc show_error {w top msg} {
df3d83b1
PM
465 message $w.m -text $msg -justify center -aspect 400
466 pack $w.m -side top -fill x -padx 20 -pady 20
e54be9e3 467 button $w.ok -text OK -command "destroy $top"
df3d83b1 468 pack $w.ok -side bottom -fill x
e54be9e3
PM
469 bind $top <Visibility> "grab $top; focus $top"
470 bind $top <Key-Return> "destroy $top"
471 tkwait window $top
df3d83b1
PM
472}
473
098dd8a3
PM
474proc error_popup msg {
475 set w .error
476 toplevel $w
477 wm transient $w .
e54be9e3 478 show_error $w $w $msg
098dd8a3
PM
479}
480
10299152
PM
481proc confirm_popup msg {
482 global confirm_ok
483 set confirm_ok 0
484 set w .confirm
485 toplevel $w
486 wm transient $w .
487 message $w.m -text $msg -justify center -aspect 400
488 pack $w.m -side top -fill x -padx 20 -pady 20
489 button $w.ok -text OK -command "set confirm_ok 1; destroy $w"
490 pack $w.ok -side left -fill x
491 button $w.cancel -text Cancel -command "destroy $w"
492 pack $w.cancel -side right -fill x
493 bind $w <Visibility> "grab $w; focus $w"
494 tkwait window $w
495 return $confirm_ok
496}
497
d94f8cd6 498proc makewindow {} {
fdedbcfb 499 global canv canv2 canv3 linespc charspc ctext cflist
7e12f1a6 500 global textfont mainfont uifont tabstop
b74fd579 501 global findtype findtypemenu findloc findstring fstring geometry
887fe3c4 502 global entries sha1entry sha1string sha1but
94a2eede 503 global maincursor textcursor curtextcursor
219ea3a9 504 global rowctxmenu fakerowmenu mergemax wrapcomment
60f7a7dc 505 global highlight_files gdttype
3ea06f9f 506 global searchstring sstring
60378c0c 507 global bgcolor fgcolor bglist fglist diffcolors selectbgcolor
10299152 508 global headctxmenu
9a40c50c
PM
509
510 menu .bar
511 .bar add cascade -label "File" -menu .bar.file
4840be66 512 .bar configure -font $uifont
9a40c50c 513 menu .bar.file
50b44ece 514 .bar.file add command -label "Update" -command updatecommits
f1d83ba3 515 .bar.file add command -label "Reread references" -command rereadrefs
1d10f36d 516 .bar.file add command -label "Quit" -command doquit
4840be66 517 .bar.file configure -font $uifont
712fcc08
PM
518 menu .bar.edit
519 .bar add cascade -label "Edit" -menu .bar.edit
520 .bar.edit add command -label "Preferences" -command doprefs
4840be66 521 .bar.edit configure -font $uifont
da7c24dd 522
fdedbcfb 523 menu .bar.view -font $uifont
50b44ece 524 .bar add cascade -label "View" -menu .bar.view
da7c24dd
PM
525 .bar.view add command -label "New view..." -command {newview 0}
526 .bar.view add command -label "Edit view..." -command editview \
527 -state disabled
50b44ece
PM
528 .bar.view add command -label "Delete view" -command delview -state disabled
529 .bar.view add separator
a90a6d24
PM
530 .bar.view add radiobutton -label "All files" -command {showview 0} \
531 -variable selectedview -value 0
40b87ff8 532
9a40c50c
PM
533 menu .bar.help
534 .bar add cascade -label "Help" -menu .bar.help
535 .bar.help add command -label "About gitk" -command about
4e95e1f7 536 .bar.help add command -label "Key bindings" -command keys
4840be66 537 .bar.help configure -font $uifont
9a40c50c
PM
538 . configure -menu .bar
539
e9937d2a 540 # the gui has upper and lower half, parts of a paned window.
0327d27a 541 panedwindow .ctop -orient vertical
e9937d2a
JH
542
543 # possibly use assumed geometry
9ca72f4f 544 if {![info exists geometry(pwsash0)]} {
e9937d2a
JH
545 set geometry(topheight) [expr {15 * $linespc}]
546 set geometry(topwidth) [expr {80 * $charspc}]
547 set geometry(botheight) [expr {15 * $linespc}]
548 set geometry(botwidth) [expr {50 * $charspc}]
9ca72f4f
ML
549 set geometry(pwsash0) "[expr {40 * $charspc}] 2"
550 set geometry(pwsash1) "[expr {60 * $charspc}] 2"
e9937d2a
JH
551 }
552
553 # the upper half will have a paned window, a scroll bar to the right, and some stuff below
554 frame .tf -height $geometry(topheight) -width $geometry(topwidth)
555 frame .tf.histframe
556 panedwindow .tf.histframe.pwclist -orient horizontal -sashpad 0 -handlesize 4
557
558 # create three canvases
559 set cscroll .tf.histframe.csb
560 set canv .tf.histframe.pwclist.canv
9ca72f4f 561 canvas $canv \
60378c0c 562 -selectbackground $selectbgcolor \
f8a2c0d1 563 -background $bgcolor -bd 0 \
9f1afe05 564 -yscrollincr $linespc -yscrollcommand "scrollcanv $cscroll"
e9937d2a
JH
565 .tf.histframe.pwclist add $canv
566 set canv2 .tf.histframe.pwclist.canv2
9ca72f4f 567 canvas $canv2 \
60378c0c 568 -selectbackground $selectbgcolor \
f8a2c0d1 569 -background $bgcolor -bd 0 -yscrollincr $linespc
e9937d2a
JH
570 .tf.histframe.pwclist add $canv2
571 set canv3 .tf.histframe.pwclist.canv3
9ca72f4f 572 canvas $canv3 \
60378c0c 573 -selectbackground $selectbgcolor \
f8a2c0d1 574 -background $bgcolor -bd 0 -yscrollincr $linespc
e9937d2a 575 .tf.histframe.pwclist add $canv3
9ca72f4f
ML
576 eval .tf.histframe.pwclist sash place 0 $geometry(pwsash0)
577 eval .tf.histframe.pwclist sash place 1 $geometry(pwsash1)
e9937d2a
JH
578
579 # a scroll bar to rule them
580 scrollbar $cscroll -command {allcanvs yview} -highlightthickness 0
581 pack $cscroll -side right -fill y
582 bind .tf.histframe.pwclist <Configure> {resizeclistpanes %W %w}
f8a2c0d1 583 lappend bglist $canv $canv2 $canv3
e9937d2a 584 pack .tf.histframe.pwclist -fill both -expand 1 -side left
98f350e5 585
e9937d2a
JH
586 # we have two button bars at bottom of top frame. Bar 1
587 frame .tf.bar
588 frame .tf.lbar -height 15
589
590 set sha1entry .tf.bar.sha1
887fe3c4 591 set entries $sha1entry
e9937d2a 592 set sha1but .tf.bar.sha1label
887fe3c4 593 button $sha1but -text "SHA1 ID: " -state disabled -relief flat \
4840be66 594 -command gotocommit -width 8 -font $uifont
887fe3c4 595 $sha1but conf -disabledforeground [$sha1but cget -foreground]
e9937d2a 596 pack .tf.bar.sha1label -side left
887fe3c4
PM
597 entry $sha1entry -width 40 -font $textfont -textvariable sha1string
598 trace add variable sha1string write sha1change
98f350e5 599 pack $sha1entry -side left -pady 2
d698206c
PM
600
601 image create bitmap bm-left -data {
602 #define left_width 16
603 #define left_height 16
604 static unsigned char left_bits[] = {
605 0x00, 0x00, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1c, 0x00,
606 0x0e, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x0e, 0x00, 0x1c, 0x00,
607 0x38, 0x00, 0x70, 0x00, 0xe0, 0x00, 0xc0, 0x01};
608 }
609 image create bitmap bm-right -data {
610 #define right_width 16
611 #define right_height 16
612 static unsigned char right_bits[] = {
613 0x00, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x1c,
614 0x00, 0x38, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x38, 0x00, 0x1c,
615 0x00, 0x0e, 0x00, 0x07, 0x80, 0x03, 0xc0, 0x01};
616 }
e9937d2a 617 button .tf.bar.leftbut -image bm-left -command goback \
d698206c 618 -state disabled -width 26
e9937d2a
JH
619 pack .tf.bar.leftbut -side left -fill y
620 button .tf.bar.rightbut -image bm-right -command goforw \
d698206c 621 -state disabled -width 26
e9937d2a 622 pack .tf.bar.rightbut -side left -fill y
d698206c 623
e9937d2a
JH
624 button .tf.bar.findbut -text "Find" -command dofind -font $uifont
625 pack .tf.bar.findbut -side left
98f350e5 626 set findstring {}
e9937d2a 627 set fstring .tf.bar.findstring
887fe3c4 628 lappend entries $fstring
908c3585 629 entry $fstring -width 30 -font $textfont -textvariable findstring
60f7a7dc 630 trace add variable findstring write find_change
e9937d2a 631 pack $fstring -side left -expand 1 -fill x -in .tf.bar
98f350e5 632 set findtype Exact
e9937d2a
JH
633 set findtypemenu [tk_optionMenu .tf.bar.findtype \
634 findtype Exact IgnCase Regexp]
60f7a7dc 635 trace add variable findtype write find_change
e9937d2a
JH
636 .tf.bar.findtype configure -font $uifont
637 .tf.bar.findtype.menu configure -font $uifont
98f350e5 638 set findloc "All fields"
e9937d2a 639 tk_optionMenu .tf.bar.findloc findloc "All fields" Headline \
60f7a7dc
PM
640 Comments Author Committer
641 trace add variable findloc write find_change
e9937d2a
JH
642 .tf.bar.findloc configure -font $uifont
643 .tf.bar.findloc.menu configure -font $uifont
644 pack .tf.bar.findloc -side right
645 pack .tf.bar.findtype -side right
646
647 # build up the bottom bar of upper window
648 label .tf.lbar.flabel -text "Highlight: Commits " \
649 -font $uifont
650 pack .tf.lbar.flabel -side left -fill y
60f7a7dc 651 set gdttype "touching paths:"
e9937d2a
JH
652 set gm [tk_optionMenu .tf.lbar.gdttype gdttype "touching paths:" \
653 "adding/removing string:"]
60f7a7dc
PM
654 trace add variable gdttype write hfiles_change
655 $gm conf -font $uifont
e9937d2a
JH
656 .tf.lbar.gdttype conf -font $uifont
657 pack .tf.lbar.gdttype -side left -fill y
658 entry .tf.lbar.fent -width 25 -font $textfont \
908c3585
PM
659 -textvariable highlight_files
660 trace add variable highlight_files write hfiles_change
e9937d2a
JH
661 lappend entries .tf.lbar.fent
662 pack .tf.lbar.fent -side left -fill x -expand 1
663 label .tf.lbar.vlabel -text " OR in view" -font $uifont
664 pack .tf.lbar.vlabel -side left -fill y
908c3585 665 global viewhlmenu selectedhlview
e9937d2a 666 set viewhlmenu [tk_optionMenu .tf.lbar.vhl selectedhlview None]
3cd204e5 667 $viewhlmenu entryconf None -command delvhighlight
63b79191 668 $viewhlmenu conf -font $uifont
e9937d2a
JH
669 .tf.lbar.vhl conf -font $uifont
670 pack .tf.lbar.vhl -side left -fill y
671 label .tf.lbar.rlabel -text " OR " -font $uifont
672 pack .tf.lbar.rlabel -side left -fill y
164ff275 673 global highlight_related
e9937d2a
JH
674 set m [tk_optionMenu .tf.lbar.relm highlight_related None \
675 "Descendent" "Not descendent" "Ancestor" "Not ancestor"]
164ff275 676 $m conf -font $uifont
e9937d2a 677 .tf.lbar.relm conf -font $uifont
164ff275 678 trace add variable highlight_related write vrel_change
e9937d2a
JH
679 pack .tf.lbar.relm -side left -fill y
680
681 # Finish putting the upper half of the viewer together
682 pack .tf.lbar -in .tf -side bottom -fill x
683 pack .tf.bar -in .tf -side bottom -fill x
684 pack .tf.histframe -fill both -side top -expand 1
685 .ctop add .tf
9ca72f4f
ML
686 .ctop paneconfigure .tf -height $geometry(topheight)
687 .ctop paneconfigure .tf -width $geometry(topwidth)
e9937d2a
JH
688
689 # now build up the bottom
690 panedwindow .pwbottom -orient horizontal
691
692 # lower left, a text box over search bar, scroll bar to the right
693 # if we know window height, then that will set the lower text height, otherwise
694 # we set lower text height which will drive window height
695 if {[info exists geometry(main)]} {
696 frame .bleft -width $geometry(botwidth)
697 } else {
698 frame .bleft -width $geometry(botwidth) -height $geometry(botheight)
699 }
700 frame .bleft.top
a8d610a2 701 frame .bleft.mid
e9937d2a
JH
702
703 button .bleft.top.search -text "Search" -command dosearch \
3ea06f9f 704 -font $uifont
e9937d2a
JH
705 pack .bleft.top.search -side left -padx 5
706 set sstring .bleft.top.sstring
3ea06f9f
PM
707 entry $sstring -width 20 -font $textfont -textvariable searchstring
708 lappend entries $sstring
709 trace add variable searchstring write incrsearch
710 pack $sstring -side left -expand 1 -fill x
a8d610a2
PM
711 radiobutton .bleft.mid.diff -text "Diff" \
712 -command changediffdisp -variable diffelide -value {0 0}
713 radiobutton .bleft.mid.old -text "Old version" \
714 -command changediffdisp -variable diffelide -value {0 1}
715 radiobutton .bleft.mid.new -text "New version" \
716 -command changediffdisp -variable diffelide -value {1 0}
717 pack .bleft.mid.diff .bleft.mid.old .bleft.mid.new -side left
e9937d2a 718 set ctext .bleft.ctext
f8a2c0d1 719 text $ctext -background $bgcolor -foreground $fgcolor \
7e12f1a6 720 -tabs "[expr {$tabstop * $charspc}]" \
f8a2c0d1 721 -state disabled -font $textfont \
3ea06f9f 722 -yscrollcommand scrolltext -wrap none
e9937d2a
JH
723 scrollbar .bleft.sb -command "$ctext yview"
724 pack .bleft.top -side top -fill x
a8d610a2 725 pack .bleft.mid -side top -fill x
e9937d2a 726 pack .bleft.sb -side right -fill y
d2610d11 727 pack $ctext -side left -fill both -expand 1
f8a2c0d1
PM
728 lappend bglist $ctext
729 lappend fglist $ctext
d2610d11 730
f1b86294 731 $ctext tag conf comment -wrap $wrapcomment
f0654861 732 $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
f8a2c0d1
PM
733 $ctext tag conf hunksep -fore [lindex $diffcolors 2]
734 $ctext tag conf d0 -fore [lindex $diffcolors 0]
735 $ctext tag conf d1 -fore [lindex $diffcolors 1]
712fcc08
PM
736 $ctext tag conf m0 -fore red
737 $ctext tag conf m1 -fore blue
738 $ctext tag conf m2 -fore green
739 $ctext tag conf m3 -fore purple
740 $ctext tag conf m4 -fore brown
b77b0278
PM
741 $ctext tag conf m5 -fore "#009090"
742 $ctext tag conf m6 -fore magenta
743 $ctext tag conf m7 -fore "#808000"
744 $ctext tag conf m8 -fore "#009000"
745 $ctext tag conf m9 -fore "#ff0080"
746 $ctext tag conf m10 -fore cyan
747 $ctext tag conf m11 -fore "#b07070"
748 $ctext tag conf m12 -fore "#70b0f0"
749 $ctext tag conf m13 -fore "#70f0b0"
750 $ctext tag conf m14 -fore "#f0b070"
751 $ctext tag conf m15 -fore "#ff70b0"
712fcc08 752 $ctext tag conf mmax -fore darkgrey
b77b0278 753 set mergemax 16
712fcc08
PM
754 $ctext tag conf mresult -font [concat $textfont bold]
755 $ctext tag conf msep -font [concat $textfont bold]
756 $ctext tag conf found -back yellow
e5c2d856 757
e9937d2a 758 .pwbottom add .bleft
9ca72f4f 759 .pwbottom paneconfigure .bleft -width $geometry(botwidth)
e9937d2a
JH
760
761 # lower right
762 frame .bright
763 frame .bright.mode
764 radiobutton .bright.mode.patch -text "Patch" \
f8b28a40 765 -command reselectline -variable cmitmode -value "patch"
d59c4b6f 766 .bright.mode.patch configure -font $uifont
e9937d2a 767 radiobutton .bright.mode.tree -text "Tree" \
f8b28a40 768 -command reselectline -variable cmitmode -value "tree"
d59c4b6f 769 .bright.mode.tree configure -font $uifont
e9937d2a
JH
770 grid .bright.mode.patch .bright.mode.tree -sticky ew
771 pack .bright.mode -side top -fill x
772 set cflist .bright.cfiles
7fcceed7 773 set indent [font measure $mainfont "nn"]
e9937d2a 774 text $cflist \
60378c0c 775 -selectbackground $selectbgcolor \
f8a2c0d1
PM
776 -background $bgcolor -foreground $fgcolor \
777 -font $mainfont \
7fcceed7 778 -tabs [list $indent [expr {2 * $indent}]] \
e9937d2a 779 -yscrollcommand ".bright.sb set" \
7fcceed7
PM
780 -cursor [. cget -cursor] \
781 -spacing1 1 -spacing3 1
f8a2c0d1
PM
782 lappend bglist $cflist
783 lappend fglist $cflist
e9937d2a
JH
784 scrollbar .bright.sb -command "$cflist yview"
785 pack .bright.sb -side right -fill y
d2610d11 786 pack $cflist -side left -fill both -expand 1
89b11d3b
PM
787 $cflist tag configure highlight \
788 -background [$cflist cget -selectbackground]
63b79191 789 $cflist tag configure bold -font [concat $mainfont bold]
d2610d11 790
e9937d2a
JH
791 .pwbottom add .bright
792 .ctop add .pwbottom
1db95b00 793
e9937d2a
JH
794 # restore window position if known
795 if {[info exists geometry(main)]} {
796 wm geometry . "$geometry(main)"
797 }
798
799 bind .pwbottom <Configure> {resizecdetpanes %W %w}
800 pack .ctop -fill both -expand 1
c8dfbcf9
PM
801 bindall <1> {selcanvline %W %x %y}
802 #bindall <B1-Motion> {selcanvline %W %x %y}
cfb4563c
PM
803 bindall <ButtonRelease-4> "allcanvs yview scroll -5 units"
804 bindall <ButtonRelease-5> "allcanvs yview scroll 5 units"
be0cd098
PM
805 bindall <2> "canvscan mark %W %x %y"
806 bindall <B2-Motion> "canvscan dragto %W %x %y"
6e5f7203
RN
807 bindkey <Home> selfirstline
808 bindkey <End> sellastline
17386066
PM
809 bind . <Key-Up> "selnextline -1"
810 bind . <Key-Down> "selnextline 1"
4e7d6779
PM
811 bind . <Shift-Key-Up> "next_highlight -1"
812 bind . <Shift-Key-Down> "next_highlight 1"
6e5f7203
RN
813 bindkey <Key-Right> "goforw"
814 bindkey <Key-Left> "goback"
815 bind . <Key-Prior> "selnextpage -1"
816 bind . <Key-Next> "selnextpage 1"
817 bind . <Control-Home> "allcanvs yview moveto 0.0"
818 bind . <Control-End> "allcanvs yview moveto 1.0"
819 bind . <Control-Key-Up> "allcanvs yview scroll -1 units"
820 bind . <Control-Key-Down> "allcanvs yview scroll 1 units"
821 bind . <Control-Key-Prior> "allcanvs yview scroll -1 pages"
822 bind . <Control-Key-Next> "allcanvs yview scroll 1 pages"
cfb4563c
PM
823 bindkey <Key-Delete> "$ctext yview scroll -1 pages"
824 bindkey <Key-BackSpace> "$ctext yview scroll -1 pages"
825 bindkey <Key-space> "$ctext yview scroll 1 pages"
df3d83b1
PM
826 bindkey p "selnextline -1"
827 bindkey n "selnextline 1"
6e2dda35
RS
828 bindkey z "goback"
829 bindkey x "goforw"
830 bindkey i "selnextline -1"
831 bindkey k "selnextline 1"
832 bindkey j "goback"
833 bindkey l "goforw"
cfb4563c
PM
834 bindkey b "$ctext yview scroll -1 pages"
835 bindkey d "$ctext yview scroll 18 units"
836 bindkey u "$ctext yview scroll -18 units"
b74fd579
PM
837 bindkey / {findnext 1}
838 bindkey <Key-Return> {findnext 0}
df3d83b1 839 bindkey ? findprev
39ad8570 840 bindkey f nextfile
e7a09191 841 bindkey <F5> updatecommits
1d10f36d 842 bind . <Control-q> doquit
98f350e5 843 bind . <Control-f> dofind
b74fd579 844 bind . <Control-g> {findnext 0}
1902c270 845 bind . <Control-r> dosearchback
3ea06f9f 846 bind . <Control-s> dosearch
1d10f36d
PM
847 bind . <Control-equal> {incrfont 1}
848 bind . <Control-KP_Add> {incrfont 1}
849 bind . <Control-minus> {incrfont -1}
850 bind . <Control-KP_Subtract> {incrfont -1}
b6047c5a 851 wm protocol . WM_DELETE_WINDOW doquit
df3d83b1 852 bind . <Button-1> "click %W"
17386066 853 bind $fstring <Key-Return> dofind
887fe3c4 854 bind $sha1entry <Key-Return> gotocommit
ee3dc72e 855 bind $sha1entry <<PasteSelection>> clearsha1
7fcceed7
PM
856 bind $cflist <1> {sel_flist %W %x %y; break}
857 bind $cflist <B1-Motion> {sel_flist %W %x %y; break}
f8b28a40 858 bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
ea13cba1
PM
859
860 set maincursor [. cget -cursor]
861 set textcursor [$ctext cget -cursor]
94a2eede 862 set curtextcursor $textcursor
84ba7345 863
c8dfbcf9
PM
864 set rowctxmenu .rowctxmenu
865 menu $rowctxmenu -tearoff 0
866 $rowctxmenu add command -label "Diff this -> selected" \
867 -command {diffvssel 0}
868 $rowctxmenu add command -label "Diff selected -> this" \
869 -command {diffvssel 1}
74daedb6 870 $rowctxmenu add command -label "Make patch" -command mkpatch
bdbfbe3d 871 $rowctxmenu add command -label "Create tag" -command mktag
4a2139f5 872 $rowctxmenu add command -label "Write commit to file" -command writecommit
d6ac1a86 873 $rowctxmenu add command -label "Create new branch" -command mkbranch
ca6d8f58
PM
874 $rowctxmenu add command -label "Cherry-pick this commit" \
875 -command cherrypick
6fb735ae
PM
876 $rowctxmenu add command -label "Reset HEAD branch to here" \
877 -command resethead
10299152 878
219ea3a9
PM
879 set fakerowmenu .fakerowmenu
880 menu $fakerowmenu -tearoff 0
881 $fakerowmenu add command -label "Diff this -> selected" \
882 -command {diffvssel 0}
883 $fakerowmenu add command -label "Diff selected -> this" \
884 -command {diffvssel 1}
885 $fakerowmenu add command -label "Make patch" -command mkpatch
886# $fakerowmenu add command -label "Commit" -command {mkcommit 0}
887# $fakerowmenu add command -label "Commit all" -command {mkcommit 1}
888# $fakerowmenu add command -label "Revert local changes" -command revertlocal
889
10299152
PM
890 set headctxmenu .headctxmenu
891 menu $headctxmenu -tearoff 0
892 $headctxmenu add command -label "Check out this branch" \
893 -command cobranch
894 $headctxmenu add command -label "Remove this branch" \
895 -command rmbranch
df3d83b1
PM
896}
897
be0cd098
PM
898# mouse-2 makes all windows scan vertically, but only the one
899# the cursor is in scans horizontally
900proc canvscan {op w x y} {
901 global canv canv2 canv3
902 foreach c [list $canv $canv2 $canv3] {
903 if {$c == $w} {
904 $c scan $op $x $y
905 } else {
906 $c scan $op 0 $y
907 }
908 }
909}
910
9f1afe05
PM
911proc scrollcanv {cscroll f0 f1} {
912 $cscroll set $f0 $f1
913 drawfrac $f0 $f1
908c3585 914 flushhighlights
9f1afe05
PM
915}
916
df3d83b1
PM
917# when we make a key binding for the toplevel, make sure
918# it doesn't get triggered when that key is pressed in the
919# find string entry widget.
920proc bindkey {ev script} {
887fe3c4 921 global entries
df3d83b1
PM
922 bind . $ev $script
923 set escript [bind Entry $ev]
924 if {$escript == {}} {
925 set escript [bind Entry <Key>]
926 }
887fe3c4
PM
927 foreach e $entries {
928 bind $e $ev "$escript; break"
929 }
df3d83b1
PM
930}
931
932# set the focus back to the toplevel for any click outside
887fe3c4 933# the entry widgets
df3d83b1 934proc click {w} {
887fe3c4
PM
935 global entries
936 foreach e $entries {
937 if {$w == $e} return
df3d83b1 938 }
887fe3c4 939 focus .
0fba86b3
PM
940}
941
942proc savestuff {w} {
7e12f1a6 943 global canv canv2 canv3 ctext cflist mainfont textfont uifont tabstop
712fcc08 944 global stuffsaved findmergefiles maxgraphpct
219ea3a9 945 global maxwidth showneartags showlocalchanges
098dd8a3 946 global viewname viewfiles viewargs viewperm nextviewnum
f1b86294 947 global cmitmode wrapcomment
60378c0c 948 global colors bgcolor fgcolor diffcolors selectbgcolor
4ef17537 949
0fba86b3 950 if {$stuffsaved} return
df3d83b1 951 if {![winfo viewable .]} return
0fba86b3
PM
952 catch {
953 set f [open "~/.gitk-new" w]
f0654861
PM
954 puts $f [list set mainfont $mainfont]
955 puts $f [list set textfont $textfont]
4840be66 956 puts $f [list set uifont $uifont]
7e12f1a6 957 puts $f [list set tabstop $tabstop]
f0654861 958 puts $f [list set findmergefiles $findmergefiles]
8d858d1a 959 puts $f [list set maxgraphpct $maxgraphpct]
04c13d38 960 puts $f [list set maxwidth $maxwidth]
f8b28a40 961 puts $f [list set cmitmode $cmitmode]
f1b86294 962 puts $f [list set wrapcomment $wrapcomment]
b8ab2e17 963 puts $f [list set showneartags $showneartags]
219ea3a9 964 puts $f [list set showlocalchanges $showlocalchanges]
f8a2c0d1
PM
965 puts $f [list set bgcolor $bgcolor]
966 puts $f [list set fgcolor $fgcolor]
967 puts $f [list set colors $colors]
968 puts $f [list set diffcolors $diffcolors]
60378c0c 969 puts $f [list set selectbgcolor $selectbgcolor]
e9937d2a 970
b6047c5a 971 puts $f "set geometry(main) [wm geometry .]"
e9937d2a
JH
972 puts $f "set geometry(topwidth) [winfo width .tf]"
973 puts $f "set geometry(topheight) [winfo height .tf]"
9ca72f4f
ML
974 puts $f "set geometry(pwsash0) \"[.tf.histframe.pwclist sash coord 0]\""
975 puts $f "set geometry(pwsash1) \"[.tf.histframe.pwclist sash coord 1]\""
e9937d2a
JH
976 puts $f "set geometry(botwidth) [winfo width .bleft]"
977 puts $f "set geometry(botheight) [winfo height .bleft]"
978
a90a6d24
PM
979 puts -nonewline $f "set permviews {"
980 for {set v 0} {$v < $nextviewnum} {incr v} {
981 if {$viewperm($v)} {
098dd8a3 982 puts $f "{[list $viewname($v) $viewfiles($v) $viewargs($v)]}"
a90a6d24
PM
983 }
984 }
985 puts $f "}"
0fba86b3
PM
986 close $f
987 file rename -force "~/.gitk-new" "~/.gitk"
988 }
989 set stuffsaved 1
1db95b00
PM
990}
991
43bddeb4
PM
992proc resizeclistpanes {win w} {
993 global oldwidth
418c4c7b 994 if {[info exists oldwidth($win)]} {
43bddeb4
PM
995 set s0 [$win sash coord 0]
996 set s1 [$win sash coord 1]
997 if {$w < 60} {
998 set sash0 [expr {int($w/2 - 2)}]
999 set sash1 [expr {int($w*5/6 - 2)}]
1000 } else {
1001 set factor [expr {1.0 * $w / $oldwidth($win)}]
1002 set sash0 [expr {int($factor * [lindex $s0 0])}]
1003 set sash1 [expr {int($factor * [lindex $s1 0])}]
1004 if {$sash0 < 30} {
1005 set sash0 30
1006 }
1007 if {$sash1 < $sash0 + 20} {
2ed49d54 1008 set sash1 [expr {$sash0 + 20}]
43bddeb4
PM
1009 }
1010 if {$sash1 > $w - 10} {
2ed49d54 1011 set sash1 [expr {$w - 10}]
43bddeb4 1012 if {$sash0 > $sash1 - 20} {
2ed49d54 1013 set sash0 [expr {$sash1 - 20}]
43bddeb4
PM
1014 }
1015 }
1016 }
1017 $win sash place 0 $sash0 [lindex $s0 1]
1018 $win sash place 1 $sash1 [lindex $s1 1]
1019 }
1020 set oldwidth($win) $w
1021}
1022
1023proc resizecdetpanes {win w} {
1024 global oldwidth
418c4c7b 1025 if {[info exists oldwidth($win)]} {
43bddeb4
PM
1026 set s0 [$win sash coord 0]
1027 if {$w < 60} {
1028 set sash0 [expr {int($w*3/4 - 2)}]
1029 } else {
1030 set factor [expr {1.0 * $w / $oldwidth($win)}]
1031 set sash0 [expr {int($factor * [lindex $s0 0])}]
1032 if {$sash0 < 45} {
1033 set sash0 45
1034 }
1035 if {$sash0 > $w - 15} {
2ed49d54 1036 set sash0 [expr {$w - 15}]
43bddeb4
PM
1037 }
1038 }
1039 $win sash place 0 $sash0 [lindex $s0 1]
1040 }
1041 set oldwidth($win) $w
1042}
1043
b5721c72
PM
1044proc allcanvs args {
1045 global canv canv2 canv3
1046 eval $canv $args
1047 eval $canv2 $args
1048 eval $canv3 $args
1049}
1050
1051proc bindall {event action} {
1052 global canv canv2 canv3
1053 bind $canv $event $action
1054 bind $canv2 $event $action
1055 bind $canv3 $event $action
1056}
1057
9a40c50c 1058proc about {} {
d59c4b6f 1059 global uifont
9a40c50c
PM
1060 set w .about
1061 if {[winfo exists $w]} {
1062 raise $w
1063 return
1064 }
1065 toplevel $w
1066 wm title $w "About gitk"
1067 message $w.m -text {
9f1afe05 1068Gitk - a commit viewer for git
9a40c50c 1069
9f1afe05 1070