2 # Tcl ignores the next line -*- tcl -*- \
3 if test "z$*" = zversion \
4 ||
test "z$*" = z--version
; \
6 echo 'git-gui version @@GITGUI_VERSION@@'; \
11 set appvers
{@@GITGUI_VERSION@@
}
13 Copyright ©
2006, 2007 Shawn Pearce
, et. al.
15 This program is free software
; you can redistribute it and
/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation
; either version
2 of the License
, or
18 (at your option
) any later version.
20 This program is distributed
in the hope that it will be useful
,
21 but WITHOUT ANY WARRANTY
; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License
for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program
; if not
, write to the Free Software
27 Foundation
, Inc.
, 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
}
29 ######################################################################
31 ## Tcl/Tk sanity check
33 if {[catch
{package require Tcl
8.4} err
]
34 ||
[catch
{package require Tk
8.4} err
]
40 -title [mc
"git-gui: fatal error"] \
45 catch
{rename send
{}} ; # What an evil concept...
47 ######################################################################
51 set oguilib
{@@GITGUI_LIBDIR@@
}
52 set oguirel
{@@GITGUI_RELATIVE@@
}
53 if {$oguirel eq
{1}} {
54 set oguilib
[file dirname [file dirname [file normalize
$argv0]]]
55 set oguilib
[file join $oguilib share git-gui lib
]
56 set oguimsg
[file join $oguilib msgs
]
57 } elseif
{[string match @@
* $oguirel]} {
58 set oguilib
[file join [file dirname [file normalize
$argv0]] lib
]
59 set oguimsg
[file join [file dirname [file normalize
$argv0]] po
]
61 set oguimsg
[file join $oguilib msgs
]
65 ######################################################################
67 ## enable verbose loading?
69 if {![catch
{set _verbose
$env(GITGUI_VERBOSE
)}]} {
71 rename auto_load real__auto_load
72 proc auto_load
{name args
} {
73 puts stderr
"auto_load $name"
74 return [uplevel
1 real__auto_load
$name $args]
76 rename
source real__source
78 puts stderr
"source $name"
79 uplevel
1 real__source
$name
83 ######################################################################
85 ## Internationalization (i18n) through msgcat and gettext. See
86 ## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html
88 package require msgcat
91 set fmt [::msgcat
::mc
$fmt]
92 set cmk
[string first @@
$fmt]
94 set fmt [string range
$fmt 0 [expr {$cmk - 1}]]
96 return [eval [list format
$fmt] $args]
100 return [join $args {}]
103 ::msgcat
::mcload
$oguimsg
106 ######################################################################
110 set _appname
[lindex
[file split $argv0] end
]
127 return [eval [list
file join $_gitdir] $args]
130 proc gitexec
{args
} {
132 if {$_gitexec eq
{}} {
133 if {[catch
{set _gitexec
[git
--exec-path]} err
]} {
134 error
"Git not installed?\n\n$err"
137 set _gitexec
[exec cygpath \
142 set _gitexec
[file normalize
$_gitexec]
148 return [eval [list
file join $_gitexec] $args]
156 if {[tk windowingsystem
] eq
{aqua
}} {
163 if {$
::tcl_platform
(platform
) eq
{windows
}} {
171 if {$_iscygwin eq
{}} {
172 if {$
::tcl_platform
(platform
) eq
{windows
}} {
173 if {[catch
{set p
[exec cygpath
--windir]} err
]} {
185 proc is_enabled
{option
} {
186 global enabled_options
187 if {[catch
{set on
$enabled_options($option)}]} {return 0}
191 proc enable_option
{option
} {
192 global enabled_options
193 set enabled_options
($option) 1
196 proc disable_option
{option
} {
197 global enabled_options
198 set enabled_options
($option) 0
201 ######################################################################
205 proc is_many_config
{name
} {
206 switch
-glob -- $name {
215 proc is_config_true
{name
} {
217 if {[catch
{set v
$repo_config($name)}]} {
219 } elseif
{$v eq
{true
} ||
$v eq
{1} ||
$v eq
{yes}} {
226 proc get_config
{name
} {
228 if {[catch
{set v
$repo_config($name)}]} {
235 proc load_config
{include_global
} {
236 global repo_config global_config default_config
238 array
unset global_config
239 if {$include_global} {
241 set fd_rc
[git_read config
--global --list]
242 while {[gets
$fd_rc line
] >= 0} {
243 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
244 if {[is_many_config
$name]} {
245 lappend global_config
($name) $value
247 set global_config
($name) $value
255 array
unset repo_config
257 set fd_rc
[git_read config
--list]
258 while {[gets
$fd_rc line
] >= 0} {
259 if {[regexp
{^
([^
=]+)=(.
*)$
} $line line name value
]} {
260 if {[is_many_config
$name]} {
261 lappend repo_config
($name) $value
263 set repo_config
($name) $value
270 foreach name
[array names default_config
] {
271 if {[catch
{set v
$global_config($name)}]} {
272 set global_config
($name) $default_config($name)
274 if {[catch
{set v
$repo_config($name)}]} {
275 set repo_config
($name) $default_config($name)
280 ######################################################################
284 proc _git_cmd
{name
} {
287 if {[catch
{set v
$_git_cmd_path($name)}]} {
291 --exec-path { return [list $
::_git
$name] }
294 set p
[gitexec git-
$name$
::_search_exe
]
295 if {[file exists
$p]} {
297 } elseif
{[is_Windows
] && [file exists
[gitexec git-
$name]]} {
298 # Try to determine what sort of magic will make
299 # git-$name go and do its thing, because native
300 # Tcl on Windows doesn't know it.
302 set p
[gitexec git-
$name]
307 switch
-glob -- [lindex
$s 0] {
309 #!*perl { set i perl }
310 #!*python { set i python }
311 default
{ error
"git-$name is not supported: $s" }
315 if {![info exists interp
]} {
316 set interp
[_which
$i]
319 error
"git-$name requires $i (not in PATH)"
321 set v
[concat
[list
$interp] [lrange
$s 1 end
] [list
$p]]
323 # Assume it is builtin to git somehow and we
324 # aren't actually able to see a file for it.
326 set v
[list $
::_git
$name]
328 set _git_cmd_path
($name) $v
334 global env _search_exe _search_path
336 if {$_search_path eq
{}} {
338 set _search_path
[split [exec cygpath \
344 } elseif
{[is_Windows
]} {
345 set _search_path
[split $env(PATH
) {;}]
348 set _search_path
[split $env(PATH
) :]
353 foreach p
$_search_path {
354 set p
[file join $p $what$_search_exe]
355 if {[file exists
$p]} {
356 return [file normalize
$p]
362 proc _lappend_nice
{cmd_var
} {
366 if {![info exists _nice
]} {
367 set _nice
[_which nice
]
378 switch
-- [lindex
$args 0] {
389 set args
[lrange
$args 1 end
]
392 set cmdp
[_git_cmd
[lindex
$args 0]]
393 set args
[lrange
$args 1 end
]
395 return [eval $opt $cmdp $args]
398 proc _open_stdout_stderr
{cmd
} {
402 if { [lindex
$cmd end
] eq
{2>@
1}
403 && $err eq
{can not
find channel named
"1"}
405 # Older versions of Tcl 8.4 don't have this 2>@1 IO
406 # redirect operator. Fallback to |& cat for those.
407 # The command was not actually started, so its safe
408 # to try to start it a second time.
410 set fd
[open
[concat \
411 [lrange
$cmd 0 end-1
] \
418 fconfigure
$fd -eofchar {}
422 proc git_read
{args
} {
426 switch
-- [lindex
$args 0] {
441 set args
[lrange
$args 1 end
]
444 set cmdp
[_git_cmd
[lindex
$args 0]]
445 set args
[lrange
$args 1 end
]
447 return [_open_stdout_stderr
[concat
$opt $cmdp $args]]
450 proc git_write
{args
} {
454 switch
-- [lindex
$args 0] {
465 set args
[lrange
$args 1 end
]
468 set cmdp
[_git_cmd
[lindex
$args 0]]
469 set args
[lrange
$args 1 end
]
471 return [open
[concat
$opt $cmdp $args] w
]
475 regsub
-all ' $value "'\\''" value
479 proc load_current_branch {} {
480 global current_branch is_detached
482 set fd [open [gitdir HEAD] r]
483 if {[gets $fd ref] < 1} {
488 set pfx {ref: refs/heads/}
489 set len [string length $pfx]
490 if {[string equal -length $len $pfx $ref]} {
491 # We're on a branch. It might not exist. But
492 # HEAD looks good enough to be a branch.
494 set current_branch [string range $ref $len end]
497 # Assume this is a detached head.
499 set current_branch HEAD
504 auto_load tk_optionMenu
505 rename tk_optionMenu real__tkOptionMenu
506 proc tk_optionMenu {w varName args} {
507 set m [eval real__tkOptionMenu $w $varName $args]
508 $m configure -font font_ui
509 $w configure -font font_ui
513 ######################################################################
517 set _git [_which git]
519 catch {wm withdraw .}
520 error_popup [mc "Cannot
find git
in PATH.
"]
524 ######################################################################
528 if {[catch {set _git_version [git --version]} err]} {
529 catch {wm withdraw .}
533 -title [mc "git-gui
: fatal error
"] \
534 -message "Cannot determine Git version
:
538 [appname
] requires Git
1.5.0 or later.
"
541 if {![regsub {^git version } $_git_version {} _git_version]} {
542 catch {wm withdraw .}
546 -title [mc "git-gui
: fatal error
"] \
547 -message [strcat [mc "Cannot parse Git version string
:"] "\n\n$_git_version"]
551 set _real_git_version $_git_version
552 regsub -- {-dirty$} $_git_version {} _git_version
553 regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
554 regsub {\.rc[0-9]+$} $_git_version {} _git_version
555 regsub {\.GIT$} $_git_version {} _git_version
557 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
558 catch {wm withdraw .}
563 -title "[appname
]: warning
" \
564 -message [mc "Git version cannot be determined.
566 %s claims it is version
'%s'.
568 %s requires
at least Git
1.5.0 or later.
570 Assume
'%s' is version
1.5.0?
571 " $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} {
572 set _git_version 1.5.0
577 unset _real_git_version
579 proc git-version {args} {
582 switch [llength $args] {
588 set op [lindex $args 0]
589 set vr [lindex $args 1]
590 set cm [package vcompare $_git_version $vr]
591 return [expr $cm $op 0]
595 set type [lindex $args 0]
596 set name [lindex $args 1]
597 set parm [lindex $args 2]
598 set body [lindex $args 3]
600 if {($type ne {proc} && $type ne {method})} {
601 error "Invalid arguments to git-version
"
603 if {[llength $body] < 2 || [lindex $body end-1] ne {default}} {
604 error "Last arm of
$type $name must be default
"
607 foreach {op vr cb} [lrange $body 0 end-2] {
608 if {[git-version $op $vr]} {
609 return [uplevel [list $type $name $parm $cb]]
613 return [uplevel [list $type $name $parm [lindex $body end]]]
617 error "git-version
>= x
"
623 if {[git-version < 1.5]} {
624 catch {wm withdraw .}
628 -title [mc "git-gui
: fatal error
"] \
629 -message "[appname
] requires Git
1.5.0 or later.
631 You are using
[git-version
]:
637 ######################################################################
639 ## configure our library
641 set idx [file join $oguilib tclIndex]
642 if {[catch {set fd [open $idx r]} err]} {
643 catch {wm withdraw .}
647 -title [mc "git-gui
: fatal error
"] \
651 if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
653 while {[gets $fd n] >= 0} {
654 if {$n ne {} && ![string match #* $n]} {
666 if {[lsearch -exact $loaded $p] >= 0} continue
667 source [file join $oguilib $p]
672 set auto_path [concat [list $oguilib] $auto_path]
674 unset -nocomplain idx fd
676 ######################################################################
678 ## feature option selection
680 if {[regexp {^git-(.+)$} [appname] _junk subcommand]} {
685 if {$subcommand eq {gui.sh}} {
688 if {$subcommand eq {gui} && [llength $argv] > 0} {
689 set subcommand [lindex $argv 0]
690 set argv [lrange $argv 1 end]
693 enable_option multicommit
695 enable_option transport
698 switch -- $subcommand {
703 disable_option multicommit
704 disable_option branch
705 disable_option transport
708 enable_option singlecommit
710 disable_option multicommit
711 disable_option branch
712 disable_option transport
716 ######################################################################
721 set _gitdir $env(GIT_DIR)
725 set _gitdir [git rev-parse --git-dir]
726 set _prefix [git rev-parse --show-prefix]
728 catch {wm withdraw .}
729 error_popup [strcat [mc "Cannot
find the git directory
:"] "\n\n$err"]
732 if {![file isdirectory $_gitdir] && [is_Cygwin]} {
733 catch {set _gitdir [exec cygpath --unix $_gitdir]}
735 if {![file isdirectory $_gitdir]} {
736 catch {wm withdraw .}
737 error_popup [strcat [mc "Git directory not found
:"] "\n\n$_gitdir"]
740 if {$_prefix ne {}} {
741 regsub -all {[^/]+/} $_prefix ../ cdup
742 if {[catch {cd $cdup} err]} {
743 catch {wm withdraw .}
744 error_popup [strcat [mc "Cannot move to top of working directory
:"] "\n\n$err"]
748 } elseif {![is_enabled bare]} {
749 if {[lindex [file split $_gitdir] end] ne {.git}} {
750 catch {wm withdraw .}
751 error_popup [strcat [mc "Cannot use funny .git directory
:"] "\n\n$_gitdir"]
754 if {[catch {cd [file dirname $_gitdir]} err]} {
755 catch {wm withdraw .}
756 error_popup [strcat [mc "No working directory
"] " [file dirname $_gitdir]:\n\n$err"]
760 set _reponame [file split [file normalize $_gitdir]]
761 if {[lindex $_reponame end] eq {.git}} {
762 set _reponame [lindex $_reponame end-1]
764 set _reponame [lindex $_reponame end]
767 ######################################################################
771 set current_diff_path {}
772 set current_diff_side {}
773 set diff_actions [list]
777 set MERGE_HEAD [list]
780 set current_branch {}
782 set current_diff_path {}
784 set selected_commit_type new
786 ######################################################################
794 set disable_on_lock [list]
795 set index_lock_type none
797 proc lock_index {type} {
798 global index_lock_type disable_on_lock
800 if {$index_lock_type eq {none}} {
801 set index_lock_type $type
802 foreach w $disable_on_lock {
803 uplevel #0 $w disabled
806 } elseif {$index_lock_type eq "begin-
$type"} {
807 set index_lock_type $type
813 proc unlock_index {} {
814 global index_lock_type disable_on_lock
816 set index_lock_type none
817 foreach w $disable_on_lock {
822 ######################################################################
826 proc repository_state {ctvar hdvar mhvar} {
827 global current_branch
828 upvar $ctvar ct $hdvar hd $mhvar mh
833 if {[catch {set hd [git rev-parse --verify HEAD]}]} {
839 set merge_head [gitdir MERGE_HEAD]
840 if {[file exists $merge_head]} {
842 set fd_mh [open $merge_head r]
843 while {[gets $fd_mh line] >= 0} {
854 global PARENT empty_tree
856 set p [lindex $PARENT 0]
860 if {$empty_tree eq {}} {
861 set empty_tree [git mktree << {}]
866 proc rescan {after {honor_trustmtime 1}} {
867 global HEAD PARENT MERGE_HEAD commit_type
868 global ui_index ui_workdir ui_comm
869 global rescan_active file_states
872 if {$rescan_active > 0 || ![lock_index read]} return
874 repository_state newType newHEAD newMERGE_HEAD
875 if {[string match amend* $commit_type]
876 && $newType eq {normal}
877 && $newHEAD eq $HEAD} {
881 set MERGE_HEAD $newMERGE_HEAD
882 set commit_type $newType
885 array unset file_states
887 if {!$::GITGUI_BCK_exists &&
888 (![$ui_comm edit modified]
889 || [string trim [$ui_comm get 0.0 end]] eq {})} {
890 if {[string match amend* $commit_type]} {
891 } elseif {[load_message GITGUI_MSG]} {
892 } elseif {[load_message MERGE_MSG]} {
893 } elseif {[load_message SQUASH_MSG]} {
896 $ui_comm edit modified false
899 if {$honor_trustmtime && $repo_config(gui.trustmtime) eq {true}} {
900 rescan_stage2 {} $after
903 ui_status [mc "Refreshing
file status...
"]
904 set fd_rf [git_read update-index \
910 fconfigure $fd_rf -blocking 0 -translation binary
911 fileevent $fd_rf readable \
912 [list rescan_stage2 $fd_rf $after]
916 proc rescan_stage2 {fd after} {
917 global rescan_active buf_rdi buf_rdf buf_rlo
921 if {![eof $fd]} return
925 set ls_others [list --exclude-per-directory=.gitignore]
926 set info_exclude [gitdir info exclude]
927 if {[file readable $info_exclude]} {
928 lappend ls_others "--exclude-from=$info_exclude"
930 set user_exclude [get_config core.excludesfile]
931 if {$user_exclude ne {} && [file readable $user_exclude]} {
932 lappend ls_others "--exclude-from=$user_exclude"
940 ui_status [mc "Scanning
for modified files ...
"]
941 set fd_di [git_read diff-index --cached -z [PARENT]]
942 set fd_df [git_read diff-files -z]
943 set fd_lo [eval git_read ls-files --others -z $ls_others]
945 fconfigure $fd_di -blocking 0 -translation binary -encoding binary
946 fconfigure $fd_df -blocking 0 -translation binary -encoding binary
947 fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
948 fileevent $fd_di readable [list read_diff_index $fd_di $after]
949 fileevent $fd_df readable [list read_diff_files $fd_df $after]
950 fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
953 proc load_message {file} {
957 if {[file isfile $f]} {
958 if {[catch {set fd [open $f r]}]} {
961 fconfigure $fd -eofchar {}
962 set content [string trim [read $fd]]
964 regsub -all -line {[ \r\t]+$} $content {} content
965 $ui_comm delete 0.0 end
966 $ui_comm insert end $content
972 proc read_diff_index {fd after} {
975 append buf_rdi [read $fd]
977 set n [string length $buf_rdi]
979 set z1 [string first "\
0" $buf_rdi $c]
982 set z2 [string first "\
0" $buf_rdi $z1]
986 set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
987 set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
989 [encoding convertfrom $p] \
991 [list [lindex $i 0] [lindex $i 2]] \
997 set buf_rdi [string range $buf_rdi $c end]
1002 rescan_done $fd buf_rdi $after
1005 proc read_diff_files {fd after} {
1008 append buf_rdf [read $fd]
1010 set n [string length $buf_rdf]
1012 set z1 [string first "\
0" $buf_rdf $c]
1013 if {$z1 == -1} break
1015 set z2 [string first "\
0" $buf_rdf $z1]
1016 if {$z2 == -1} break
1019 set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
1020 set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
1022 [encoding convertfrom $p] \
1025 [list [lindex $i 0] [lindex $i 2]]
1030 set buf_rdf [string range $buf_rdf $c end]
1035 rescan_done $fd buf_rdf $after
1038 proc read_ls_others {fd after} {
1041 append buf_rlo [read $fd]
1042 set pck [split $buf_rlo "\
0"]
1043 set buf_rlo [lindex $pck end]
1044 foreach p [lrange $pck 0 end-1] {
1045 set p [encoding convertfrom $p]
1046 if {[string index $p end] eq {/}} {
1047 set p [string range $p 0 end-1]
1051 rescan_done $fd buf_rlo $after
1054 proc rescan_done {fd buf after} {
1055 global rescan_active current_diff_path
1056 global file_states repo_config
1059 if {![eof $fd]} return
1062 if {[incr rescan_active -1] > 0} return
1067 if {$current_diff_path ne {}} reshow_diff
1071 proc prune_selection {} {
1072 global file_states selected_paths
1074 foreach path [array names selected_paths] {
1075 if {[catch {set still_here $file_states($path)}]} {
1076 unset selected_paths($path)
1081 ######################################################################
1085 proc mapicon {w state path} {
1088 if {[catch {set r $all_icons($state$w)}]} {
1089 puts "error
: no icon
for $w state
={$state} $path"
1095 proc mapdesc {state path} {
1098 if {[catch {set r $all_descs($state)}]} {
1099 puts "error
: no desc
for state
={$state} $path"
1105 proc ui_status {msg} {
1106 $::main_status show $msg
1109 proc ui_ready {{test {}}} {
1110 $::main_status show [mc "Ready.
"] $test
1113 proc escape_path {path} {
1114 regsub -all {\\} $path "\\\\" path
1115 regsub -all "\n" $path "\\n
" path
1119 proc short_path {path} {
1120 return [escape_path [lindex [file split $path] end]]
1124 set null_sha1 [string repeat 0 40]
1126 proc merge_state {path new_state {head_info {}} {index_info {}}} {
1127 global file_states next_icon_id null_sha1
1129 set s0 [string index $new_state 0]
1130 set s1 [string index $new_state 1]
1132 if {[catch {set info $file_states($path)}]} {
1134 set icon n[incr next_icon_id]
1136 set state [lindex $info 0]
1137 set icon [lindex $info 1]
1138 if {$head_info eq {}} {set head_info [lindex $info 2]}
1139 if {$index_info eq {}} {set index_info [lindex $info 3]}
1142 if {$s0 eq {?}} {set s0 [string index $state 0]} \
1143 elseif {$s0 eq {_}} {set s0 _}
1145 if {$s1 eq {?}} {set s1 [string index $state 1]} \
1146 elseif {$s1 eq {_}} {set s1 _}
1148 if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} {
1149 set head_info [list 0 $null_sha1]
1150 } elseif {$s0 ne {_} && [string index $state 0] eq {_}
1151 && $head_info eq {}} {
1152 set head_info $index_info
1155 set file_states($path) [list $s0$s1 $icon \
1156 $head_info $index_info \
1161 proc display_file_helper {w path icon_name old_m new_m} {
1164 if {$new_m eq {_}} {
1165 set lno [lsearch -sorted -exact $file_lists($w) $path]
1167 set file_lists($w) [lreplace $file_lists($w) $lno $lno]
1169 $w conf -state normal
1170 $w delete $lno.0 [expr {$lno + 1}].0
1171 $w conf -state disabled
1173 } elseif {$old_m eq {_} && $new_m ne {_}} {
1174 lappend file_lists($w) $path
1175 set file_lists($w) [lsort -unique $file_lists($w)]
1176 set lno [lsearch -sorted -exact $file_lists($w) $path]
1178 $w conf -state normal
1179 $w image create $lno.0 \
1180 -align center -padx 5 -pady 1 \
1182 -image [mapicon $w $new_m $path]
1183 $w insert $lno.1 "[escape_path
$path]\n"
1184 $w conf -state disabled
1185 } elseif {$old_m ne $new_m} {
1186 $w conf -state normal
1187 $w image conf $icon_name -image [mapicon $w $new_m $path]
1188 $w conf -state disabled
1192 proc display_file {path state} {
1193 global file_states selected_paths
1194 global ui_index ui_workdir
1196 set old_m [merge_state $path $state]
1197 set s $file_states($path)
1198 set new_m [lindex $s 0]
1199 set icon_name [lindex $s 1]
1201 set o [string index $old_m 0]
1202 set n [string index $new_m 0]
1209 display_file_helper $ui_index $path $icon_name $o $n
1211 if {[string index $old_m 0] eq {U}} {
1214 set o [string index $old_m 1]
1216 if {[string index $new_m 0] eq {U}} {
1219 set n [string index $new_m 1]
1221 display_file_helper $ui_workdir $path $icon_name $o $n
1223 if {$new_m eq {__}} {
1224 unset file_states($path)
1225 catch {unset selected_paths($path)}
1229 proc display_all_files_helper {w path icon_name m} {
1232 lappend file_lists($w) $path
1233 set lno [expr {[lindex [split [$w index end] .] 0] - 1}]
1234 $w image create end \
1235 -align center -padx 5 -pady 1 \
1237 -image [mapicon $w $m $path]
1238 $w insert end "[escape_path
$path]\n"
1241 proc display_all_files {} {
1242 global ui_index ui_workdir
1243 global file_states file_lists
1246 $ui_index conf -state normal
1247 $ui_workdir conf -state normal
1249 $ui_index delete 0.0 end
1250 $ui_workdir delete 0.0 end
1253 set file_lists($ui_index) [list]
1254 set file_lists($ui_workdir) [list]
1256 foreach path [lsort [array names file_states]] {
1257 set s $file_states($path)
1259 set icon_name [lindex $s 1]
1261 set s [string index $m 0]
1262 if {$s ne {U} && $s ne {_}} {
1263 display_all_files_helper $ui_index $path \
1267 if {[string index $m 0] eq {U}} {
1270 set s [string index $m 1]
1273 display_all_files_helper $ui_workdir $path \
1278 $ui_index conf -state disabled
1279 $ui_workdir conf -state disabled
1282 ######################################################################
1287 #define mask_width 14
1288 #define mask_height 15
1289 static unsigned char mask_bits[] = {
1290 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1291 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1292 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1295 image create bitmap file_plain -background white -foreground black -data {
1296 #define plain_width 14
1297 #define plain_height 15
1298 static unsigned char plain_bits[] = {
1299 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1300 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1301 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1302 } -maskdata $filemask
1304 image create bitmap file_mod -background white -foreground blue -data {
1305 #define mod_width 14
1306 #define mod_height 15
1307 static unsigned char mod_bits[] = {
1308 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1309 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1310 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1311 } -maskdata $filemask
1313 image create bitmap file_fulltick -background white -foreground "#007000" -data {
1314 #define file_fulltick_width 14
1315 #define file_fulltick_height 15
1316 static unsigned char file_fulltick_bits
[] = {
1317 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1318 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1319 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1320 } -maskdata $filemask
1322 image create bitmap file_parttick
-background white
-foreground "#005050" -data {
1323 #define parttick_width 14
1324 #define parttick_height 15
1325 static unsigned char parttick_bits
[] = {
1326 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1327 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1328 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1329 } -maskdata $filemask
1331 image create bitmap file_question
-background white
-foreground black
-data {
1332 #define file_question_width 14
1333 #define file_question_height 15
1334 static unsigned char file_question_bits
[] = {
1335 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1336 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1337 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1338 } -maskdata $filemask
1340 image create bitmap file_removed
-background white
-foreground red
-data {
1341 #define file_removed_width 14
1342 #define file_removed_height 15
1343 static unsigned char file_removed_bits
[] = {
1344 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1345 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1346 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1347 } -maskdata $filemask
1349 image create bitmap file_merge
-background white
-foreground blue
-data {
1350 #define file_merge_width 14
1351 #define file_merge_height 15
1352 static unsigned char file_merge_bits
[] = {
1353 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1354 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1355 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1356 } -maskdata $filemask
1358 set ui_index .vpane.files.index.list
1359 set ui_workdir .vpane.files.workdir.list
1361 set all_icons
(_
$ui_index) file_plain
1362 set all_icons
(A
$ui_index) file_fulltick
1363 set all_icons
(M
$ui_index) file_fulltick
1364 set all_icons
(D
$ui_index) file_removed
1365 set all_icons
(U
$ui_index) file_merge
1367 set all_icons
(_
$ui_workdir) file_plain
1368 set all_icons
(M
$ui_workdir) file_mod
1369 set all_icons
(D
$ui_workdir) file_question
1370 set all_icons
(U
$ui_workdir) file_merge
1371 set all_icons
(O
$ui_workdir) file_plain
1373 set max_status_desc
0
1375 {__
{mc
"Unmodified"}}
1377 {_M
{mc
"Modified, not staged"}}
1378 {M_
{mc
"Staged for commit"}}
1379 {MM
{mc
"Portions staged for commit"}}
1380 {MD
{mc
"Staged for commit, missing"}}
1382 {_O
{mc
"Untracked, not staged"}}
1383 {A_
{mc
"Staged for commit"}}
1384 {AM
{mc
"Portions staged for commit"}}
1385 {AD
{mc
"Staged for commit, missing"}}
1388 {D_
{mc
"Staged for removal"}}
1389 {DO
{mc
"Staged for removal, still present"}}
1391 {U_
{mc
"Requires merge resolution"}}
1392 {UU
{mc
"Requires merge resolution"}}
1393 {UM
{mc
"Requires merge resolution"}}
1394 {UD
{mc
"Requires merge resolution"}}
1396 set text
[eval [lindex
$i 1]]
1397 if {$max_status_desc < [string length
$text]} {
1398 set max_status_desc
[string length
$text]
1400 set all_descs
([lindex
$i 0]) $text
1404 ######################################################################
1408 proc bind_button3
{w cmd
} {
1409 bind $w <Any-Button-3
> $cmd
1411 # Mac OS X sends Button-2 on right click through three-button mouse,
1412 # or through trackpad right-clicking (two-finger touch + click).
1413 bind $w <Any-Button-2
> $cmd
1414 bind $w <Control-Button-1
> $cmd
1418 proc scrollbar2many
{list mode args
} {
1419 foreach w
$list {eval $w $mode $args}
1422 proc many2scrollbar
{list mode sb top bottom
} {
1423 $sb set $top $bottom
1424 foreach w
$list {$w $mode moveto
$top}
1427 proc incr_font_size
{font
{amt
1}} {
1428 set sz
[font configure
$font -size]
1430 font configure
$font -size $sz
1431 font configure
${font}bold
-size $sz
1432 font configure
${font}italic
-size $sz
1435 ######################################################################
1439 set starting_gitk_msg
[mc
"Starting gitk... please wait..."]
1441 proc do_gitk
{revs
} {
1442 # -- Always start gitk through whatever we were loaded with. This
1443 # lets us bypass using shell process on Windows systems.
1445 set exe
[file join [file dirname $
::_git
] gitk
]
1446 set cmd
[list
[info nameofexecutable
] $exe]
1447 if {! [file exists
$exe]} {
1448 error_popup
[mc
"Unable to start gitk:\n\n%s does not exist" $exe]
1450 eval exec $cmd $revs &
1451 ui_status $
::starting_gitk_msg
1453 ui_ready
$starting_gitk_msg
1461 global ui_comm is_quitting repo_config commit_type
1462 global GITGUI_BCK_exists GITGUI_BCK_i
1464 if {$is_quitting} return
1467 if {[winfo exists
$ui_comm]} {
1468 # -- Stash our current commit buffer.
1470 set save
[gitdir GITGUI_MSG
]
1471 if {$GITGUI_BCK_exists && ![$ui_comm edit modified
]} {
1472 file rename
-force [gitdir GITGUI_BCK
] $save
1473 set GITGUI_BCK_exists
0
1475 set msg
[string trim
[$ui_comm get
0.0 end
]]
1476 regsub
-all -line {[ \r\t]+$
} $msg {} msg
1477 if {(![string match amend
* $commit_type]
1478 ||
[$ui_comm edit modified
])
1481 set fd
[open
$save w
]
1482 puts
-nonewline $fd $msg
1486 catch
{file delete
$save}
1490 # -- Remove our editor backup, its not needed.
1492 after cancel
$GITGUI_BCK_i
1493 if {$GITGUI_BCK_exists} {
1494 catch
{file delete
[gitdir GITGUI_BCK
]}
1497 # -- Stash our current window geometry into this repository.
1499 set cfg_geometry
[list
]
1500 lappend cfg_geometry
[wm geometry .
]
1501 lappend cfg_geometry
[lindex
[.vpane sash coord
0] 1]
1502 lappend cfg_geometry
[lindex
[.vpane.files sash coord
0] 0]
1503 if {[catch
{set rc_geometry
$repo_config(gui.geometry
)}]} {
1506 if {$cfg_geometry ne
$rc_geometry} {
1507 catch
{git config gui.geometry
$cfg_geometry}
1522 proc toggle_or_diff
{w x y
} {
1523 global file_states file_lists current_diff_path ui_index ui_workdir
1524 global last_clicked selected_paths
1526 set pos
[split [$w index @
$x,$y] .
]
1527 set lno
[lindex
$pos 0]
1528 set col [lindex
$pos 1]
1529 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
1535 set last_clicked
[list
$w $lno]
1536 array
unset selected_paths
1537 $ui_index tag remove in_sel
0.0 end
1538 $ui_workdir tag remove in_sel
0.0 end
1541 if {$current_diff_path eq
$path} {
1542 set after
{reshow_diff
;}
1546 if {$w eq
$ui_index} {
1548 "Unstaging [short_path $path] from commit" \
1550 [concat
$after [list ui_ready
]]
1551 } elseif
{$w eq
$ui_workdir} {
1553 "Adding [short_path $path]" \
1555 [concat
$after [list ui_ready
]]
1558 show_diff
$path $w $lno
1562 proc add_one_to_selection
{w x y
} {
1563 global file_lists last_clicked selected_paths
1565 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
1566 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
1572 if {$last_clicked ne
{}
1573 && [lindex
$last_clicked 0] ne
$w} {
1574 array
unset selected_paths
1575 [lindex
$last_clicked 0] tag remove in_sel
0.0 end
1578 set last_clicked
[list
$w $lno]
1579 if {[catch
{set in_sel
$selected_paths($path)}]} {
1583 unset selected_paths
($path)
1584 $w tag remove in_sel
$lno.0 [expr {$lno + 1}].0
1586 set selected_paths
($path) 1
1587 $w tag add in_sel
$lno.0 [expr {$lno + 1}].0
1591 proc add_range_to_selection
{w x y
} {
1592 global file_lists last_clicked selected_paths
1594 if {[lindex
$last_clicked 0] ne
$w} {
1595 toggle_or_diff
$w $x $y
1599 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
1600 set lc
[lindex
$last_clicked 1]
1609 foreach path
[lrange
$file_lists($w) \
1610 [expr {$begin - 1}] \
1611 [expr {$end - 1}]] {
1612 set selected_paths
($path) 1
1614 $w tag add in_sel
$begin.0 [expr {$end + 1}].0
1617 ######################################################################
1621 set cursor_ptr arrow
1622 font create font_diff
-family Courier
-size 10
1626 eval font configure font_ui
[font actual
[.dummy cget
-font]]
1630 font create font_uiitalic
1631 font create font_uibold
1632 font create font_diffbold
1633 font create font_diffitalic
1635 foreach class
{Button Checkbutton Entry Label
1636 Labelframe Listbox Menu Message
1637 Radiobutton Spinbox Text
} {
1638 option add
*$class.font font_ui
1642 if {[is_Windows
] ||
[is_MacOSX
]} {
1643 option add
*Menu.tearOff
0
1654 proc apply_config
{} {
1655 global repo_config font_descs
1657 foreach option
$font_descs {
1658 set name
[lindex
$option 0]
1659 set font
[lindex
$option 1]
1661 foreach
{cn cv
} $repo_config(gui.
$name) {
1662 font configure
$font $cn $cv
1665 error_popup
[strcat
[mc
"Invalid font specified in %s:" "gui.$name"] "\n\n$err"]
1667 foreach
{cn cv
} [font configure
$font] {
1668 font configure
${font}bold
$cn $cv
1669 font configure
${font}italic
$cn $cv
1671 font configure
${font}bold
-weight bold
1672 font configure
${font}italic
-slant italic
1676 set default_config
(merge.diffstat
) true
1677 set default_config
(merge.summary
) false
1678 set default_config
(merge.verbosity
) 2
1679 set default_config
(user.name
) {}
1680 set default_config
(user.email
) {}
1682 set default_config
(gui.matchtrackingbranch
) false
1683 set default_config
(gui.pruneduringfetch
) false
1684 set default_config
(gui.trustmtime
) false
1685 set default_config
(gui.diffcontext
) 5
1686 set default_config
(gui.newbranchtemplate
) {}
1687 set default_config
(gui.fontui
) [font configure font_ui
]
1688 set default_config
(gui.fontdiff
) [font configure font_diff
]
1690 {fontui font_ui
{mc
"Main Font"}}
1691 {fontdiff font_diff
{mc
"Diff/Console Font"}}
1696 ######################################################################
1704 menu .mbar
-tearoff 0
1705 .mbar add cascade
-label [mc Repository
] -menu .mbar.repository
1706 .mbar add cascade
-label [mc Edit
] -menu .mbar.edit
1707 if {[is_enabled branch
]} {
1708 .mbar add cascade
-label [mc Branch
] -menu .mbar.branch
1710 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
1711 .mbar add cascade
-label [mc Commit@@noun
] -menu .mbar.commit
1713 if {[is_enabled transport
]} {
1714 .mbar add cascade
-label [mc Merge
] -menu .mbar.merge
1715 .mbar add cascade
-label [mc Fetch
] -menu .mbar.fetch
1716 .mbar add cascade
-label [mc Push
] -menu .mbar.push
1718 . configure
-menu .mbar
1720 # -- Repository Menu
1722 menu .mbar.repository
1724 .mbar.repository add
command \
1725 -label [mc
"Browse Current Branch's Files"] \
1726 -command {browser
::new
$current_branch}
1727 set ui_browse_current
[.mbar.repository index last
]
1728 .mbar.repository add
command \
1729 -label [mc
"Browse Branch Files..."] \
1730 -command browser_open
::dialog
1731 .mbar.repository add separator
1733 .mbar.repository add
command \
1734 -label [mc
"Visualize Current Branch's History"] \
1735 -command {do_gitk
$current_branch}
1736 set ui_visualize_current
[.mbar.repository index last
]
1737 .mbar.repository add
command \
1738 -label [mc
"Visualize All Branch History"] \
1739 -command {do_gitk
--all}
1740 .mbar.repository add separator
1742 proc current_branch_write
{args
} {
1743 global current_branch
1744 .mbar.repository entryconf $
::ui_browse_current \
1745 -label [mc
"Browse %s's Files" $current_branch]
1746 .mbar.repository entryconf $
::ui_visualize_current \
1747 -label [mc
"Visualize %s's History" $current_branch]
1749 trace add variable current_branch
write current_branch_write
1751 if {[is_enabled multicommit
]} {
1752 .mbar.repository add
command -label [mc
"Database Statistics"] \
1755 .mbar.repository add
command -label [mc
"Compress Database"] \
1758 .mbar.repository add
command -label [mc
"Verify Database"] \
1759 -command do_fsck_objects
1761 .mbar.repository add separator
1764 .mbar.repository add
command \
1765 -label [mc
"Create Desktop Icon"] \
1766 -command do_cygwin_shortcut
1767 } elseif
{[is_Windows
]} {
1768 .mbar.repository add
command \
1769 -label [mc
"Create Desktop Icon"] \
1770 -command do_windows_shortcut
1771 } elseif
{[is_MacOSX
]} {
1772 .mbar.repository add
command \
1773 -label [mc
"Create Desktop Icon"] \
1774 -command do_macosx_app
1778 .mbar.repository add
command -label [mc Quit
] \
1785 .mbar.edit add
command -label [mc Undo
] \
1786 -command {catch
{[focus
] edit undo
}} \
1788 .mbar.edit add
command -label [mc Redo
] \
1789 -command {catch
{[focus
] edit redo
}} \
1791 .mbar.edit add separator
1792 .mbar.edit add
command -label [mc Cut
] \
1793 -command {catch
{tk_textCut
[focus
]}} \
1795 .mbar.edit add
command -label [mc Copy
] \
1796 -command {catch
{tk_textCopy
[focus
]}} \
1798 .mbar.edit add
command -label [mc Paste
] \
1799 -command {catch
{tk_textPaste
[focus
]; [focus
] see insert
}} \
1801 .mbar.edit add
command -label [mc Delete
] \
1802 -command {catch
{[focus
] delete sel.first sel.last
}} \
1804 .mbar.edit add separator
1805 .mbar.edit add
command -label [mc
"Select All"] \
1806 -command {catch
{[focus
] tag add sel
0.0 end
}} \
1811 if {[is_enabled branch
]} {
1814 .mbar.branch add
command -label [mc
"Create..."] \
1815 -command branch_create
::dialog \
1817 lappend disable_on_lock
[list .mbar.branch entryconf \
1818 [.mbar.branch index last
] -state]
1820 .mbar.branch add
command -label [mc
"Checkout..."] \
1821 -command branch_checkout
::dialog \
1823 lappend disable_on_lock
[list .mbar.branch entryconf \
1824 [.mbar.branch index last
] -state]
1826 .mbar.branch add
command -label [mc
"Rename..."] \
1827 -command branch_rename
::dialog
1828 lappend disable_on_lock
[list .mbar.branch entryconf \
1829 [.mbar.branch index last
] -state]
1831 .mbar.branch add
command -label [mc
"Delete..."] \
1832 -command branch_delete
::dialog
1833 lappend disable_on_lock
[list .mbar.branch entryconf \
1834 [.mbar.branch index last
] -state]
1836 .mbar.branch add
command -label [mc
"Reset..."] \
1837 -command merge
::reset_hard
1838 lappend disable_on_lock
[list .mbar.branch entryconf \
1839 [.mbar.branch index last
] -state]
1844 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
1847 .mbar.commit add radiobutton \
1848 -label [mc
"New Commit"] \
1849 -command do_select_commit_type \
1850 -variable selected_commit_type \
1852 lappend disable_on_lock \
1853 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1855 .mbar.commit add radiobutton \
1856 -label [mc
"Amend Last Commit"] \
1857 -command do_select_commit_type \
1858 -variable selected_commit_type \
1860 lappend disable_on_lock \
1861 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1863 .mbar.commit add separator
1865 .mbar.commit add
command -label [mc Rescan
] \
1866 -command do_rescan \
1868 lappend disable_on_lock \
1869 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1871 .mbar.commit add
command -label [mc
"Stage To Commit"] \
1872 -command do_add_selection
1873 lappend disable_on_lock \
1874 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1876 .mbar.commit add
command -label [mc
"Stage Changed Files To Commit"] \
1877 -command do_add_all \
1879 lappend disable_on_lock \
1880 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1882 .mbar.commit add
command -label [mc
"Unstage From Commit"] \
1883 -command do_unstage_selection
1884 lappend disable_on_lock \
1885 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1887 .mbar.commit add
command -label [mc
"Revert Changes"] \
1888 -command do_revert_selection
1889 lappend disable_on_lock \
1890 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1892 .mbar.commit add separator
1894 .mbar.commit add
command -label [mc
"Sign Off"] \
1895 -command do_signoff \
1898 .mbar.commit add
command -label [mc Commit@@verb
] \
1899 -command do_commit \
1900 -accelerator $M1T-Return
1901 lappend disable_on_lock \
1902 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
1907 if {[is_enabled branch
]} {
1909 .mbar.merge add
command -label [mc
"Local Merge..."] \
1910 -command merge
::dialog \
1912 lappend disable_on_lock \
1913 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
1914 .mbar.merge add
command -label [mc
"Abort Merge..."] \
1915 -command merge
::reset_hard
1916 lappend disable_on_lock \
1917 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
1922 if {[is_enabled transport
]} {
1926 .mbar.push add
command -label [mc
"Push..."] \
1927 -command do_push_anywhere \
1929 .mbar.push add
command -label [mc
"Delete..."] \
1930 -command remote_branch_delete
::dialog
1934 # -- Apple Menu (Mac OS X only)
1936 .mbar add cascade
-label [mc Apple
] -menu .mbar.apple
1939 .mbar.apple add
command -label [mc
"About %s" [appname
]] \
1941 .mbar.apple add
command -label [mc
"Options..."] \
1946 .mbar.edit add separator
1947 .mbar.edit add
command -label [mc
"Options..."] \
1953 .mbar add cascade
-label [mc Help
] -menu .mbar.
help
1957 .mbar.
help add
command -label [mc
"About %s" [appname
]] \
1962 catch
{set browser
$repo_config(instaweb.browser
)}
1963 set doc_path
[file dirname [gitexec
]]
1964 set doc_path
[file join $doc_path Documentation index.html
]
1967 set doc_path
[exec cygpath
--mixed $doc_path]
1970 if {$browser eq
{}} {
1973 } elseif
{[is_Cygwin
]} {
1974 set program_files
[file dirname [exec cygpath
--windir]]
1975 set program_files
[file join $program_files {Program Files
}]
1976 set firefox
[file join $program_files {Mozilla Firefox
} firefox.exe
]
1977 set ie
[file join $program_files {Internet Explorer
} IEXPLORE.EXE
]
1978 if {[file exists
$firefox]} {
1979 set browser
$firefox
1980 } elseif
{[file exists
$ie]} {
1983 unset program_files firefox ie
1987 if {[file isfile
$doc_path]} {
1988 set doc_url
"file:$doc_path"
1990 set doc_url
{http
://www.kernel.org
/pub
/software
/scm
/git
/docs
/}
1993 if {$browser ne
{}} {
1994 .mbar.
help add
command -label [mc
"Online Documentation"] \
1995 -command [list
exec $browser $doc_url &]
1997 unset browser doc_path doc_url
2000 bind .
<Visibility
> {
2001 bind .
<Visibility
> {}
2005 # -- Standard bindings
2007 wm protocol . WM_DELETE_WINDOW do_quit
2008 bind all
<$M1B-Key-q> do_quit
2009 bind all
<$M1B-Key-Q> do_quit
2010 bind all
<$M1B-Key-w> {destroy
[winfo toplevel
%W
]}
2011 bind all
<$M1B-Key-W> {destroy
[winfo toplevel
%W
]}
2013 set subcommand_args
{}
2015 puts stderr
"usage: $::argv0 $::subcommand $::subcommand_args"
2019 # -- Not a normal commit type invocation? Do that instead!
2021 switch
-- $subcommand {
2024 set subcommand_args
{rev? path
}
2025 if {$argv eq
{}} usage
2030 if {$is_path ||
[file exists
$_prefix$a]} {
2031 if {$path ne
{}} usage
2034 } elseif
{$a eq
{--}} {
2036 if {$head ne
{}} usage
2041 } elseif
{$head eq
{}} {
2042 if {$head ne
{}} usage
2051 if {$head ne
{} && $path eq
{}} {
2052 set path
$_prefix$head
2059 if {[regexp
{^
[0-9a-f]{1,39}$
} $head]} {
2061 set head [git rev-parse
--verify $head]
2067 set current_branch
$head
2070 switch
-- $subcommand {
2073 if {$path ne
{} && [file isdirectory
$path]} {
2074 set head $current_branch
2080 browser
::new
$head $path
2083 if {$head eq
{} && ![file exists
$path]} {
2084 puts stderr
[mc
"fatal: cannot stat path %s: No such file or directory" $path]
2087 blame
::new
$head $path
2094 if {[llength
$argv] != 0} {
2095 puts
-nonewline stderr
"usage: $argv0"
2096 if {$subcommand ne
{gui
} && [appname
] ne
"git-$subcommand"} {
2097 puts
-nonewline stderr
" $subcommand"
2102 # fall through to setup UI for commits
2105 puts stderr
"usage: $argv0 \[{blame|browser|citool}\]"
2116 -text [mc
"Current Branch:"] \
2120 -textvariable current_branch \
2123 pack .branch.l1
-side left
2124 pack .branch.cb
-side left
-fill x
2125 pack .branch
-side top
-fill x
2127 # -- Main Window Layout
2129 panedwindow .vpane
-orient vertical
2130 panedwindow .vpane.files
-orient horizontal
2131 .vpane add .vpane.files
-sticky nsew
-height 100 -width 200
2132 pack .vpane
-anchor n
-side top
-fill both
-expand 1
2134 # -- Index File List
2136 frame .vpane.files.index
-height 100 -width 200
2137 label .vpane.files.index.title
-text [mc
"Staged Changes (Will Be Committed)"] \
2138 -background lightgreen
2139 text
$ui_index -background white
-borderwidth 0 \
2140 -width 20 -height 10 \
2142 -cursor $cursor_ptr \
2143 -xscrollcommand {.vpane.files.index.sx
set} \
2144 -yscrollcommand {.vpane.files.index.sy
set} \
2146 scrollbar .vpane.files.index.sx
-orient h
-command [list
$ui_index xview
]
2147 scrollbar .vpane.files.index.sy
-orient v
-command [list
$ui_index yview
]
2148 pack .vpane.files.index.title
-side top
-fill x
2149 pack .vpane.files.index.sx
-side bottom
-fill x
2150 pack .vpane.files.index.sy
-side right
-fill y
2151 pack
$ui_index -side left
-fill both
-expand 1
2152 .vpane.files add .vpane.files.index
-sticky nsew
2154 # -- Working Directory File List
2156 frame .vpane.files.workdir
-height 100 -width 200
2157 label .vpane.files.workdir.title
-text [mc
"Unstaged Changes (Will Not Be Committed)"] \
2158 -background lightsalmon
2159 text
$ui_workdir -background white
-borderwidth 0 \
2160 -width 20 -height 10 \
2162 -cursor $cursor_ptr \
2163 -xscrollcommand {.vpane.files.workdir.sx
set} \
2164 -yscrollcommand {.vpane.files.workdir.sy
set} \
2166 scrollbar .vpane.files.workdir.sx
-orient h
-command [list
$ui_workdir xview
]
2167 scrollbar .vpane.files.workdir.sy
-orient v
-command [list
$ui_workdir yview
]
2168 pack .vpane.files.workdir.title
-side top
-fill x
2169 pack .vpane.files.workdir.sx
-side bottom
-fill x
2170 pack .vpane.files.workdir.sy
-side right
-fill y
2171 pack
$ui_workdir -side left
-fill both
-expand 1
2172 .vpane.files add .vpane.files.workdir
-sticky nsew
2174 foreach i
[list
$ui_index $ui_workdir] {
2175 $i tag conf in_diff
-background lightgray
2176 $i tag conf in_sel
-background lightgray
2180 # -- Diff and Commit Area
2182 frame .vpane.lower
-height 300 -width 400
2183 frame .vpane.lower.commarea
2184 frame .vpane.lower.
diff -relief sunken
-borderwidth 1
2185 pack .vpane.lower.commarea
-side top
-fill x
2186 pack .vpane.lower.
diff -side bottom
-fill both
-expand 1
2187 .vpane add .vpane.lower
-sticky nsew
2189 # -- Commit Area Buttons
2191 frame .vpane.lower.commarea.buttons
2192 label .vpane.lower.commarea.buttons.l
-text {} \
2195 pack .vpane.lower.commarea.buttons.l
-side top
-fill x
2196 pack .vpane.lower.commarea.buttons
-side left
-fill y
2198 button .vpane.lower.commarea.buttons.rescan
-text [mc Rescan
] \
2200 pack .vpane.lower.commarea.buttons.rescan
-side top
-fill x
2201 lappend disable_on_lock \
2202 {.vpane.lower.commarea.buttons.rescan conf
-state}
2204 button .vpane.lower.commarea.buttons.incall
-text [mc
"Stage Changed"] \
2206 pack .vpane.lower.commarea.buttons.incall
-side top
-fill x
2207 lappend disable_on_lock \
2208 {.vpane.lower.commarea.buttons.incall conf
-state}
2210 button .vpane.lower.commarea.buttons.signoff
-text [mc
"Sign Off"] \
2212 pack .vpane.lower.commarea.buttons.signoff
-side top
-fill x
2214 button .vpane.lower.commarea.buttons.commit
-text [mc Commit@@verb
] \
2216 pack .vpane.lower.commarea.buttons.commit
-side top
-fill x
2217 lappend disable_on_lock \
2218 {.vpane.lower.commarea.buttons.commit conf
-state}
2220 button .vpane.lower.commarea.buttons.push
-text [mc Push
] \
2221 -command do_push_anywhere
2222 pack .vpane.lower.commarea.buttons.push
-side top
-fill x
2224 # -- Commit Message Buffer
2226 frame .vpane.lower.commarea.buffer
2227 frame .vpane.lower.commarea.buffer.header
2228 set ui_comm .vpane.lower.commarea.buffer.t
2229 set ui_coml .vpane.lower.commarea.buffer.header.l
2230 radiobutton .vpane.lower.commarea.buffer.header.new \
2231 -text [mc
"New Commit"] \
2232 -command do_select_commit_type \
2233 -variable selected_commit_type \
2235 lappend disable_on_lock \
2236 [list .vpane.lower.commarea.buffer.header.new conf
-state]
2237 radiobutton .vpane.lower.commarea.buffer.header.amend \
2238 -text [mc
"Amend Last Commit"] \
2239 -command do_select_commit_type \
2240 -variable selected_commit_type \
2242 lappend disable_on_lock \
2243 [list .vpane.lower.commarea.buffer.header.amend conf
-state]
2247 proc trace_commit_type
{varname args
} {
2248 global ui_coml commit_type
2249 switch
-glob -- $commit_type {
2250 initial
{set txt
[mc
"Initial Commit Message:"]}
2251 amend
{set txt
[mc
"Amended Commit Message:"]}
2252 amend-initial
{set txt
[mc
"Amended Initial Commit Message:"]}
2253 amend-merge
{set txt
[mc
"Amended Merge Commit Message:"]}
2254 merge
{set txt
[mc
"Merge Commit Message:"]}
2255 * {set txt
[mc
"Commit Message:"]}
2257 $ui_coml conf
-text $txt
2259 trace add variable commit_type
write trace_commit_type
2260 pack
$ui_coml -side left
-fill x
2261 pack .vpane.lower.commarea.buffer.header.amend
-side right
2262 pack .vpane.lower.commarea.buffer.header.new
-side right
2264 text
$ui_comm -background white
-borderwidth 1 \
2267 -autoseparators true \
2269 -width 75 -height 9 -wrap none \
2271 -yscrollcommand {.vpane.lower.commarea.buffer.sby
set}
2272 scrollbar .vpane.lower.commarea.buffer.sby \
2273 -command [list
$ui_comm yview
]
2274 pack .vpane.lower.commarea.buffer.header
-side top
-fill x
2275 pack .vpane.lower.commarea.buffer.sby
-side right
-fill y
2276 pack
$ui_comm -side left
-fill y
2277 pack .vpane.lower.commarea.buffer
-side left
-fill y
2279 # -- Commit Message Buffer Context Menu
2281 set ctxm .vpane.lower.commarea.buffer.ctxm
2282 menu
$ctxm -tearoff 0
2285 -command {tk_textCut
$ui_comm}
2288 -command {tk_textCopy
$ui_comm}
2291 -command {tk_textPaste
$ui_comm}
2293 -label [mc Delete
] \
2294 -command {$ui_comm delete sel.first sel.last
}
2297 -label [mc
"Select All"] \
2298 -command {focus
$ui_comm;$ui_comm tag add sel
0.0 end
}
2300 -label [mc
"Copy All"] \
2302 $ui_comm tag add sel
0.0 end
2303 tk_textCopy
$ui_comm
2304 $ui_comm tag remove sel
0.0 end
2308 -label [mc
"Sign Off"] \
2310 bind_button3
$ui_comm "tk_popup $ctxm %X %Y"
2314 proc trace_current_diff_path
{varname args
} {
2315 global current_diff_path diff_actions file_states
2316 if {$current_diff_path eq
{}} {
2322 set p
$current_diff_path
2323 set s
[mapdesc
[lindex
$file_states($p) 0] $p]
2325 set p
[escape_path
$p]
2329 .vpane.lower.
diff.header.status configure
-text $s
2330 .vpane.lower.
diff.header.
file configure
-text $f
2331 .vpane.lower.
diff.header.path configure
-text $p
2332 foreach w
$diff_actions {
2336 trace add variable current_diff_path
write trace_current_diff_path
2338 frame .vpane.lower.
diff.header
-background gold
2339 label .vpane.lower.
diff.header.status \
2341 -width $max_status_desc \
2344 label .vpane.lower.
diff.header.
file \
2348 label .vpane.lower.
diff.header.path \
2352 pack .vpane.lower.
diff.header.status
-side left
2353 pack .vpane.lower.
diff.header.
file -side left
2354 pack .vpane.lower.
diff.header.path
-fill x
2355 set ctxm .vpane.lower.
diff.header.ctxm
2356 menu
$ctxm -tearoff 0
2364 -- $current_diff_path
2366 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2367 bind_button3 .vpane.lower.
diff.header.path
"tk_popup $ctxm %X %Y"
2371 frame .vpane.lower.
diff.body
2372 set ui_diff .vpane.lower.
diff.body.t
2373 text
$ui_diff -background white
-borderwidth 0 \
2374 -width 80 -height 15 -wrap none \
2376 -xscrollcommand {.vpane.lower.
diff.body.sbx
set} \
2377 -yscrollcommand {.vpane.lower.
diff.body.sby
set} \
2379 scrollbar .vpane.lower.
diff.body.sbx
-orient horizontal \
2380 -command [list
$ui_diff xview
]
2381 scrollbar .vpane.lower.
diff.body.sby
-orient vertical \
2382 -command [list
$ui_diff yview
]
2383 pack .vpane.lower.
diff.body.sbx
-side bottom
-fill x
2384 pack .vpane.lower.
diff.body.sby
-side right
-fill y
2385 pack
$ui_diff -side left
-fill both
-expand 1
2386 pack .vpane.lower.
diff.header
-side top
-fill x
2387 pack .vpane.lower.
diff.body
-side bottom
-fill both
-expand 1
2389 $ui_diff tag conf d_cr
-elide true
2390 $ui_diff tag conf d_@
-foreground blue
-font font_diffbold
2391 $ui_diff tag conf d_
+ -foreground {#00a000}
2392 $ui_diff tag conf d_-
-foreground red
2394 $ui_diff tag conf d_
++ -foreground {#00a000}
2395 $ui_diff tag conf d_--
-foreground red
2396 $ui_diff tag conf d_
+s \
2397 -foreground {#00a000} \
2398 -background {#e2effa}
2399 $ui_diff tag conf d_-s \
2401 -background {#e2effa}
2402 $ui_diff tag conf d_s
+ \
2403 -foreground {#00a000} \
2405 $ui_diff tag conf d_s- \
2409 $ui_diff tag conf d
<<<<<<< \
2410 -foreground orange \
2412 $ui_diff tag conf d
======= \
2413 -foreground orange \
2415 $ui_diff tag conf d
>>>>>>> \
2416 -foreground orange \
2419 $ui_diff tag raise sel
2421 # -- Diff Body Context Menu
2423 set ctxm .vpane.lower.
diff.body.ctxm
2424 menu
$ctxm -tearoff 0
2426 -label [mc Refresh
] \
2427 -command reshow_diff
2428 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2431 -command {tk_textCopy
$ui_diff}
2432 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2434 -label [mc
"Select All"] \
2435 -command {focus
$ui_diff;$ui_diff tag add sel
0.0 end
}
2436 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2438 -label [mc
"Copy All"] \
2440 $ui_diff tag add sel
0.0 end
2441 tk_textCopy
$ui_diff
2442 $ui_diff tag remove sel
0.0 end
2444 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2447 -label [mc
"Apply/Reverse Hunk"] \
2448 -command {apply_hunk
$cursorX $cursorY}
2449 set ui_diff_applyhunk
[$ctxm index last
]
2450 lappend diff_actions
[list
$ctxm entryconf
$ui_diff_applyhunk -state]
2453 -label [mc
"Decrease Font Size"] \
2454 -command {incr_font_size font_diff
-1}
2455 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2457 -label [mc
"Increase Font Size"] \
2458 -command {incr_font_size font_diff
1}
2459 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2462 -label [mc
"Show Less Context"] \
2463 -command {if {$repo_config(gui.diffcontext
) >= 1} {
2464 incr repo_config
(gui.diffcontext
) -1
2467 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2469 -label [mc
"Show More Context"] \
2470 -command {if {$repo_config(gui.diffcontext
) < 99} {
2471 incr repo_config
(gui.diffcontext
)
2474 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
2476 $ctxm add
command -label [mc
"Options..."] \
2478 proc popup_diff_menu
{ctxm x y X Y
} {
2479 global current_diff_path file_states
2482 if {$
::ui_index eq $
::current_diff_side
} {
2483 set l
[mc
"Unstage Hunk From Commit"]
2485 set l
[mc
"Stage Hunk For Commit"]
2488 ||
$current_diff_path eq
{}
2489 ||
![info exists file_states
($current_diff_path)]
2490 ||
{_O
} eq
[lindex
$file_states($current_diff_path) 0]} {
2495 $ctxm entryconf $
::ui_diff_applyhunk
-state $s -label $l
2496 tk_popup
$ctxm $X $Y
2498 bind_button3
$ui_diff [list popup_diff_menu
$ctxm %x
%y
%X
%Y
]
2502 set main_status
[::status_bar
::new .status
]
2503 pack .status
-anchor w
-side bottom
-fill x
2504 $main_status show
[mc
"Initializing..."]
2509 set gm
$repo_config(gui.geometry
)
2510 wm geometry .
[lindex
$gm 0]
2511 .vpane sash place
0 \
2512 [lindex
[.vpane sash coord
0] 0] \
2514 .vpane.files sash place
0 \
2516 [lindex
[.vpane.files sash coord
0] 1]
2522 bind $ui_comm <$M1B-Key-Return> {do_commit
;break}
2523 bind $ui_comm <$M1B-Key-i> {do_add_all
;break}
2524 bind $ui_comm <$M1B-Key-I> {do_add_all
;break}
2525 bind $ui_comm <$M1B-Key-x> {tk_textCut
%W
;break}
2526 bind $ui_comm <$M1B-Key-X> {tk_textCut
%W
;break}
2527 bind $ui_comm <$M1B-Key-c> {tk_textCopy
%W
;break}
2528 bind $ui_comm <$M1B-Key-C> {tk_textCopy
%W
;break}
2529 bind $ui_comm <$M1B-Key-v> {tk_textPaste
%W
; %W see insert
; break}
2530 bind $ui_comm <$M1B-Key-V> {tk_textPaste
%W
; %W see insert
; break}
2531 bind $ui_comm <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
2532 bind $ui_comm <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
2534 bind $ui_diff <$M1B-Key-x> {tk_textCopy
%W
;break}
2535 bind $ui_diff <$M1B-Key-X> {tk_textCopy
%W
;break}
2536 bind $ui_diff <$M1B-Key-c> {tk_textCopy
%W
;break}
2537 bind $ui_diff <$M1B-Key-C> {tk_textCopy
%W
;break}
2538 bind $ui_diff <$M1B-Key-v> {break}
2539 bind $ui_diff <$M1B-Key-V> {break}
2540 bind $ui_diff <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
2541 bind $ui_diff <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
2542 bind $ui_diff <Key-Up
> {catch
{%W yview scroll
-1 units
};break}
2543 bind $ui_diff <Key-Down
> {catch
{%W yview scroll
1 units
};break}
2544 bind $ui_diff <Key-Left
> {catch
{%W xview scroll
-1 units
};break}
2545 bind $ui_diff <Key-Right
> {catch
{%W xview scroll
1 units
};break}
2546 bind $ui_diff <Key-k
> {catch
{%W yview scroll
-1 units
};break}
2547 bind $ui_diff <Key-j
> {catch
{%W yview scroll
1 units
};break}
2548 bind $ui_diff <Key-h
> {catch
{%W xview scroll
-1 units
};break}
2549 bind $ui_diff <Key-l
> {catch
{%W xview scroll
1 units
};break}
2550 bind $ui_diff <Control-Key-b
> {catch
{%W yview scroll
-1 pages
};break}
2551 bind $ui_diff <Control-Key-f
> {catch
{%W yview scroll
1 pages
};break}
2552 bind $ui_diff <Button-1
> {focus
%W
}
2554 if {[is_enabled branch
]} {
2555 bind .
<$M1B-Key-n> branch_create
::dialog
2556 bind .
<$M1B-Key-N> branch_create
::dialog
2557 bind .
<$M1B-Key-o> branch_checkout
::dialog
2558 bind .
<$M1B-Key-O> branch_checkout
::dialog
2559 bind .
<$M1B-Key-m> merge
::dialog
2560 bind .
<$M1B-Key-M> merge
::dialog
2562 if {[is_enabled transport
]} {
2563 bind .
<$M1B-Key-p> do_push_anywhere
2564 bind .
<$M1B-Key-P> do_push_anywhere
2567 bind .
<Key-F5
> do_rescan
2568 bind .
<$M1B-Key-r> do_rescan
2569 bind .
<$M1B-Key-R> do_rescan
2570 bind .
<$M1B-Key-s> do_signoff
2571 bind .
<$M1B-Key-S> do_signoff
2572 bind .
<$M1B-Key-i> do_add_all
2573 bind .
<$M1B-Key-I> do_add_all
2574 bind .
<$M1B-Key-Return> do_commit
2575 foreach i
[list
$ui_index $ui_workdir] {
2576 bind $i <Button-1
> "toggle_or_diff $i %x %y; break"
2577 bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break"
2578 bind $i <Shift-Button-1
> "add_range_to_selection $i %x %y; break"
2582 set file_lists
($ui_index) [list
]
2583 set file_lists
($ui_workdir) [list
]
2585 wm title .
"[appname] ([reponame]) [file normalize [file dirname [gitdir]]]"
2586 focus
-force $ui_comm
2588 # -- Warn the user about environmental problems. Cygwin's Tcl
2589 # does *not* pass its env array onto any processes it spawns.
2590 # This means that git processes get none of our environment.
2595 set msg
[mc
"Possible environment issues exist.
2597 The following environment variables are probably
2598 going to be ignored by any Git subprocess run
2602 foreach name
[array names env
] {
2603 switch
-regexp -- $name {
2604 {^GIT_INDEX_FILE$
} -
2605 {^GIT_OBJECT_DIRECTORY$
} -
2606 {^GIT_ALTERNATE_OBJECT_DIRECTORIES$
} -
2608 {^GIT_EXTERNAL_DIFF$
} -
2612 {^GIT_CONFIG_LOCAL$
} -
2613 {^GIT_
(AUTHOR|COMMITTER
)_DATE$
} {
2614 append msg
" - $name\n"
2617 {^GIT_
(AUTHOR|COMMITTER
)_
(NAME|EMAIL
)$
} {
2618 append msg
" - $name\n"
2620 set suggest_user
$name
2624 if {$ignored_env > 0} {
2626 This is due to a known issue with the
2627 Tcl binary distributed by Cygwin."]
2629 if {$suggest_user ne
{}} {
2632 A good replacement for %s
2633 is placing values for the user.name and
2634 user.email settings into your personal
2640 unset ignored_env msg suggest_user name
2643 # -- Only initialize complex UI if we are going to stay running.
2645 if {[is_enabled transport
]} {
2652 if {[winfo exists
$ui_comm]} {
2653 set GITGUI_BCK_exists
[load_message GITGUI_BCK
]
2655 # -- If both our backup and message files exist use the
2656 # newer of the two files to initialize the buffer.
2658 if {$GITGUI_BCK_exists} {
2659 set m
[gitdir GITGUI_MSG
]
2660 if {[file isfile
$m]} {
2661 if {[file mtime
[gitdir GITGUI_BCK
]] > [file mtime
$m]} {
2662 catch
{file delete
[gitdir GITGUI_MSG
]}
2664 $ui_comm delete
0.0 end
2666 $ui_comm edit modified false
2667 catch
{file delete
[gitdir GITGUI_BCK
]}
2668 set GITGUI_BCK_exists
0
2674 proc backup_commit_buffer
{} {
2675 global ui_comm GITGUI_BCK_exists
2677 set m
[$ui_comm edit modified
]
2678 if {$m ||
$GITGUI_BCK_exists} {
2679 set msg
[string trim
[$ui_comm get
0.0 end
]]
2680 regsub
-all -line {[ \r\t]+$
} $msg {} msg
2683 if {$GITGUI_BCK_exists} {
2684 catch
{file delete
[gitdir GITGUI_BCK
]}
2685 set GITGUI_BCK_exists
0
2689 set fd
[open
[gitdir GITGUI_BCK
] w
]
2690 puts
-nonewline $fd $msg
2692 set GITGUI_BCK_exists
1
2696 $ui_comm edit modified false
2699 set ::GITGUI_BCK_i
[after
2000 backup_commit_buffer
]
2702 backup_commit_buffer
2705 lock_index begin-read
2706 if {![winfo ismapped .
]} {
2710 if {[is_enabled multicommit
]} {