]> git.ipfire.org Git - thirdparty/git.git/blame - git-gui
git-gui: Reverted file name text field to a label.
[thirdparty/git.git] / git-gui
CommitLineData
cb07fc2a
SP
1#!/bin/sh
2# Tcl ignores the next line -*- tcl -*- \
3exec wish "$0" -- "$@"
4
5# Copyright (C) 2006 Shawn Pearce, 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
da5239dc
SP
10set appname [lindex [file split $argv0] end]
11set gitdir {}
12
2d19516d
SP
13######################################################################
14##
15## config
16
51f4d16b
SP
17proc is_many_config {name} {
18 switch -glob -- $name {
19 remote.*.fetch -
20 remote.*.push
21 {return 1}
22 *
23 {return 0}
24 }
25}
2d19516d 26
6bbd1cb9 27proc load_config {include_global} {
51f4d16b
SP
28 global repo_config global_config default_config
29
30 array unset global_config
6bbd1cb9
SP
31 if {$include_global} {
32 catch {
33 set fd_rc [open "| git repo-config --global --list" r]
34 while {[gets $fd_rc line] >= 0} {
35 if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
36 if {[is_many_config $name]} {
37 lappend global_config($name) $value
38 } else {
39 set global_config($name) $value
40 }
51f4d16b
SP
41 }
42 }
6bbd1cb9 43 close $fd_rc
51f4d16b 44 }
51f4d16b 45 }
6bbd1cb9
SP
46
47 array unset repo_config
2d19516d
SP
48 catch {
49 set fd_rc [open "| git repo-config --list" r]
50 while {[gets $fd_rc line] >= 0} {
51 if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
51f4d16b
SP
52 if {[is_many_config $name]} {
53 lappend repo_config($name) $value
54 } else {
55 set repo_config($name) $value
56 }
2d19516d
SP
57 }
58 }
59 close $fd_rc
60 }
61
51f4d16b
SP
62 foreach name [array names default_config] {
63 if {[catch {set v $global_config($name)}]} {
64 set global_config($name) $default_config($name)
65 }
66 if {[catch {set v $repo_config($name)}]} {
67 set repo_config($name) $default_config($name)
68 }
2d19516d
SP
69 }
70}
71
51f4d16b 72proc save_config {} {
92148d80
SP
73 global default_config font_descs
74 global repo_config global_config
51f4d16b 75 global repo_config_new global_config_new
2d19516d 76
92148d80
SP
77 foreach option $font_descs {
78 set name [lindex $option 0]
79 set font [lindex $option 1]
80 font configure $font \
81 -family $global_config_new(gui.$font^^family) \
82 -size $global_config_new(gui.$font^^size)
83 font configure ${font}bold \
84 -family $global_config_new(gui.$font^^family) \
85 -size $global_config_new(gui.$font^^size)
86 set global_config_new(gui.$name) [font configure $font]
87 unset global_config_new(gui.$font^^family)
88 unset global_config_new(gui.$font^^size)
89 }
90
91 foreach name [array names default_config] {
51f4d16b 92 set value $global_config_new($name)
043f7011
SP
93 if {$value ne $global_config($name)} {
94 if {$value eq $default_config($name)} {
51f4d16b
SP
95 catch {exec git repo-config --global --unset $name}
96 } else {
7b64d0b7
SP
97 regsub -all "\[{}\]" $value {"} value
98 exec git repo-config --global $name $value
51f4d16b
SP
99 }
100 set global_config($name) $value
043f7011 101 if {$value eq $repo_config($name)} {
51f4d16b
SP
102 catch {exec git repo-config --unset $name}
103 set repo_config($name) $value
104 }
105 }
2d19516d
SP
106 }
107
92148d80 108 foreach name [array names default_config] {
51f4d16b 109 set value $repo_config_new($name)
043f7011
SP
110 if {$value ne $repo_config($name)} {
111 if {$value eq $global_config($name)} {
51f4d16b
SP
112 catch {exec git repo-config --unset $name}
113 } else {
7b64d0b7
SP
114 regsub -all "\[{}\]" $value {"} value
115 exec git repo-config $name $value
51f4d16b
SP
116 }
117 set repo_config($name) $value
118 }
2d19516d
SP
119 }
120}
121
da5239dc
SP
122proc error_popup {msg} {
123 global gitdir appname
124
125 set title $appname
043f7011 126 if {$gitdir ne {}} {
da5239dc
SP
127 append title { (}
128 append title [lindex \
129 [file split [file normalize [file dirname $gitdir]]] \
130 end]
131 append title {)}
132 }
44be340e
SP
133 tk_messageBox \
134 -parent . \
da5239dc
SP
135 -icon error \
136 -type ok \
137 -title "$title: error" \
138 -message $msg
139}
140
16403d0b
SP
141proc info_popup {msg} {
142 global gitdir appname
143
144 set title $appname
043f7011 145 if {$gitdir ne {}} {
16403d0b
SP
146 append title { (}
147 append title [lindex \
148 [file split [file normalize [file dirname $gitdir]]] \
149 end]
150 append title {)}
151 }
152 tk_messageBox \
153 -parent . \
154 -icon error \
155 -type ok \
156 -title $title \
157 -message $msg
158}
159
2d19516d
SP
160######################################################################
161##
162## repository setup
163
44be340e
SP
164if { [catch {set cdup [exec git rev-parse --show-cdup]} err]
165 || [catch {set gitdir [exec git rev-parse --git-dir]} err]} {
166 catch {wm withdraw .}
167 error_popup "Cannot find the git directory:\n\n$err"
2d19516d
SP
168 exit 1
169}
043f7011 170if {$cdup ne ""} {
2d19516d
SP
171 cd $cdup
172}
173unset cdup
174
4ccdab02 175set single_commit 0
043f7011 176if {$appname eq {git-citool}} {
2d19516d
SP
177 set single_commit 1
178}
179
cb07fc2a
SP
180######################################################################
181##
e210e674 182## task management
cb07fc2a
SP
183
184set status_active 0
131f503b 185set diff_active 0
131f503b 186
e210e674
SP
187set disable_on_lock [list]
188set index_lock_type none
189
e57ca85e
SP
190set HEAD {}
191set PARENT {}
192set commit_type {}
193
e210e674
SP
194proc lock_index {type} {
195 global index_lock_type disable_on_lock
131f503b 196
043f7011 197 if {$index_lock_type eq {none}} {
e210e674
SP
198 set index_lock_type $type
199 foreach w $disable_on_lock {
200 uplevel #0 $w disabled
201 }
202 return 1
043f7011 203 } elseif {$index_lock_type eq {begin-update} && $type eq {update}} {
e210e674 204 set index_lock_type $type
131f503b
SP
205 return 1
206 }
207 return 0
208}
cb07fc2a 209
e210e674
SP
210proc unlock_index {} {
211 global index_lock_type disable_on_lock
212
213 set index_lock_type none
214 foreach w $disable_on_lock {
215 uplevel #0 $w normal
216 }
217}
218
219######################################################################
220##
221## status
222
ec6b424a
SP
223proc repository_state {hdvar ctvar} {
224 global gitdir
225 upvar $hdvar hd $ctvar ct
226
227 if {[catch {set hd [exec git rev-parse --verify HEAD]}]} {
228 set ct initial
229 } elseif {[file exists [file join $gitdir MERGE_HEAD]]} {
230 set ct merge
231 } else {
232 set ct normal
233 }
234}
235
e57ca85e
SP
236proc update_status {{final Ready.}} {
237 global HEAD PARENT commit_type
131f503b 238 global ui_index ui_other ui_status_value ui_comm
7f1df79b 239 global status_active file_states
51f4d16b 240 global repo_config
cb07fc2a 241
e210e674 242 if {$status_active || ![lock_index read]} return
cb07fc2a 243
e57ca85e 244 repository_state new_HEAD new_type
043f7011
SP
245 if {$commit_type eq {amend}
246 && $new_type eq {normal}
247 && $new_HEAD eq $HEAD} {
e57ca85e
SP
248 } else {
249 set HEAD $new_HEAD
250 set PARENT $new_HEAD
251 set commit_type $new_type
252 }
253
cb07fc2a 254 array unset file_states
cb07fc2a 255
131f503b 256 if {![$ui_comm edit modified]
043f7011 257 || [string trim [$ui_comm get 0.0 end]] eq {}} {
131f503b
SP
258 if {[load_message GITGUI_MSG]} {
259 } elseif {[load_message MERGE_MSG]} {
260 } elseif {[load_message SQUASH_MSG]} {
261 }
262 $ui_comm edit modified false
b2c6fcf1 263 $ui_comm edit reset
131f503b
SP
264 }
265
043f7011 266 if {$repo_config(gui.trustmtime) eq {true}} {
e534f3a8
SP
267 update_status_stage2 {} $final
268 } else {
269 set status_active 1
270 set ui_status_value {Refreshing file status...}
16403d0b
SP
271 set cmd [list git update-index]
272 lappend cmd -q
273 lappend cmd --unmerged
274 lappend cmd --ignore-missing
275 lappend cmd --refresh
276 set fd_rf [open "| $cmd" r]
e534f3a8 277 fconfigure $fd_rf -blocking 0 -translation binary
390adaea
SP
278 fileevent $fd_rf readable \
279 [list update_status_stage2 $fd_rf $final]
e534f3a8 280 }
131f503b
SP
281}
282
e534f3a8 283proc update_status_stage2 {fd final} {
e57ca85e 284 global gitdir PARENT commit_type
131f503b 285 global ui_index ui_other ui_status_value ui_comm
03e4ec53 286 global status_active
868c8752 287 global buf_rdi buf_rdf buf_rlo
131f503b 288
043f7011 289 if {$fd ne {}} {
e534f3a8
SP
290 read $fd
291 if {![eof $fd]} return
292 close $fd
293 }
131f503b 294
cb07fc2a
SP
295 set ls_others [list | git ls-files --others -z \
296 --exclude-per-directory=.gitignore]
297 set info_exclude [file join $gitdir info exclude]
298 if {[file readable $info_exclude]} {
299 lappend ls_others "--exclude-from=$info_exclude"
300 }
301
868c8752
SP
302 set buf_rdi {}
303 set buf_rdf {}
304 set buf_rlo {}
305
131f503b
SP
306 set status_active 3
307 set ui_status_value {Scanning for modified files ...}
e57ca85e 308 set fd_di [open "| git diff-index --cached -z $PARENT" r]
cb07fc2a
SP
309 set fd_df [open "| git diff-files -z" r]
310 set fd_lo [open $ls_others r]
cb07fc2a
SP
311
312 fconfigure $fd_di -blocking 0 -translation binary
313 fconfigure $fd_df -blocking 0 -translation binary
314 fconfigure $fd_lo -blocking 0 -translation binary
e57ca85e
SP
315 fileevent $fd_di readable [list read_diff_index $fd_di $final]
316 fileevent $fd_df readable [list read_diff_files $fd_df $final]
317 fileevent $fd_lo readable [list read_ls_others $fd_lo $final]
cb07fc2a
SP
318}
319
131f503b
SP
320proc load_message {file} {
321 global gitdir ui_comm
322
323 set f [file join $gitdir $file]
e57ca85e 324 if {[file isfile $f]} {
131f503b
SP
325 if {[catch {set fd [open $f r]}]} {
326 return 0
327 }
e57ca85e 328 set content [string trim [read $fd]]
131f503b
SP
329 close $fd
330 $ui_comm delete 0.0 end
331 $ui_comm insert end $content
332 return 1
333 }
334 return 0
335}
336
e57ca85e 337proc read_diff_index {fd final} {
cb07fc2a
SP
338 global buf_rdi
339
340 append buf_rdi [read $fd]
868c8752
SP
341 set c 0
342 set n [string length $buf_rdi]
343 while {$c < $n} {
344 set z1 [string first "\0" $buf_rdi $c]
345 if {$z1 == -1} break
346 incr z1
347 set z2 [string first "\0" $buf_rdi $z1]
348 if {$z2 == -1} break
349
350 set c $z2
351 incr z2 -1
352 display_file \
353 [string range $buf_rdi $z1 $z2] \
354 [string index $buf_rdi [expr $z1 - 2]]_
355 incr c
cb07fc2a 356 }
868c8752
SP
357 if {$c < $n} {
358 set buf_rdi [string range $buf_rdi $c end]
359 } else {
360 set buf_rdi {}
361 }
362
e57ca85e 363 status_eof $fd buf_rdi $final
cb07fc2a
SP
364}
365
e57ca85e 366proc read_diff_files {fd final} {
cb07fc2a
SP
367 global buf_rdf
368
369 append buf_rdf [read $fd]
868c8752
SP
370 set c 0
371 set n [string length $buf_rdf]
372 while {$c < $n} {
373 set z1 [string first "\0" $buf_rdf $c]
374 if {$z1 == -1} break
375 incr z1
376 set z2 [string first "\0" $buf_rdf $z1]
377 if {$z2 == -1} break
378
379 set c $z2
380 incr z2 -1
381 display_file \
382 [string range $buf_rdf $z1 $z2] \
383 _[string index $buf_rdf [expr $z1 - 2]]
384 incr c
385 }
386 if {$c < $n} {
387 set buf_rdf [string range $buf_rdf $c end]
388 } else {
389 set buf_rdf {}
cb07fc2a 390 }
868c8752 391
e57ca85e 392 status_eof $fd buf_rdf $final
cb07fc2a
SP
393}
394
e57ca85e 395proc read_ls_others {fd final} {
cb07fc2a
SP
396 global buf_rlo
397
398 append buf_rlo [read $fd]
399 set pck [split $buf_rlo "\0"]
400 set buf_rlo [lindex $pck end]
401 foreach p [lrange $pck 0 end-1] {
402 display_file $p _O
403 }
e57ca85e 404 status_eof $fd buf_rlo $final
cb07fc2a
SP
405}
406
e57ca85e 407proc status_eof {fd buf final} {
7f1df79b
SP
408 global status_active ui_status_value
409 upvar $buf to_clear
cb07fc2a
SP
410
411 if {[eof $fd]} {
7f1df79b 412 set to_clear {}
cb07fc2a 413 close $fd
93f654df 414
cb07fc2a 415 if {[incr status_active -1] == 0} {
93f654df 416 display_all_files
7f1df79b
SP
417 unlock_index
418 reshow_diff
6b292675 419 set ui_status_value $final
cb07fc2a
SP
420 }
421 }
422}
423
424######################################################################
425##
426## diff
427
cb07fc2a 428proc clear_diff {} {
03e4ec53 429 global ui_diff ui_fname_value ui_fstatus_value ui_index ui_other
cb07fc2a
SP
430
431 $ui_diff conf -state normal
432 $ui_diff delete 0.0 end
433 $ui_diff conf -state disabled
03e4ec53 434
cb07fc2a
SP
435 set ui_fname_value {}
436 set ui_fstatus_value {}
03e4ec53
SP
437
438 $ui_index tag remove in_diff 0.0 end
439 $ui_other tag remove in_diff 0.0 end
cb07fc2a
SP
440}
441
7f1df79b
SP
442proc reshow_diff {} {
443 global ui_fname_value ui_status_value file_states
444
043f7011 445 if {$ui_fname_value eq {}
73ad179b 446 || [catch {set s $file_states($ui_fname_value)}]} {
7f1df79b 447 clear_diff
73ad179b
SP
448 } else {
449 show_diff $ui_fname_value
7f1df79b
SP
450 }
451}
452
16403d0b
SP
453proc handle_empty_diff {} {
454 global ui_fname_value file_states file_lists
455
456 set path $ui_fname_value
457 set s $file_states($path)
043f7011 458 if {[lindex $s 0] ne {_M}} return
16403d0b
SP
459
460 info_popup "No differences detected.
461
462[short_path $path] has no changes.
463
464The modification date of this file was updated by another
465application and you currently have the Trust File Modification
51f4d16b 466Timestamps option enabled, so Git did not automatically detect
16403d0b
SP
467that there are no content differences in this file.
468
469This file will now be removed from the modified files list, to
470prevent possible confusion.
471"
472 if {[catch {exec git update-index -- $path} err]} {
473 error_popup "Failed to refresh index:\n\n$err"
474 }
475
476 clear_diff
477 set old_w [mapcol [lindex $file_states($path) 0] $path]
478 set lno [lsearch -sorted $file_lists($old_w) $path]
479 if {$lno >= 0} {
480 set file_lists($old_w) \
481 [lreplace $file_lists($old_w) $lno $lno]
482 incr lno
483 $old_w conf -state normal
484 $old_w delete $lno.0 [expr $lno + 1].0
485 $old_w conf -state disabled
486 }
487}
488
03e4ec53
SP
489proc show_diff {path {w {}} {lno {}}} {
490 global file_states file_lists
fd2656fd 491 global PARENT diff_3way diff_active repo_config
cb07fc2a
SP
492 global ui_diff ui_fname_value ui_fstatus_value ui_status_value
493
e210e674 494 if {$diff_active || ![lock_index read]} return
cb07fc2a
SP
495
496 clear_diff
043f7011 497 if {$w eq {} || $lno == {}} {
03e4ec53
SP
498 foreach w [array names file_lists] {
499 set lno [lsearch -sorted $file_lists($w) $path]
500 if {$lno >= 0} {
501 incr lno
502 break
503 }
504 }
505 }
043f7011 506 if {$w ne {} && $lno >= 1} {
03e4ec53
SP
507 $w tag add in_diff $lno.0 [expr $lno + 1].0
508 }
509
cb07fc2a
SP
510 set s $file_states($path)
511 set m [lindex $s 0]
512 set diff_3way 0
513 set diff_active 1
c11b5f20 514 set ui_fname_value $path
cb07fc2a 515 set ui_fstatus_value [mapdesc $m $path]
68e009de 516 set ui_status_value "Loading diff of [escape_path $path]..."
cb07fc2a 517
fd2656fd
SP
518 set cmd [list | git diff-index]
519 lappend cmd --no-color
358d8de8
SP
520 if {$repo_config(gui.diffcontext) > 0} {
521 lappend cmd "-U$repo_config(gui.diffcontext)"
522 }
fd2656fd
SP
523 lappend cmd -p
524
cb07fc2a 525 switch $m {
cb07fc2a 526 MM {
fd2656fd 527 lappend cmd -c
cb07fc2a
SP
528 }
529 _O {
530 if {[catch {
531 set fd [open $path r]
532 set content [read $fd]
533 close $fd
534 } err ]} {
131f503b 535 set diff_active 0
e210e674 536 unlock_index
68e009de 537 set ui_status_value "Unable to display [escape_path $path]"
44be340e 538 error_popup "Error loading file:\n\n$err"
cb07fc2a
SP
539 return
540 }
541 $ui_diff conf -state normal
542 $ui_diff insert end $content
543 $ui_diff conf -state disabled
bd1e2b40
SP
544 set diff_active 0
545 unlock_index
546 set ui_status_value {Ready.}
cb07fc2a
SP
547 return
548 }
549 }
550
fd2656fd
SP
551 lappend cmd $PARENT
552 lappend cmd --
553 lappend cmd $path
554
cb07fc2a 555 if {[catch {set fd [open $cmd r]} err]} {
131f503b 556 set diff_active 0
e210e674 557 unlock_index
68e009de 558 set ui_status_value "Unable to display [escape_path $path]"
44be340e 559 error_popup "Error loading diff:\n\n$err"
cb07fc2a
SP
560 return
561 }
562
6f6eed28 563 fconfigure $fd -blocking 0 -translation auto
cb07fc2a
SP
564 fileevent $fd readable [list read_diff $fd]
565}
566
567proc read_diff {fd} {
568 global ui_diff ui_status_value diff_3way diff_active
51f4d16b 569 global repo_config
cb07fc2a
SP
570
571 while {[gets $fd line] >= 0} {
6f6eed28
SP
572 if {[string match {diff --git *} $line]} continue
573 if {[string match {diff --combined *} $line]} continue
574 if {[string match {--- *} $line]} continue
575 if {[string match {+++ *} $line]} continue
cb07fc2a
SP
576 if {[string match index* $line]} {
577 if {[string first , $line] >= 0} {
578 set diff_3way 1
579 }
580 }
581
582 $ui_diff conf -state normal
583 if {!$diff_3way} {
584 set x [string index $line 0]
585 switch -- $x {
586 "@" {set tags da}
587 "+" {set tags dp}
588 "-" {set tags dm}
589 default {set tags {}}
590 }
591 } else {
592 set x [string range $line 0 1]
593 switch -- $x {
594 default {set tags {}}
595 "@@" {set tags da}
596 "++" {set tags dp; set x " +"}
597 " +" {set tags {di bold}; set x "++"}
598 "+ " {set tags dni; set x "-+"}
599 "--" {set tags dm; set x " -"}
600 " -" {set tags {dm bold}; set x "--"}
601 "- " {set tags di; set x "+-"}
602 default {set tags {}}
603 }
604 set line [string replace $line 0 1 $x]
605 }
606 $ui_diff insert end $line $tags
607 $ui_diff insert end "\n"
608 $ui_diff conf -state disabled
609 }
610
611 if {[eof $fd]} {
612 close $fd
613 set diff_active 0
e210e674 614 unlock_index
cb07fc2a 615 set ui_status_value {Ready.}
16403d0b 616
043f7011
SP
617 if {$repo_config(gui.trustmtime) eq {true}
618 && [$ui_diff index end] eq {2.0}} {
16403d0b
SP
619 handle_empty_diff
620 }
cb07fc2a
SP
621 }
622}
623
ec6b424a
SP
624######################################################################
625##
626## commit
627
e57ca85e
SP
628proc load_last_commit {} {
629 global HEAD PARENT commit_type ui_comm
630
043f7011
SP
631 if {$commit_type eq {amend}} return
632 if {$commit_type ne {normal}} {
e57ca85e
SP
633 error_popup "Can't amend a $commit_type commit."
634 return
635 }
636
637 set msg {}
638 set parent {}
639 set parent_count 0
640 if {[catch {
641 set fd [open "| git cat-file commit $HEAD" r]
642 while {[gets $fd line] > 0} {
643 if {[string match {parent *} $line]} {
644 set parent [string range $line 7 end]
645 incr parent_count
646 }
647 }
648 set msg [string trim [read $fd]]
649 close $fd
650 } err]} {
44be340e 651 error_popup "Error loading commit data for amend:\n\n$err"
e57ca85e
SP
652 return
653 }
654
655 if {$parent_count == 0} {
656 set commit_type amend
657 set HEAD {}
658 set PARENT {}
659 update_status
660 } elseif {$parent_count == 1} {
661 set commit_type amend
662 set PARENT $parent
663 $ui_comm delete 0.0 end
664 $ui_comm insert end $msg
665 $ui_comm edit modified false
b2c6fcf1 666 $ui_comm edit reset
e57ca85e
SP
667 update_status
668 } else {
669 error_popup {You can't amend a merge commit.}
670 return
671 }
672}
673
ec6b424a
SP
674proc commit_tree {} {
675 global tcl_platform HEAD gitdir commit_type file_states
333b0c74 676 global pch_error
4658b56f 677 global ui_status_value ui_comm
ec6b424a 678
333b0c74 679 if {![lock_index update]} return
ec6b424a
SP
680
681 # -- Our in memory state should match the repository.
682 #
683 repository_state curHEAD cur_type
043f7011
SP
684 if {$commit_type eq {amend}
685 && $cur_type eq {normal}
686 && $curHEAD eq $HEAD} {
687 } elseif {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
ec6b424a
SP
688 error_popup {Last scanned state does not match repository state.
689
690Its highly likely that another Git program modified the
691repository since our last scan. A rescan is required
692before committing.
693}
694 unlock_index
695 update_status
696 return
697 }
698
699 # -- At least one file should differ in the index.
700 #
701 set files_ready 0
702 foreach path [array names file_states] {
703 set s $file_states($path)
704 switch -glob -- [lindex $s 0] {
7f1df79b
SP
705 _? {continue}
706 A? -
707 D? -
708 M? {set files_ready 1; break}
709 U? {
ec6b424a
SP
710 error_popup "Unmerged files cannot be committed.
711
16403d0b 712File [short_path $path] has merge conflicts.
7fe7e733 713You must resolve them and include the file before committing.
ec6b424a
SP
714"
715 unlock_index
716 return
717 }
718 default {
719 error_popup "Unknown file state [lindex $s 0] detected.
720
16403d0b 721File [short_path $path] cannot be committed by this program.
ec6b424a
SP
722"
723 }
724 }
725 }
726 if {!$files_ready} {
7fe7e733 727 error_popup {No included files to commit.
ec6b424a 728
7fe7e733 729You must include at least 1 file before you can commit.
ec6b424a
SP
730}
731 unlock_index
732 return
733 }
734
735 # -- A message is required.
736 #
737 set msg [string trim [$ui_comm get 1.0 end]]
043f7011 738 if {$msg eq {}} {
ec6b424a
SP
739 error_popup {Please supply a commit message.
740
741A good commit message has the following format:
742
743- First line: Describe in one sentance what you did.
744- Second line: Blank
745- Remaining lines: Describe why this change is good.
746}
747 unlock_index
748 return
749 }
750
751 # -- Ask the pre-commit hook for the go-ahead.
752 #
753 set pchook [file join $gitdir hooks pre-commit]
043f7011 754 if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
4658b56f
SP
755 set pchook [list sh -c [concat \
756 "if test -x \"$pchook\";" \
757 "then exec \"$pchook\" 2>&1;" \
758 "fi"]]
ec6b424a 759 } elseif {[file executable $pchook]} {
4658b56f 760 set pchook [list $pchook |& cat]
ec6b424a
SP
761 } else {
762 set pchook {}
763 }
043f7011 764 if {$pchook ne {}} {
4658b56f
SP
765 set ui_status_value {Calling pre-commit hook...}
766 set pch_error {}
767 set fd_ph [open "| $pchook" r]
768 fconfigure $fd_ph -blocking 0 -translation binary
769 fileevent $fd_ph readable \
770 [list commit_stage1 $fd_ph $curHEAD $msg]
771 } else {
772 commit_stage2 $curHEAD $msg
773 }
774}
775
776proc commit_stage1 {fd_ph curHEAD msg} {
333b0c74 777 global pch_error ui_status_value
4658b56f
SP
778
779 append pch_error [read $fd_ph]
780 fconfigure $fd_ph -blocking 1
781 if {[eof $fd_ph]} {
782 if {[catch {close $fd_ph}]} {
783 set ui_status_value {Commit declined by pre-commit hook.}
784 hook_failed_popup pre-commit $pch_error
785 unlock_index
333b0c74
SP
786 } else {
787 commit_stage2 $curHEAD $msg
4658b56f 788 }
333b0c74
SP
789 set pch_error {}
790 } else {
791 fconfigure $fd_ph -blocking 0
ec6b424a 792 }
4658b56f
SP
793}
794
795proc commit_stage2 {curHEAD msg} {
796 global ui_status_value
ec6b424a
SP
797
798 # -- Write the tree in the background.
799 #
ec6b424a 800 set ui_status_value {Committing changes...}
ec6b424a 801 set fd_wt [open "| git write-tree" r]
4658b56f 802 fileevent $fd_wt readable [list commit_stage3 $fd_wt $curHEAD $msg]
ec6b424a
SP
803}
804
4658b56f 805proc commit_stage3 {fd_wt curHEAD msg} {
c8ebafd8 806 global single_commit gitdir HEAD PARENT commit_type tcl_platform
333b0c74 807 global ui_status_value ui_comm
7f1df79b 808 global file_states
ec6b424a
SP
809
810 gets $fd_wt tree_id
043f7011 811 if {$tree_id eq {} || [catch {close $fd_wt} err]} {
44be340e 812 error_popup "write-tree failed:\n\n$err"
ec6b424a
SP
813 set ui_status_value {Commit failed.}
814 unlock_index
815 return
816 }
817
818 # -- Create the commit.
819 #
820 set cmd [list git commit-tree $tree_id]
043f7011 821 if {$PARENT ne {}} {
e57ca85e 822 lappend cmd -p $PARENT
ec6b424a 823 }
043f7011 824 if {$commit_type eq {merge}} {
ec6b424a
SP
825 if {[catch {
826 set fd_mh [open [file join $gitdir MERGE_HEAD] r]
bd1e2b40
SP
827 while {[gets $fd_mh merge_head] >= 0} {
828 lappend cmd -p $merge_head
ec6b424a
SP
829 }
830 close $fd_mh
831 } err]} {
44be340e 832 error_popup "Loading MERGE_HEAD failed:\n\n$err"
ec6b424a
SP
833 set ui_status_value {Commit failed.}
834 unlock_index
835 return
836 }
837 }
043f7011 838 if {$PARENT eq {}} {
ec6b424a
SP
839 # git commit-tree writes to stderr during initial commit.
840 lappend cmd 2>/dev/null
841 }
842 lappend cmd << $msg
843 if {[catch {set cmt_id [eval exec $cmd]} err]} {
44be340e 844 error_popup "commit-tree failed:\n\n$err"
ec6b424a
SP
845 set ui_status_value {Commit failed.}
846 unlock_index
847 return
848 }
849
850 # -- Update the HEAD ref.
851 #
852 set reflogm commit
043f7011 853 if {$commit_type ne {normal}} {
ec6b424a
SP
854 append reflogm " ($commit_type)"
855 }
856 set i [string first "\n" $msg]
857 if {$i >= 0} {
858 append reflogm {: } [string range $msg 0 [expr $i - 1]]
859 } else {
860 append reflogm {: } $msg
861 }
e57ca85e 862 set cmd [list git update-ref -m $reflogm HEAD $cmt_id $curHEAD]
ec6b424a 863 if {[catch {eval exec $cmd} err]} {
44be340e 864 error_popup "update-ref failed:\n\n$err"
ec6b424a
SP
865 set ui_status_value {Commit failed.}
866 unlock_index
867 return
868 }
869
870 # -- Cleanup after ourselves.
871 #
872 catch {file delete [file join $gitdir MERGE_HEAD]}
873 catch {file delete [file join $gitdir MERGE_MSG]}
874 catch {file delete [file join $gitdir SQUASH_MSG]}
875 catch {file delete [file join $gitdir GITGUI_MSG]}
876
877 # -- Let rerere do its thing.
878 #
879 if {[file isdirectory [file join $gitdir rr-cache]]} {
880 catch {exec git rerere}
881 }
882
c8ebafd8
SP
883 # -- Run the post-commit hook.
884 #
885 set pchook [file join $gitdir hooks post-commit]
043f7011 886 if {$tcl_platform(platform) eq {windows} && [file isfile $pchook]} {
c8ebafd8
SP
887 set pchook [list sh -c [concat \
888 "if test -x \"$pchook\";" \
889 "then exec \"$pchook\";" \
890 "fi"]]
891 } elseif {![file executable $pchook]} {
892 set pchook {}
893 }
043f7011 894 if {$pchook ne {}} {
c8ebafd8
SP
895 catch {exec $pchook &}
896 }
897
e57ca85e
SP
898 $ui_comm delete 0.0 end
899 $ui_comm edit modified false
b2c6fcf1 900 $ui_comm edit reset
ec6b424a
SP
901
902 if {$single_commit} do_quit
903
7f1df79b
SP
904 # -- Update status without invoking any git commands.
905 #
7f1df79b 906 set commit_type normal
bd1e2b40
SP
907 set HEAD $cmt_id
908 set PARENT $cmt_id
7f1df79b
SP
909
910 foreach path [array names file_states] {
911 set s $file_states($path)
912 set m [lindex $s 0]
913 switch -glob -- $m {
914 A? -
915 M? -
916 D? {set m _[string index $m 1]}
917 }
918
043f7011 919 if {$m eq {__}} {
7f1df79b
SP
920 unset file_states($path)
921 } else {
922 lset file_states($path) 0 $m
923 }
924 }
925
926 display_all_files
ec6b424a 927 unlock_index
7f1df79b
SP
928 reshow_diff
929 set ui_status_value \
930 "Changes committed as [string range $cmt_id 0 7]."
ec6b424a
SP
931}
932
8c0ce436
SP
933######################################################################
934##
935## fetch pull push
936
937proc fetch_from {remote} {
938 set w [new_console "fetch $remote" \
939 "Fetching new changes from $remote"]
cc4b1c02 940 set cmd [list git fetch]
8c0ce436 941 lappend cmd $remote
cc4b1c02 942 console_exec $w $cmd
8c0ce436
SP
943}
944
d33ba5fa 945proc pull_remote {remote branch} {
ebf336b9 946 global HEAD commit_type file_states repo_config
ec39d83a 947
988b8a7d 948 if {![lock_index update]} return
ec39d83a
SP
949
950 # -- Our in memory state should match the repository.
951 #
952 repository_state curHEAD cur_type
043f7011 953 if {$commit_type ne $cur_type || $HEAD ne $curHEAD} {
ec39d83a
SP
954 error_popup {Last scanned state does not match repository state.
955
956Its highly likely that another Git program modified the
957repository since our last scan. A rescan is required
958before a pull can be started.
959}
960 unlock_index
961 update_status
962 return
963 }
964
965 # -- No differences should exist before a pull.
966 #
967 if {[array size file_states] != 0} {
968 error_popup {Uncommitted but modified files are present.
969
970You should not perform a pull with unmodified files in your working
971directory as Git would be unable to recover from an incorrect merge.
972
973Commit or throw away all changes before starting a pull operation.
974}
975 unlock_index
976 return
977 }
978
d33ba5fa
SP
979 set w [new_console "pull $remote $branch" \
980 "Pulling new changes from branch $branch in $remote"]
981 set cmd [list git pull]
043f7011 982 if {$repo_config(gui.pullsummary) eq {false}} {
ebf336b9
SP
983 lappend cmd --no-summary
984 }
d33ba5fa
SP
985 lappend cmd $remote
986 lappend cmd $branch
987 console_exec $w $cmd [list post_pull_remote $remote $branch]
988}
989
990proc post_pull_remote {remote branch success} {
ec39d83a
SP
991 global HEAD PARENT commit_type
992 global ui_status_value
993
988b8a7d 994 unlock_index
d33ba5fa 995 if {$success} {
ec39d83a
SP
996 repository_state HEAD commit_type
997 set PARENT $HEAD
998 set $ui_status_value {Ready.}
d33ba5fa 999 } else {
390adaea
SP
1000 update_status \
1001 "Conflicts detected while pulling $branch from $remote."
d33ba5fa
SP
1002 }
1003}
1004
8c0ce436
SP
1005proc push_to {remote} {
1006 set w [new_console "push $remote" \
1007 "Pushing changes to $remote"]
cc4b1c02 1008 set cmd [list git push]
8c0ce436 1009 lappend cmd $remote
cc4b1c02 1010 console_exec $w $cmd
8c0ce436
SP
1011}
1012
cb07fc2a
SP
1013######################################################################
1014##
1015## ui helpers
1016
1017proc mapcol {state path} {
6b292675 1018 global all_cols ui_other
cb07fc2a
SP
1019
1020 if {[catch {set r $all_cols($state)}]} {
1021 puts "error: no column for state={$state} $path"
6b292675 1022 return $ui_other
cb07fc2a
SP
1023 }
1024 return $r
1025}
1026
1027proc mapicon {state path} {
1028 global all_icons
1029
1030 if {[catch {set r $all_icons($state)}]} {
1031 puts "error: no icon for state={$state} $path"
1032 return file_plain
1033 }
1034 return $r
1035}
1036
1037proc mapdesc {state path} {
1038 global all_descs
1039
1040 if {[catch {set r $all_descs($state)}]} {
1041 puts "error: no desc for state={$state} $path"
1042 return $state
1043 }
1044 return $r
1045}
1046
68e009de
SP
1047proc escape_path {path} {
1048 regsub -all "\n" $path "\\n" path
1049 return $path
1050}
1051
16403d0b
SP
1052proc short_path {path} {
1053 return [escape_path [lindex [file split $path] end]]
1054}
1055
93f654df
SP
1056set next_icon_id 0
1057
6b292675 1058proc merge_state {path new_state} {
93f654df 1059 global file_states next_icon_id
cb07fc2a 1060
6b292675
SP
1061 set s0 [string index $new_state 0]
1062 set s1 [string index $new_state 1]
1063
1064 if {[catch {set info $file_states($path)}]} {
1065 set state __
1066 set icon n[incr next_icon_id]
cb07fc2a 1067 } else {
6b292675
SP
1068 set state [lindex $info 0]
1069 set icon [lindex $info 1]
cb07fc2a
SP
1070 }
1071
043f7011 1072 if {$s0 eq {_}} {
6b292675 1073 set s0 [string index $state 0]
043f7011 1074 } elseif {$s0 eq {*}} {
6b292675 1075 set s0 _
cb07fc2a
SP
1076 }
1077
043f7011 1078 if {$s1 eq {_}} {
6b292675 1079 set s1 [string index $state 1]
043f7011 1080 } elseif {$s1 eq {*}} {
6b292675 1081 set s1 _
cb07fc2a
SP
1082 }
1083
6b292675
SP
1084 set file_states($path) [list $s0$s1 $icon]
1085 return $state
cb07fc2a
SP
1086}
1087
1088proc display_file {path state} {
03e4ec53 1089 global file_states file_lists status_active
cb07fc2a
SP
1090
1091 set old_m [merge_state $path $state]
93f654df
SP
1092 if {$status_active} return
1093
cb07fc2a 1094 set s $file_states($path)
93f654df 1095 set new_m [lindex $s 0]
0fb8f9ce
SP
1096 set new_w [mapcol $new_m $path]
1097 set old_w [mapcol $old_m $path]
1098 set new_icon [mapicon $new_m $path]
cb07fc2a 1099
043f7011 1100 if {$new_w ne $old_w} {
03e4ec53 1101 set lno [lsearch -sorted $file_lists($old_w) $path]
cb07fc2a
SP
1102 if {$lno >= 0} {
1103 incr lno
93f654df
SP
1104 $old_w conf -state normal
1105 $old_w delete $lno.0 [expr $lno + 1].0
1106 $old_w conf -state disabled
cb07fc2a 1107 }
93f654df 1108
03e4ec53
SP
1109 lappend file_lists($new_w) $path
1110 set file_lists($new_w) [lsort $file_lists($new_w)]
1111 set lno [lsearch -sorted $file_lists($new_w) $path]
1112 incr lno
93f654df
SP
1113 $new_w conf -state normal
1114 $new_w image create $lno.0 \
1115 -align center -padx 5 -pady 1 \
1116 -name [lindex $s 1] \
e4ee9af4 1117 -image $new_icon
68e009de 1118 $new_w insert $lno.1 "[escape_path $path]\n"
93f654df 1119 $new_w conf -state disabled
043f7011 1120 } elseif {$new_icon ne [mapicon $old_m $path]} {
93f654df
SP
1121 $new_w conf -state normal
1122 $new_w image conf [lindex $s 1] -image $new_icon
1123 $new_w conf -state disabled
cb07fc2a 1124 }
93f654df 1125}
cb07fc2a 1126
93f654df 1127proc display_all_files {} {
03e4ec53 1128 global ui_index ui_other file_states file_lists
93f654df
SP
1129
1130 $ui_index conf -state normal
1131 $ui_other conf -state normal
1132
7f1df79b
SP
1133 $ui_index delete 0.0 end
1134 $ui_other delete 0.0 end
1135
62aac80b
SP
1136 set file_lists($ui_index) [list]
1137 set file_lists($ui_other) [list]
1138
93f654df
SP
1139 foreach path [lsort [array names file_states]] {
1140 set s $file_states($path)
1141 set m [lindex $s 0]
6b292675 1142 set w [mapcol $m $path]
03e4ec53 1143 lappend file_lists($w) $path
6b292675 1144 $w image create end \
cb07fc2a 1145 -align center -padx 5 -pady 1 \
93f654df
SP
1146 -name [lindex $s 1] \
1147 -image [mapicon $m $path]
68e009de 1148 $w insert end "[escape_path $path]\n"
cb07fc2a 1149 }
93f654df
SP
1150
1151 $ui_index conf -state disabled
1152 $ui_other conf -state disabled
cb07fc2a
SP
1153}
1154
74e6b12f 1155proc update_index {pathList} {
2cbe5577 1156 global update_index_cp update_index_rsd ui_status_value
131f503b 1157
74e6b12f 1158 if {![lock_index update]} return
131f503b 1159
74e6b12f 1160 set update_index_cp 0
2cbe5577 1161 set update_index_rsd 0
aaf1085a 1162 set pathList [lsort $pathList]
74e6b12f
SP
1163 set totalCnt [llength $pathList]
1164 set batch [expr {int($totalCnt * .01) + 1}]
1165 if {$batch > 25} {set batch 25}
1166
1167 set ui_status_value "Including files ... 0/$totalCnt 0%"
1168 set ui_status_value [format \
1169 "Including files ... %i/%i files (%.2f%%)" \
1170 $update_index_cp \
1171 $totalCnt \
1172 0.0]
1173 set fd [open "| git update-index --add --remove -z --stdin" w]
7f09cfaf
SP
1174 fconfigure $fd \
1175 -blocking 0 \
1176 -buffering full \
1177 -buffersize 512 \
1178 -translation binary
74e6b12f
SP
1179 fileevent $fd writable [list \
1180 write_update_index \
1181 $fd \
1182 $pathList \
1183 $totalCnt \
1184 $batch \
1185 ]
1186}
1187
1188proc write_update_index {fd pathList totalCnt batch} {
2cbe5577 1189 global update_index_cp update_index_rsd ui_status_value
74e6b12f 1190 global file_states ui_fname_value
131f503b 1191
74e6b12f
SP
1192 if {$update_index_cp >= $totalCnt} {
1193 close $fd
1194 unlock_index
2cbe5577 1195 if {$update_index_rsd} {
fd2656fd 1196 reshow_diff
2cbe5577
SP
1197 } else {
1198 set ui_status_value {Ready.}
1199 }
74e6b12f 1200 return
131f503b 1201 }
131f503b 1202
74e6b12f
SP
1203 for {set i $batch} \
1204 {$update_index_cp < $totalCnt && $i > 0} \
1205 {incr i -1} {
1206 set path [lindex $pathList $update_index_cp]
1207 incr update_index_cp
1208
1209 switch -- [lindex $file_states($path) 0] {
1210 AM -
1211 _O {set new A*}
1212 _M -
1213 MM {set new M*}
1214 AD -
1215 _D {set new D*}
1216 default {continue}
1217 }
cb07fc2a 1218
74e6b12f
SP
1219 puts -nonewline $fd $path
1220 puts -nonewline $fd "\0"
1221 display_file $path $new
043f7011 1222 if {$ui_fname_value eq $path} {
2cbe5577 1223 set update_index_rsd 1
74e6b12f 1224 }
cb07fc2a
SP
1225 }
1226
74e6b12f
SP
1227 set ui_status_value [format \
1228 "Including files ... %i/%i files (%.2f%%)" \
1229 $update_index_cp \
1230 $totalCnt \
1231 [expr {100.0 * $update_index_cp / $totalCnt}]]
cb07fc2a
SP
1232}
1233
8c0ce436
SP
1234######################################################################
1235##
2d19516d 1236## remote management
0d4f3eb5 1237
8c0ce436 1238proc load_all_remotes {} {
0d4f3eb5 1239 global gitdir all_remotes repo_config
8c0ce436
SP
1240
1241 set all_remotes [list]
1242 set rm_dir [file join $gitdir remotes]
1243 if {[file isdirectory $rm_dir]} {
d47ae541
SP
1244 set all_remotes [concat $all_remotes [glob \
1245 -types f \
1246 -tails \
1247 -nocomplain \
1248 -directory $rm_dir *]]
8c0ce436
SP
1249 }
1250
0d4f3eb5
SP
1251 foreach line [array names repo_config remote.*.url] {
1252 if {[regexp ^remote\.(.*)\.url\$ $line line name]} {
8c0ce436
SP
1253 lappend all_remotes $name
1254 }
1255 }
8c0ce436
SP
1256
1257 set all_remotes [lsort -unique $all_remotes]
1258}
1259
1260proc populate_remote_menu {m pfx op} {
b4946930 1261 global all_remotes
8c0ce436
SP
1262
1263 foreach remote $all_remotes {
1264 $m add command -label "$pfx $remote..." \
1265 -command [list $op $remote] \
b4946930 1266 -font font_ui
8c0ce436
SP
1267 }
1268}
1269
d33ba5fa 1270proc populate_pull_menu {m} {
b4946930 1271 global gitdir repo_config all_remotes disable_on_lock
d33ba5fa
SP
1272
1273 foreach remote $all_remotes {
1274 set rb {}
043f7011
SP
1275 if {[array get repo_config remote.$remote.url] ne {}} {
1276 if {[array get repo_config remote.$remote.fetch] ne {}} {
d33ba5fa
SP
1277 regexp {^([^:]+):} \
1278 [lindex $repo_config(remote.$remote.fetch) 0] \
1279 line rb
1280 }
1281 } else {
1282 catch {
1283 set fd [open [file join $gitdir remotes $remote] r]
1284 while {[gets $fd line] >= 0} {
1285 if {[regexp {^Pull:[ \t]*([^:]+):} $line line rb]} {
1286 break
1287 }
1288 }
1289 close $fd
1290 }
1291 }
1292
1293 set rb_short $rb
1294 regsub ^refs/heads/ $rb {} rb_short
043f7011 1295 if {$rb_short ne {}} {
d33ba5fa
SP
1296 $m add command \
1297 -label "Branch $rb_short from $remote..." \
1298 -command [list pull_remote $remote $rb] \
b4946930 1299 -font font_ui
0a462d67
SP
1300 lappend disable_on_lock \
1301 [list $m entryconf [$m index last] -state]
d33ba5fa
SP
1302 }
1303 }
1304}
1305
cb07fc2a
SP
1306######################################################################
1307##
1308## icons
1309
1310set filemask {
1311#define mask_width 14
1312#define mask_height 15
1313static unsigned char mask_bits[] = {
1314 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1315 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1316 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1317}
1318
1319image create bitmap file_plain -background white -foreground black -data {
1320#define plain_width 14
1321#define plain_height 15
1322static unsigned char plain_bits[] = {
1323 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1324 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1325 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1326} -maskdata $filemask
1327
1328image create bitmap file_mod -background white -foreground blue -data {
1329#define mod_width 14
1330#define mod_height 15
1331static unsigned char mod_bits[] = {
1332 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1333 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1334 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1335} -maskdata $filemask
1336
131f503b
SP
1337image create bitmap file_fulltick -background white -foreground "#007000" -data {
1338#define file_fulltick_width 14
1339#define file_fulltick_height 15
1340static unsigned char file_fulltick_bits[] = {
cb07fc2a
SP
1341 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1342 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1343 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1344} -maskdata $filemask
1345
1346image create bitmap file_parttick -background white -foreground "#005050" -data {
1347#define parttick_width 14
1348#define parttick_height 15
1349static unsigned char parttick_bits[] = {
1350 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1351 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1352 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1353} -maskdata $filemask
1354
1355image create bitmap file_question -background white -foreground black -data {
1356#define file_question_width 14
1357#define file_question_height 15
1358static unsigned char file_question_bits[] = {
1359 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1360 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1361 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1362} -maskdata $filemask
1363
1364image create bitmap file_removed -background white -foreground red -data {
1365#define file_removed_width 14
1366#define file_removed_height 15
1367static unsigned char file_removed_bits[] = {
1368 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1369 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1370 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1371} -maskdata $filemask
1372
1373image create bitmap file_merge -background white -foreground blue -data {
1374#define file_merge_width 14
1375#define file_merge_height 15
1376static unsigned char file_merge_bits[] = {
1377 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1378 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1379 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1380} -maskdata $filemask
1381
6b292675
SP
1382set ui_index .vpane.files.index.list
1383set ui_other .vpane.files.other.list
131f503b 1384set max_status_desc 0
cb07fc2a 1385foreach i {
131f503b
SP
1386 {__ i plain "Unmodified"}
1387 {_M i mod "Modified"}
135f76ed 1388 {M_ i fulltick "Included in commit"}
7fe7e733 1389 {MM i parttick "Partially included"}
131f503b
SP
1390
1391 {_O o plain "Untracked"}
135f76ed 1392 {A_ o fulltick "Added by commit"}
131f503b 1393 {AM o parttick "Partially added"}
6b292675 1394 {AD o question "Added (but now gone)"}
131f503b
SP
1395
1396 {_D i question "Missing"}
135f76ed
SP
1397 {D_ i removed "Removed by commit"}
1398 {DD i removed "Removed by commit"}
131f503b
SP
1399 {DO i removed "Removed (still exists)"}
1400
1401 {UM i merge "Merge conflicts"}
1402 {U_ i merge "Merge conflicts"}
cb07fc2a 1403 } {
131f503b
SP
1404 if {$max_status_desc < [string length [lindex $i 3]]} {
1405 set max_status_desc [string length [lindex $i 3]]
1406 }
043f7011 1407 if {[lindex $i 1] eq {i}} {
6b292675
SP
1408 set all_cols([lindex $i 0]) $ui_index
1409 } else {
1410 set all_cols([lindex $i 0]) $ui_other
1411 }
131f503b
SP
1412 set all_icons([lindex $i 0]) file_[lindex $i 2]
1413 set all_descs([lindex $i 0]) [lindex $i 3]
cb07fc2a
SP
1414}
1415unset filemask i
1416
1417######################################################################
1418##
1419## util
1420
16fccd7a
SP
1421proc is_MacOSX {} {
1422 global tcl_platform tk_library
043f7011
SP
1423 if {$tcl_platform(platform) eq {unix}
1424 && $tcl_platform(os) eq {Darwin}
16fccd7a
SP
1425 && [string match /Library/Frameworks/* $tk_library]} {
1426 return 1
1427 }
1428 return 0
1429}
1430
1431proc bind_button3 {w cmd} {
1432 bind $w <Any-Button-3> $cmd
1433 if {[is_MacOSX]} {
1434 bind $w <Control-Button-1> $cmd
1435 }
1436}
1437
b4946930
SP
1438proc incr_font_size {font {amt 1}} {
1439 set sz [font configure $font -size]
1440 incr sz $amt
1441 font configure $font -size $sz
1442 font configure ${font}bold -size $sz
1443}
1444
6e27d826 1445proc hook_failed_popup {hook msg} {
b4946930 1446 global gitdir appname
6e27d826
SP
1447
1448 set w .hookfail
1449 toplevel $w
6e27d826
SP
1450
1451 frame $w.m
1452 label $w.m.l1 -text "$hook hook failed:" \
1453 -anchor w \
1454 -justify left \
b4946930 1455 -font font_uibold
6e27d826
SP
1456 text $w.m.t \
1457 -background white -borderwidth 1 \
1458 -relief sunken \
1459 -width 80 -height 10 \
b4946930 1460 -font font_diff \
6e27d826
SP
1461 -yscrollcommand [list $w.m.sby set]
1462 label $w.m.l2 \
1463 -text {You must correct the above errors before committing.} \
1464 -anchor w \
1465 -justify left \
b4946930 1466 -font font_uibold
6e27d826
SP
1467 scrollbar $w.m.sby -command [list $w.m.t yview]
1468 pack $w.m.l1 -side top -fill x
1469 pack $w.m.l2 -side bottom -fill x
1470 pack $w.m.sby -side right -fill y
1471 pack $w.m.t -side left -fill both -expand 1
1472 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1473
1474 $w.m.t insert 1.0 $msg
1475 $w.m.t conf -state disabled
1476
1477 button $w.ok -text OK \
1478 -width 15 \
b4946930 1479 -font font_ui \
6e27d826 1480 -command "destroy $w"
1e5c18fb 1481 pack $w.ok -side bottom -anchor e -pady 10 -padx 10
6e27d826
SP
1482
1483 bind $w <Visibility> "grab $w; focus $w"
1484 bind $w <Key-Return> "destroy $w"
d33ba5fa
SP
1485 wm title $w "$appname ([lindex [file split \
1486 [file normalize [file dirname $gitdir]]] \
1487 end]): error"
6e27d826
SP
1488 tkwait window $w
1489}
1490
8c0ce436
SP
1491set next_console_id 0
1492
1493proc new_console {short_title long_title} {
37af79d1
SP
1494 global next_console_id console_data
1495 set w .console[incr next_console_id]
1496 set console_data($w) [list $short_title $long_title]
1497 return [console_init $w]
1498}
1499
1500proc console_init {w} {
1501 global console_cr console_data
b4946930 1502 global gitdir appname M1B
8c0ce436 1503
ee3dc935 1504 set console_cr($w) 1.0
8c0ce436
SP
1505 toplevel $w
1506 frame $w.m
37af79d1 1507 label $w.m.l1 -text "[lindex $console_data($w) 1]:" \
8c0ce436
SP
1508 -anchor w \
1509 -justify left \
b4946930 1510 -font font_uibold
8c0ce436
SP
1511 text $w.m.t \
1512 -background white -borderwidth 1 \
1513 -relief sunken \
1514 -width 80 -height 10 \
b4946930 1515 -font font_diff \
8c0ce436
SP
1516 -state disabled \
1517 -yscrollcommand [list $w.m.sby set]
1e5c18fb
SP
1518 label $w.m.s -text {Working... please wait...} \
1519 -anchor w \
07123f40 1520 -justify left \
b4946930 1521 -font font_uibold
8c0ce436
SP
1522 scrollbar $w.m.sby -command [list $w.m.t yview]
1523 pack $w.m.l1 -side top -fill x
07123f40 1524 pack $w.m.s -side bottom -fill x
8c0ce436
SP
1525 pack $w.m.sby -side right -fill y
1526 pack $w.m.t -side left -fill both -expand 1
1527 pack $w.m -side top -fill both -expand 1 -padx 5 -pady 10
1528
0e794311
SP
1529 menu $w.ctxm -tearoff 0
1530 $w.ctxm add command -label "Copy" \
b4946930 1531 -font font_ui \
0e794311
SP
1532 -command "tk_textCopy $w.m.t"
1533 $w.ctxm add command -label "Select All" \
b4946930 1534 -font font_ui \
0e794311
SP
1535 -command "$w.m.t tag add sel 0.0 end"
1536 $w.ctxm add command -label "Copy All" \
b4946930 1537 -font font_ui \
0e794311
SP
1538 -command "
1539 $w.m.t tag add sel 0.0 end
1540 tk_textCopy $w.m.t
1541 $w.m.t tag remove sel 0.0 end
1542 "
1543
1e5c18fb 1544 button $w.ok -text {Close} \
b4946930 1545 -font font_ui \
8c0ce436
SP
1546 -state disabled \
1547 -command "destroy $w"
1e5c18fb 1548 pack $w.ok -side bottom -anchor e -pady 10 -padx 10
8c0ce436 1549
16fccd7a 1550 bind_button3 $w.m.t "tk_popup $w.ctxm %X %Y"
62aac80b
SP
1551 bind $w.m.t <$M1B-Key-a> "$w.m.t tag add sel 0.0 end;break"
1552 bind $w.m.t <$M1B-Key-A> "$w.m.t tag add sel 0.0 end;break"
8c0ce436 1553 bind $w <Visibility> "focus $w"
d33ba5fa
SP
1554 wm title $w "$appname ([lindex [file split \
1555 [file normalize [file dirname $gitdir]]] \
1556 end]): [lindex $console_data($w) 0]"
8c0ce436
SP
1557 return $w
1558}
1559
d33ba5fa 1560proc console_exec {w cmd {after {}}} {
cc4b1c02
SP
1561 global tcl_platform
1562
1563 # -- Windows tosses the enviroment when we exec our child.
1564 # But most users need that so we have to relogin. :-(
1565 #
043f7011 1566 if {$tcl_platform(platform) eq {windows}} {
cc4b1c02
SP
1567 set cmd [list sh --login -c "cd \"[pwd]\" && [join $cmd { }]"]
1568 }
1569
1570 # -- Tcl won't let us redirect both stdout and stderr to
1571 # the same pipe. So pass it through cat...
1572 #
1573 set cmd [concat | $cmd |& cat]
1574
1575 set fd_f [open $cmd r]
ee3dc935 1576 fconfigure $fd_f -blocking 0 -translation binary
d33ba5fa 1577 fileevent $fd_f readable [list console_read $w $fd_f $after]
cc4b1c02
SP
1578}
1579
d33ba5fa 1580proc console_read {w fd after} {
37af79d1 1581 global console_cr console_data
ee3dc935 1582
ee3dc935 1583 set buf [read $fd]
043f7011 1584 if {$buf ne {}} {
37af79d1
SP
1585 if {![winfo exists $w]} {console_init $w}
1586 $w.m.t conf -state normal
1587 set c 0
1588 set n [string length $buf]
1589 while {$c < $n} {
1590 set cr [string first "\r" $buf $c]
1591 set lf [string first "\n" $buf $c]
1592 if {$cr < 0} {set cr [expr $n + 1]}
1593 if {$lf < 0} {set lf [expr $n + 1]}
1594
1595 if {$lf < $cr} {
1596 $w.m.t insert end [string range $buf $c $lf]
1597 set console_cr($w) [$w.m.t index {end -1c}]
1598 set c $lf
1599 incr c
1600 } else {
1601 $w.m.t delete $console_cr($w) end
1602 $w.m.t insert end "\n"
1603 $w.m.t insert end [string range $buf $c $cr]
1604 set c $cr
1605 incr c
1606 }
ee3dc935 1607 }
37af79d1
SP
1608 $w.m.t conf -state disabled
1609 $w.m.t see end
8c0ce436 1610 }
8c0ce436 1611
07123f40 1612 fconfigure $fd -blocking 1
8c0ce436 1613 if {[eof $fd]} {
07123f40 1614 if {[catch {close $fd}]} {
37af79d1 1615 if {![winfo exists $w]} {console_init $w}
07123f40 1616 $w.m.s conf -background red -text {Error: Command Failed}
37af79d1 1617 $w.ok conf -state normal
d33ba5fa 1618 set ok 0
37af79d1 1619 } elseif {[winfo exists $w]} {
07123f40 1620 $w.m.s conf -background green -text {Success}
37af79d1 1621 $w.ok conf -state normal
d33ba5fa 1622 set ok 1
07123f40 1623 }
ee3dc935 1624 array unset console_cr $w
37af79d1 1625 array unset console_data $w
043f7011 1626 if {$after ne {}} {
d33ba5fa
SP
1627 uplevel #0 $after $ok
1628 }
07123f40 1629 return
8c0ce436 1630 }
07123f40 1631 fconfigure $fd -blocking 0
8c0ce436
SP
1632}
1633
cb07fc2a
SP
1634######################################################################
1635##
1636## ui commands
1637
e210e674 1638set starting_gitk_msg {Please wait... Starting gitk...}
cc4b1c02 1639
cb07fc2a 1640proc do_gitk {} {
e210e674
SP
1641 global tcl_platform ui_status_value starting_gitk_msg
1642
1643 set ui_status_value $starting_gitk_msg
e57ca85e 1644 after 10000 {
043f7011 1645 if {$ui_status_value eq $starting_gitk_msg} {
e210e674
SP
1646 set ui_status_value {Ready.}
1647 }
1648 }
cb07fc2a 1649
043f7011 1650 if {$tcl_platform(platform) eq {windows}} {
cb07fc2a
SP
1651 exec sh -c gitk &
1652 } else {
1653 exec gitk &
1654 }
1655}
1656
d1536c48
SP
1657proc do_repack {} {
1658 set w [new_console "repack" "Repacking the object database"]
1659 set cmd [list git repack]
1660 lappend cmd -a
1661 lappend cmd -d
1662 console_exec $w $cmd
1663}
1664
b5834d70 1665set is_quitting 0
c4fe7728 1666
cb07fc2a 1667proc do_quit {} {
51f4d16b 1668 global gitdir ui_comm is_quitting repo_config
c4fe7728 1669
b5834d70
SP
1670 if {$is_quitting} return
1671 set is_quitting 1
131f503b 1672
51f4d16b
SP
1673 # -- Stash our current commit buffer.
1674 #
131f503b 1675 set save [file join $gitdir GITGUI_MSG]
ec6b424a 1676 set msg [string trim [$ui_comm get 0.0 end]]
043f7011 1677 if {[$ui_comm edit modified] && $msg ne {}} {
131f503b
SP
1678 catch {
1679 set fd [open $save w]
1680 puts $fd [string trim [$ui_comm get 0.0 end]]
1681 close $fd
1682 }
043f7011 1683 } elseif {$msg eq {} && [file exists $save]} {
131f503b
SP
1684 file delete $save
1685 }
1686
51f4d16b
SP
1687 # -- Stash our current window geometry into this repository.
1688 #
1689 set cfg_geometry [list]
1690 lappend cfg_geometry [wm geometry .]
1691 lappend cfg_geometry [lindex [.vpane sash coord 0] 1]
1692 lappend cfg_geometry [lindex [.vpane.files sash coord 0] 0]
1693 if {[catch {set rc_geometry $repo_config(gui.geometry)}]} {
1694 set rc_geometry {}
1695 }
043f7011 1696 if {$cfg_geometry ne $rc_geometry} {
51f4d16b
SP
1697 catch {exec git repo-config gui.geometry $cfg_geometry}
1698 }
1699
cb07fc2a
SP
1700 destroy .
1701}
1702
1703proc do_rescan {} {
1704 update_status
1705}
1706
7fe7e733 1707proc do_include_all {} {
74e6b12f
SP
1708 global file_states
1709
1710 if {![lock_index begin-update]} return
1711
1712 set pathList [list]
1713 foreach path [array names file_states] {
1714 set s $file_states($path)
1715 set m [lindex $s 0]
1716 switch -- $m {
1717 AM -
1718 MM -
1719 _M -
1720 _D {lappend pathList $path}
131f503b 1721 }
74e6b12f 1722 }
043f7011 1723 if {$pathList eq {}} {
74e6b12f
SP
1724 unlock_index
1725 } else {
1726 update_index $pathList
131f503b
SP
1727 }
1728}
1729
da5239dc
SP
1730set GIT_COMMITTER_IDENT {}
1731
131f503b 1732proc do_signoff {} {
97bf01c4 1733 global ui_comm GIT_COMMITTER_IDENT
131f503b 1734
043f7011 1735 if {$GIT_COMMITTER_IDENT eq {}} {
97bf01c4 1736 if {[catch {set me [exec git var GIT_COMMITTER_IDENT]} err]} {
44be340e 1737 error_popup "Unable to obtain your identity:\n\n$err"
97bf01c4 1738 return
131f503b 1739 }
97bf01c4
SP
1740 if {![regexp {^(.*) [0-9]+ [-+0-9]+$} \
1741 $me me GIT_COMMITTER_IDENT]} {
44be340e 1742 error_popup "Invalid GIT_COMMITTER_IDENT:\n\n$me"
97bf01c4
SP
1743 return
1744 }
1745 }
1746
1daf1d0c
SP
1747 set sob "Signed-off-by: $GIT_COMMITTER_IDENT"
1748 set last [$ui_comm get {end -1c linestart} {end -1c}]
043f7011 1749 if {$last ne $sob} {
b2c6fcf1 1750 $ui_comm edit separator
043f7011 1751 if {$last ne {}
1daf1d0c
SP
1752 && ![regexp {^[A-Z][A-Za-z]*-[A-Za-z-]+: *} $last]} {
1753 $ui_comm insert end "\n"
1754 }
1755 $ui_comm insert end "\n$sob"
b2c6fcf1 1756 $ui_comm edit separator
97bf01c4 1757 $ui_comm see end
131f503b
SP
1758 }
1759}
1760
e57ca85e
SP
1761proc do_amend_last {} {
1762 load_last_commit
1763}
1764
6e27d826 1765proc do_commit {} {
ec6b424a 1766 commit_tree
6e27d826
SP
1767}
1768
51f4d16b 1769proc do_options {} {
92148d80 1770 global appname gitdir font_descs
51f4d16b
SP
1771 global repo_config global_config
1772 global repo_config_new global_config_new
1773
51f4d16b
SP
1774 array unset repo_config_new
1775 array unset global_config_new
1776 foreach name [array names repo_config] {
1777 set repo_config_new($name) $repo_config($name)
1778 }
358d8de8
SP
1779 load_config 1
1780 foreach name [array names repo_config] {
1781 switch -- $name {
1782 gui.diffcontext {continue}
1783 }
1784 set repo_config_new($name) $repo_config($name)
1785 }
51f4d16b
SP
1786 foreach name [array names global_config] {
1787 set global_config_new($name) $global_config($name)
1788 }
e01b4221
SP
1789 set reponame [lindex [file split \
1790 [file normalize [file dirname $gitdir]]] \
1791 end]
51f4d16b
SP
1792
1793 set w .options_editor
1794 toplevel $w
e01b4221 1795 wm geometry $w "+[winfo rootx .]+[winfo rooty .]"
51f4d16b
SP
1796
1797 label $w.header -text "$appname Options" \
1798 -font font_uibold
1799 pack $w.header -side top -fill x
1800
1801 frame $w.buttons
92148d80
SP
1802 button $w.buttons.restore -text {Restore Defaults} \
1803 -font font_ui \
1804 -command do_restore_defaults
1805 pack $w.buttons.restore -side left
51f4d16b
SP
1806 button $w.buttons.save -text Save \
1807 -font font_ui \
92148d80 1808 -command [list do_save_config $w]
51f4d16b
SP
1809 pack $w.buttons.save -side right
1810 button $w.buttons.cancel -text {Cancel} \
1811 -font font_ui \
92148d80 1812 -command [list destroy $w]
51f4d16b 1813 pack $w.buttons.cancel -side right
92148d80 1814 pack $w.buttons -side bottom -fill x -pady 10 -padx 10
51f4d16b 1815
e01b4221 1816 labelframe $w.repo -text "$reponame Repository" \
92148d80 1817 -font font_ui \
51f4d16b
SP
1818 -relief raised -borderwidth 2
1819 labelframe $w.global -text {Global (All Repositories)} \
92148d80 1820 -font font_ui \
51f4d16b
SP
1821 -relief raised -borderwidth 2
1822 pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5
1823 pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5
1824
1825 foreach option {
358d8de8
SP
1826 {b pullsummary {Show Pull Summary}}
1827 {b trustmtime {Trust File Modification Timestamps}}
1828 {i diffcontext {Number of Diff Context Lines}}
51f4d16b 1829 } {
358d8de8
SP
1830 set type [lindex $option 0]
1831 set name [lindex $option 1]
1832 set text [lindex $option 2]
51f4d16b 1833 foreach f {repo global} {
358d8de8
SP
1834 switch $type {
1835 b {
1836 checkbutton $w.$f.$name -text $text \
1837 -variable ${f}_config_new(gui.$name) \
1838 -onvalue true \
1839 -offvalue false \
1840 -font font_ui
1841 pack $w.$f.$name -side top -anchor w
1842 }
1843 i {
1844 frame $w.$f.$name
1845 label $w.$f.$name.l -text "$text:" -font font_ui
1846 pack $w.$f.$name.l -side left -anchor w -fill x
1847 spinbox $w.$f.$name.v \
1848 -textvariable ${f}_config_new(gui.$name) \
1849 -from 1 -to 99 -increment 1 \
1850 -width 3 \
1851 -font font_ui
1852 pack $w.$f.$name.v -side right -anchor e
1853 pack $w.$f.$name -side top -anchor w -fill x
1854 }
1855 }
51f4d16b
SP
1856 }
1857 }
1858
92148d80
SP
1859 set all_fonts [lsort [font families]]
1860 foreach option $font_descs {
1861 set name [lindex $option 0]
1862 set font [lindex $option 1]
1863 set text [lindex $option 2]
1864
1865 set global_config_new(gui.$font^^family) \
1866 [font configure $font -family]
1867 set global_config_new(gui.$font^^size) \
1868 [font configure $font -size]
1869
1870 frame $w.global.$name
1871 label $w.global.$name.l -text "$text:" -font font_ui
1872 pack $w.global.$name.l -side left -anchor w -fill x
1873 eval tk_optionMenu $w.global.$name.family \
1874 global_config_new(gui.$font^^family) \
1875 $all_fonts
1876 spinbox $w.global.$name.size \
1877 -textvariable global_config_new(gui.$font^^size) \
1878 -from 2 -to 80 -increment 1 \
1879 -width 3 \
1880 -font font_ui
1881 pack $w.global.$name.size -side right -anchor e
1882 pack $w.global.$name.family -side right -anchor e
1883 pack $w.global.$name -side top -anchor w -fill x
1884 }
1885
51f4d16b
SP
1886 bind $w <Visibility> "grab $w; focus $w"
1887 bind $w <Key-Escape> "destroy $w"
e01b4221 1888 wm title $w "$appname ($reponame): Options"
51f4d16b
SP
1889 tkwait window $w
1890}
1891
92148d80 1892proc do_restore_defaults {} {
7b64d0b7 1893 global font_descs default_config repo_config
92148d80
SP
1894 global repo_config_new global_config_new
1895
1896 foreach name [array names default_config] {
1897 set repo_config_new($name) $default_config($name)
1898 set global_config_new($name) $default_config($name)
1899 }
1900
1901 foreach option $font_descs {
1902 set name [lindex $option 0]
7b64d0b7 1903 set repo_config(gui.$name) $default_config(gui.$name)
92148d80
SP
1904 }
1905 apply_config
1906
1907 foreach option $font_descs {
1908 set name [lindex $option 0]
1909 set font [lindex $option 1]
1910 set global_config_new(gui.$font^^family) \
1911 [font configure $font -family]
1912 set global_config_new(gui.$font^^size) \
1913 [font configure $font -size]
1914 }
1915}
1916
1917proc do_save_config {w} {
1918 if {[catch {save_config} err]} {
1919 error_popup "Failed to completely save options:\n\n$err"
1920 }
358d8de8 1921 reshow_diff
92148d80
SP
1922 destroy $w
1923}
1924
cb07fc2a
SP
1925# shift == 1: left click
1926# 3: right click
1927proc click {w x y shift wx wy} {
03e4ec53 1928 global ui_index ui_other file_lists
131f503b 1929
cb07fc2a
SP
1930 set pos [split [$w index @$x,$y] .]
1931 set lno [lindex $pos 0]
1932 set col [lindex $pos 1]
03e4ec53 1933 set path [lindex $file_lists($w) [expr $lno - 1]]
043f7011 1934 if {$path eq {}} return
cb07fc2a
SP
1935
1936 if {$col > 0 && $shift == 1} {
03e4ec53 1937 show_diff $path $w $lno
cb07fc2a
SP
1938 }
1939}
1940
1941proc unclick {w x y} {
7f1df79b
SP
1942 global file_lists
1943
cb07fc2a
SP
1944 set pos [split [$w index @$x,$y] .]
1945 set lno [lindex $pos 0]
1946 set col [lindex $pos 1]
7f1df79b 1947 set path [lindex $file_lists($w) [expr $lno - 1]]
043f7011 1948 if {$path eq {}} return
cb07fc2a 1949
e210e674 1950 if {$col == 0} {
74e6b12f 1951 update_index [list $path]
cb07fc2a
SP
1952 }
1953}
1954
1955######################################################################
1956##
92148d80 1957## config defaults
cb07fc2a 1958
00f949fb 1959set cursor_ptr arrow
b4946930
SP
1960font create font_diff -family Courier -size 10
1961font create font_ui
1962catch {
1963 label .dummy
1964 eval font configure font_ui [font actual [.dummy cget -font]]
1965 destroy .dummy
1966}
1967
92148d80
SP
1968font create font_uibold
1969font create font_diffbold
cb07fc2a 1970
16fccd7a
SP
1971set M1B M1
1972set M1T M1
043f7011 1973if {$tcl_platform(platform) eq {windows}} {
16fccd7a
SP
1974 set M1B Control
1975 set M1T Ctrl
1976} elseif {[is_MacOSX]} {
1977 set M1B M1
1978 set M1T Cmd
e210e674
SP
1979}
1980
92148d80
SP
1981proc apply_config {} {
1982 global repo_config font_descs
1983
1984 foreach option $font_descs {
1985 set name [lindex $option 0]
1986 set font [lindex $option 1]
1987 if {[catch {
1988 foreach {cn cv} $repo_config(gui.$name) {
1989 font configure $font $cn $cv
1990 }
1991 } err]} {
1992 error_popup "Invalid font specified in gui.$name:\n\n$err"
1993 }
1994 foreach {cn cv} [font configure $font] {
1995 font configure ${font}bold $cn $cv
1996 }
1997 font configure ${font}bold -weight bold
1998 }
1999}
2000
2001set default_config(gui.trustmtime) false
ebf336b9 2002set default_config(gui.pullsummary) true
358d8de8 2003set default_config(gui.diffcontext) 5
92148d80
SP
2004set default_config(gui.fontui) [font configure font_ui]
2005set default_config(gui.fontdiff) [font configure font_diff]
2006set font_descs {
2007 {fontui font_ui {Main Font}}
2008 {fontdiff font_diff {Diff/Console Font}}
2009}
6bbd1cb9 2010load_config 0
92148d80
SP
2011apply_config
2012
2013######################################################################
2014##
2015## ui construction
2016
cb07fc2a 2017# -- Menu Bar
b4946930 2018menu .mbar -tearoff 0
cb07fc2a 2019.mbar add cascade -label Project -menu .mbar.project
9861671d 2020.mbar add cascade -label Edit -menu .mbar.edit
cb07fc2a 2021.mbar add cascade -label Commit -menu .mbar.commit
4ccdab02
SP
2022if {!$single_commit} {
2023 .mbar add cascade -label Fetch -menu .mbar.fetch
2024 .mbar add cascade -label Pull -menu .mbar.pull
2025 .mbar add cascade -label Push -menu .mbar.push
2026}
cb07fc2a
SP
2027. configure -menu .mbar
2028
2029# -- Project Menu
2030menu .mbar.project
6f6eed28 2031.mbar.project add command -label Visualize \
cb07fc2a 2032 -command do_gitk \
b4946930 2033 -font font_ui
4ccdab02
SP
2034if {!$single_commit} {
2035 .mbar.project add command -label {Repack Database} \
2036 -command do_repack \
2037 -font font_ui
2038}
cb07fc2a
SP
2039.mbar.project add command -label Quit \
2040 -command do_quit \
e210e674 2041 -accelerator $M1T-Q \
b4946930 2042 -font font_ui
cb07fc2a 2043
9861671d
SP
2044# -- Edit Menu
2045#
2046menu .mbar.edit
2047.mbar.edit add command -label Undo \
2048 -command {catch {[focus] edit undo}} \
2049 -accelerator $M1T-Z \
b4946930 2050 -font font_ui
9861671d
SP
2051.mbar.edit add command -label Redo \
2052 -command {catch {[focus] edit redo}} \
2053 -accelerator $M1T-Y \
b4946930 2054 -font font_ui
9861671d
SP
2055.mbar.edit add separator
2056.mbar.edit add command -label Cut \
2057 -command {catch {tk_textCut [focus]}} \
2058 -accelerator $M1T-X \
b4946930 2059 -font font_ui
9861671d
SP
2060.mbar.edit add command -label Copy \
2061 -command {catch {tk_textCopy [focus]}} \
2062 -accelerator $M1T-C \
b4946930 2063 -font font_ui
9861671d
SP
2064.mbar.edit add command -label Paste \
2065 -command {catch {tk_textPaste [focus]; [focus] see insert}} \
2066 -accelerator $M1T-V \
b4946930 2067 -font font_ui
9861671d
SP
2068.mbar.edit add command -label Delete \
2069 -command {catch {[focus] delete sel.first sel.last}} \
2070 -accelerator Del \
b4946930 2071 -font font_ui
9861671d
SP
2072.mbar.edit add separator
2073.mbar.edit add command -label {Select All} \
2074 -command {catch {[focus] tag add sel 0.0 end}} \
2075 -accelerator $M1T-A \
b4946930 2076 -font font_ui
51f4d16b
SP
2077.mbar.edit add separator
2078.mbar.edit add command -label {Options...} \
2079 -command do_options \
2080 -font font_ui
9861671d 2081
cb07fc2a
SP
2082# -- Commit Menu
2083menu .mbar.commit
2084.mbar.commit add command -label Rescan \
2085 -command do_rescan \
e210e674 2086 -accelerator F5 \
b4946930 2087 -font font_ui
e210e674
SP
2088lappend disable_on_lock \
2089 [list .mbar.commit entryconf [.mbar.commit index last] -state]
e57ca85e
SP
2090.mbar.commit add command -label {Amend Last Commit} \
2091 -command do_amend_last \
b4946930 2092 -font font_ui
e57ca85e
SP
2093lappend disable_on_lock \
2094 [list .mbar.commit entryconf [.mbar.commit index last] -state]
7fe7e733
SP
2095.mbar.commit add command -label {Include All Files} \
2096 -command do_include_all \
49b86f01 2097 -accelerator $M1T-I \
b4946930 2098 -font font_ui
e210e674
SP
2099lappend disable_on_lock \
2100 [list .mbar.commit entryconf [.mbar.commit index last] -state]
131f503b
SP
2101.mbar.commit add command -label {Sign Off} \
2102 -command do_signoff \
e210e674 2103 -accelerator $M1T-S \
b4946930 2104 -font font_ui
131f503b
SP
2105.mbar.commit add command -label Commit \
2106 -command do_commit \
e210e674 2107 -accelerator $M1T-Return \
b4946930 2108 -font font_ui
e210e674
SP
2109lappend disable_on_lock \
2110 [list .mbar.commit entryconf [.mbar.commit index last] -state]
cb07fc2a 2111
4ccdab02
SP
2112if {!$single_commit} {
2113 # -- Fetch Menu
2114 menu .mbar.fetch
cb07fc2a 2115
4ccdab02
SP
2116 # -- Pull Menu
2117 menu .mbar.pull
cb07fc2a 2118
4ccdab02
SP
2119 # -- Push Menu
2120 menu .mbar.push
2121}
8c0ce436 2122
cb07fc2a
SP
2123# -- Main Window Layout
2124panedwindow .vpane -orient vertical
2125panedwindow .vpane.files -orient horizontal
6f6eed28 2126.vpane add .vpane.files -sticky nsew -height 100 -width 400
cb07fc2a
SP
2127pack .vpane -anchor n -side top -fill both -expand 1
2128
2129# -- Index File List
cb07fc2a
SP
2130frame .vpane.files.index -height 100 -width 400
2131label .vpane.files.index.title -text {Modified Files} \
2132 -background green \
b4946930 2133 -font font_ui
cb07fc2a
SP
2134text $ui_index -background white -borderwidth 0 \
2135 -width 40 -height 10 \
b4946930 2136 -font font_ui \
6c6dd01a 2137 -cursor $cursor_ptr \
cb07fc2a 2138 -yscrollcommand {.vpane.files.index.sb set} \
cb07fc2a
SP
2139 -state disabled
2140scrollbar .vpane.files.index.sb -command [list $ui_index yview]
2141pack .vpane.files.index.title -side top -fill x
2142pack .vpane.files.index.sb -side right -fill y
2143pack $ui_index -side left -fill both -expand 1
2144.vpane.files add .vpane.files.index -sticky nsew
2145
2146# -- Other (Add) File List
cb07fc2a
SP
2147frame .vpane.files.other -height 100 -width 100
2148label .vpane.files.other.title -text {Untracked Files} \
2149 -background red \
b4946930 2150 -font font_ui
cb07fc2a
SP
2151text $ui_other -background white -borderwidth 0 \
2152 -width 40 -height 10 \
b4946930 2153 -font font_ui \
6c6dd01a 2154 -cursor $cursor_ptr \
cb07fc2a 2155 -yscrollcommand {.vpane.files.other.sb set} \
cb07fc2a
SP
2156 -state disabled
2157scrollbar .vpane.files.other.sb -command [list $ui_other yview]
2158pack .vpane.files.other.title -side top -fill x
2159pack .vpane.files.other.sb -side right -fill y
2160pack $ui_other -side left -fill both -expand 1
2161.vpane.files add .vpane.files.other -sticky nsew
2162
b4946930
SP
2163$ui_index tag conf in_diff -font font_uibold
2164$ui_other tag conf in_diff -font font_uibold
131f503b 2165
0fb8f9ce 2166# -- Diff and Commit Area
8009dcdc 2167frame .vpane.lower -height 300 -width 400
0fb8f9ce
SP
2168frame .vpane.lower.commarea
2169frame .vpane.lower.diff -relief sunken -borderwidth 1
2170pack .vpane.lower.commarea -side top -fill x
2171pack .vpane.lower.diff -side bottom -fill both -expand 1
2172.vpane add .vpane.lower -stick nsew
cb07fc2a
SP
2173
2174# -- Commit Area Buttons
0fb8f9ce
SP
2175frame .vpane.lower.commarea.buttons
2176label .vpane.lower.commarea.buttons.l -text {} \
cb07fc2a
SP
2177 -anchor w \
2178 -justify left \
b4946930 2179 -font font_ui
0fb8f9ce
SP
2180pack .vpane.lower.commarea.buttons.l -side top -fill x
2181pack .vpane.lower.commarea.buttons -side left -fill y
131f503b 2182
0fb8f9ce 2183button .vpane.lower.commarea.buttons.rescan -text {Rescan} \
cb07fc2a 2184 -command do_rescan \
b4946930 2185 -font font_ui
0fb8f9ce 2186pack .vpane.lower.commarea.buttons.rescan -side top -fill x
390adaea
SP
2187lappend disable_on_lock \
2188 {.vpane.lower.commarea.buttons.rescan conf -state}
131f503b 2189
0fb8f9ce 2190button .vpane.lower.commarea.buttons.amend -text {Amend Last} \
e57ca85e 2191 -command do_amend_last \
b4946930 2192 -font font_ui
0fb8f9ce 2193pack .vpane.lower.commarea.buttons.amend -side top -fill x
390adaea
SP
2194lappend disable_on_lock \
2195 {.vpane.lower.commarea.buttons.amend conf -state}
e57ca85e 2196
7fe7e733
SP
2197button .vpane.lower.commarea.buttons.incall -text {Include All} \
2198 -command do_include_all \
b4946930 2199 -font font_ui
7fe7e733 2200pack .vpane.lower.commarea.buttons.incall -side top -fill x
390adaea
SP
2201lappend disable_on_lock \
2202 {.vpane.lower.commarea.buttons.incall conf -state}
131f503b 2203
0fb8f9ce 2204button .vpane.lower.commarea.buttons.signoff -text {Sign Off} \
131f503b 2205 -command do_signoff \
b4946930 2206 -font font_ui
0fb8f9ce 2207pack .vpane.lower.commarea.buttons.signoff -side top -fill x
131f503b 2208
0fb8f9ce 2209button .vpane.lower.commarea.buttons.commit -text {Commit} \
cb07fc2a 2210 -command do_commit \
b4946930 2211 -font font_ui
0fb8f9ce 2212pack .vpane.lower.commarea.buttons.commit -side top -fill x
390adaea
SP
2213lappend disable_on_lock \
2214 {.vpane.lower.commarea.buttons.commit conf -state}
cb07fc2a
SP
2215
2216# -- Commit Message Buffer
0fb8f9ce
SP
2217frame .vpane.lower.commarea.buffer
2218set ui_comm .vpane.lower.commarea.buffer.t
2219set ui_coml .vpane.lower.commarea.buffer.l
bd1e2b40 2220label $ui_coml -text {Commit Message:} \
cb07fc2a
SP
2221 -anchor w \
2222 -justify left \
b4946930 2223 -font font_ui
bd1e2b40
SP
2224trace add variable commit_type write {uplevel #0 {
2225 switch -glob $commit_type \
2226 initial {$ui_coml conf -text {Initial Commit Message:}} \
2227 amend {$ui_coml conf -text {Amended Commit Message:}} \
2228 merge {$ui_coml conf -text {Merge Commit Message:}} \
2229 * {$ui_coml conf -text {Commit Message:}}
2230}}
cb07fc2a 2231text $ui_comm -background white -borderwidth 1 \
9861671d 2232 -undo true \
b2c6fcf1 2233 -maxundo 20 \
9861671d 2234 -autoseparators true \
cb07fc2a 2235 -relief sunken \
0fb8f9ce 2236 -width 75 -height 9 -wrap none \
b4946930 2237 -font font_diff \
6c6dd01a 2238 -yscrollcommand {.vpane.lower.commarea.buffer.sby set}
390adaea
SP
2239scrollbar .vpane.lower.commarea.buffer.sby \
2240 -command [list $ui_comm yview]
bd1e2b40 2241pack $ui_coml -side top -fill x
0fb8f9ce 2242pack .vpane.lower.commarea.buffer.sby -side right -fill y
cb07fc2a 2243pack $ui_comm -side left -fill y
0fb8f9ce
SP
2244pack .vpane.lower.commarea.buffer -side left -fill y
2245
0e794311
SP
2246# -- Commit Message Buffer Context Menu
2247#
2248menu $ui_comm.ctxm -tearoff 0
2249$ui_comm.ctxm add command -label "Cut" \
b4946930 2250 -font font_ui \
0e794311
SP
2251 -command "tk_textCut $ui_comm"
2252$ui_comm.ctxm add command -label "Copy" \
b4946930 2253 -font font_ui \
0e794311
SP
2254 -command "tk_textCopy $ui_comm"
2255$ui_comm.ctxm add command -label "Paste" \
b4946930 2256 -font font_ui \
0e794311
SP
2257 -command "tk_textPaste $ui_comm"
2258$ui_comm.ctxm add command -label "Delete" \
b4946930 2259 -font font_ui \
0e794311
SP
2260 -command "$ui_comm delete sel.first sel.last"
2261$ui_comm.ctxm add separator
2262$ui_comm.ctxm add command -label "Select All" \
b4946930 2263 -font font_ui \
0e794311
SP
2264 -command "$ui_comm tag add sel 0.0 end"
2265$ui_comm.ctxm add command -label "Copy All" \
b4946930 2266 -font font_ui \
0e794311
SP
2267 -command "
2268 $ui_comm tag add sel 0.0 end
2269 tk_textCopy $ui_comm
2270 $ui_comm tag remove sel 0.0 end
2271 "
2272$ui_comm.ctxm add separator
2273$ui_comm.ctxm add command -label "Sign Off" \
b4946930 2274 -font font_ui \
0e794311 2275 -command do_signoff
16fccd7a 2276bind_button3 $ui_comm "tk_popup $ui_comm.ctxm %X %Y"
0e794311 2277
0fb8f9ce
SP
2278# -- Diff Header
2279set ui_fname_value {}
2280set ui_fstatus_value {}
2281frame .vpane.lower.diff.header -background orange
3e7b0e1d
SP
2282label .vpane.lower.diff.header.l4 \
2283 -textvariable ui_fstatus_value \
2284 -background orange \
2285 -width $max_status_desc \
2286 -anchor w \
2287 -justify left \
2288 -font font_ui
0fb8f9ce
SP
2289label .vpane.lower.diff.header.l1 -text {File:} \
2290 -background orange \
b4946930 2291 -font font_ui
c11b5f20 2292set ui_fname .vpane.lower.diff.header.l2
fce89e46
SP
2293label $ui_fname \
2294 -textvariable ui_fname_value \
0fb8f9ce 2295 -background orange \
fce89e46
SP
2296 -anchor w \
2297 -justify left \
b4946930 2298 -font font_ui
c11b5f20 2299menu $ui_fname.ctxm -tearoff 0
fce89e46 2300$ui_fname.ctxm add command -label "Copy" \
c11b5f20 2301 -font font_ui \
fce89e46
SP
2302 -command {
2303 clipboard clear
2304 clipboard append \
2305 -format STRING \
2306 -type STRING \
2307 -- $ui_fname_value
2308 }
c11b5f20 2309bind_button3 $ui_fname "tk_popup $ui_fname.ctxm %X %Y"
3e7b0e1d 2310pack .vpane.lower.diff.header.l4 -side left
0fb8f9ce 2311pack .vpane.lower.diff.header.l1 -side left
3e7b0e1d 2312pack $ui_fname -fill x
0fb8f9ce
SP
2313
2314# -- Diff Body
2315frame .vpane.lower.diff.body
2316set ui_diff .vpane.lower.diff.body.t
2317text $ui_diff -background white -borderwidth 0 \
2318 -width 80 -height 15 -wrap none \
b4946930 2319 -font font_diff \
0fb8f9ce
SP
2320 -xscrollcommand {.vpane.lower.diff.body.sbx set} \
2321 -yscrollcommand {.vpane.lower.diff.body.sby set} \
0fb8f9ce
SP
2322 -state disabled
2323scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
2324 -command [list $ui_diff xview]
2325scrollbar .vpane.lower.diff.body.sby -orient vertical \
2326 -command [list $ui_diff yview]
2327pack .vpane.lower.diff.body.sbx -side bottom -fill x
2328pack .vpane.lower.diff.body.sby -side right -fill y
2329pack $ui_diff -side left -fill both -expand 1
2330pack .vpane.lower.diff.header -side top -fill x
2331pack .vpane.lower.diff.body -side bottom -fill both -expand 1
2332
2333$ui_diff tag conf dm -foreground red
2334$ui_diff tag conf dp -foreground blue
b4946930
SP
2335$ui_diff tag conf di -foreground {#00a000}
2336$ui_diff tag conf dni -foreground {#a000a0}
2337$ui_diff tag conf da -font font_diffbold
2338$ui_diff tag conf bold -font font_diffbold
cb07fc2a 2339
0e794311
SP
2340# -- Diff Body Context Menu
2341#
2342menu $ui_diff.ctxm -tearoff 0
2343$ui_diff.ctxm add command -label "Copy" \
b4946930 2344 -font font_ui \
0e794311
SP
2345 -command "tk_textCopy $ui_diff"
2346$ui_diff.ctxm add command -label "Select All" \
b4946930 2347 -font font_ui \
0e794311
SP
2348 -command "$ui_diff tag add sel 0.0 end"
2349$ui_diff.ctxm add command -label "Copy All" \
b4946930 2350 -font font_ui \
0e794311
SP
2351 -command "
2352 $ui_diff tag add sel 0.0 end
2353 tk_textCopy $ui_diff
2354 $ui_diff tag remove sel 0.0 end
2355 "
2c26e6f5
SP
2356$ui_diff.ctxm add separator
2357$ui_diff.ctxm add command -label "Decrease Font Size" \
b4946930
SP
2358 -font font_ui \
2359 -command {incr_font_size font_diff -1}
2c26e6f5 2360$ui_diff.ctxm add command -label "Increase Font Size" \
b4946930
SP
2361 -font font_ui \
2362 -command {incr_font_size font_diff 1}
358d8de8
SP
2363$ui_diff.ctxm add separator
2364$ui_diff.ctxm add command -label "Show Less Context" \
2365 -font font_ui \
2366 -command {if {$ui_fname_value ne {}
2367 && $repo_config(gui.diffcontext) >= 2} {
2368 incr repo_config(gui.diffcontext) -1
2369 reshow_diff
2370 }}
2371$ui_diff.ctxm add command -label "Show More Context" \
2372 -font font_ui \
2373 -command {if {$ui_fname_value ne {}} {
2374 incr repo_config(gui.diffcontext)
2375 reshow_diff
2376 }}
2377$ui_diff.ctxm add separator
8009dcdc
SP
2378$ui_diff.ctxm add command -label {Options...} \
2379 -font font_ui \
2380 -command do_options
16fccd7a 2381bind_button3 $ui_diff "tk_popup $ui_diff.ctxm %X %Y"
0e794311 2382
cb07fc2a
SP
2383# -- Status Bar
2384set ui_status_value {Initializing...}
2385label .status -textvariable ui_status_value \
2386 -anchor w \
2387 -justify left \
2388 -borderwidth 1 \
2389 -relief sunken \
b4946930 2390 -font font_ui
cb07fc2a
SP
2391pack .status -anchor w -side bottom -fill x
2392
2d19516d
SP
2393# -- Load geometry
2394catch {
51f4d16b 2395set gm $repo_config(gui.geometry)
c4fe7728
SP
2396wm geometry . [lindex $gm 0]
2397.vpane sash place 0 \
2398 [lindex [.vpane sash coord 0] 0] \
2399 [lindex $gm 1]
2400.vpane.files sash place 0 \
2401 [lindex $gm 2] \
2402 [lindex [.vpane.files sash coord 0] 1]
c4fe7728 2403unset gm
390adaea 2404}
2d19516d 2405
cb07fc2a 2406# -- Key Bindings
ec6b424a 2407bind $ui_comm <$M1B-Key-Return> {do_commit;break}
49b86f01
SP
2408bind $ui_comm <$M1B-Key-i> {do_include_all;break}
2409bind $ui_comm <$M1B-Key-I> {do_include_all;break}
9861671d
SP
2410bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break}
2411bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break}
2412bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break}
2413bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break}
2414bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break}
2415bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break}
2416bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2417bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break}
2418
2419bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break}
2420bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break}
2421bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break}
2422bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break}
2423bind $ui_diff <$M1B-Key-v> {break}
2424bind $ui_diff <$M1B-Key-V> {break}
2425bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
2426bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
b2c6fcf1
SP
2427bind $ui_diff <Key-Up> {catch {%W yview scroll -1 units};break}
2428bind $ui_diff <Key-Down> {catch {%W yview scroll 1 units};break}
2429bind $ui_diff <Key-Left> {catch {%W xview scroll -1 units};break}
2430bind $ui_diff <Key-Right> {catch {%W xview scroll 1 units};break}
49b86f01 2431
07123f40
SP
2432bind . <Destroy> do_quit
2433bind all <Key-F5> do_rescan
2434bind all <$M1B-Key-r> do_rescan
2435bind all <$M1B-Key-R> do_rescan
2436bind . <$M1B-Key-s> do_signoff
2437bind . <$M1B-Key-S> do_signoff
49b86f01
SP
2438bind . <$M1B-Key-i> do_include_all
2439bind . <$M1B-Key-I> do_include_all
07123f40
SP
2440bind . <$M1B-Key-Return> do_commit
2441bind all <$M1B-Key-q> do_quit
2442bind all <$M1B-Key-Q> do_quit
2443bind all <$M1B-Key-w> {destroy [winfo toplevel %W]}
2444bind all <$M1B-Key-W> {destroy [winfo toplevel %W]}
cb07fc2a
SP
2445foreach i [list $ui_index $ui_other] {
2446 bind $i <Button-1> {click %W %x %y 1 %X %Y; break}
cb07fc2a 2447 bind $i <ButtonRelease-1> {unclick %W %x %y; break}
16fccd7a 2448 bind_button3 $i {click %W %x %y 3 %X %Y; break}
cb07fc2a 2449}
62aac80b
SP
2450unset i
2451
2452set file_lists($ui_index) [list]
2453set file_lists($ui_other) [list]
cb07fc2a 2454
ec6b424a 2455wm title . "$appname ([file normalize [file dirname $gitdir]])"
cb07fc2a 2456focus -force $ui_comm
4ccdab02
SP
2457if {!$single_commit} {
2458 load_all_remotes
2459 populate_remote_menu .mbar.fetch From fetch_from
2460 populate_remote_menu .mbar.push To push_to
2461 populate_pull_menu .mbar.pull
2462}
4af2c384 2463after 1 update_status