2 # Tcl ignores the next line -*- tcl -*- \
3 if test "z$*" = zversion \
4 ||
test "z$*" = z--version
; \
6 echo 'git-gui version @@GITGUI_VERSION@@'; \
10 exec wish
"$argv0" -- "$@"
12 set appvers
{@@GITGUI_VERSION@@
}
13 set copyright
[encoding convertfrom utf-8
{
14 Copyright ©
2006, 2007 Shawn Pearce
, et. al.
16 This program is free software
; you can redistribute it and
/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation
; either version
2 of the License
, or
19 (at your option
) any later version.
21 This program is distributed
in the hope that it will be useful
,
22 but WITHOUT ANY WARRANTY
; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License
for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program
; if not
, write to the Free Software
28 Foundation
, Inc.
, 59 Temple Place
, Suite
330, Boston
, MA
02111-1307 USA
}]
30 ######################################################################
32 ## Tcl/Tk sanity check
34 if {[catch
{package require Tcl
8.4} err
]
35 ||
[catch
{package require Tk
8.4} err
]
41 -title [mc
"git-gui: fatal error"] \
46 catch
{rename send
{}} ; # What an evil concept...
48 ######################################################################
52 set oguilib
{@@GITGUI_LIBDIR@@
}
53 set oguirel
{@@GITGUI_RELATIVE@@
}
54 if {$oguirel eq
{1}} {
55 set oguilib
[file dirname [file normalize
$argv0]]
56 if {[file tail $oguilib] eq
{git-core
}} {
57 set oguilib
[file dirname $oguilib]
59 set oguilib
[file dirname $oguilib]
60 set oguilib
[file join $oguilib share git-gui lib
]
61 set oguimsg
[file join $oguilib msgs
]
62 } elseif
{[string match @@
* $oguirel]} {
63 set oguilib
[file join [file dirname [file normalize
$argv0]] lib
]
64 set oguimsg
[file join [file dirname [file normalize
$argv0]] po
]
66 set oguimsg
[file join $oguilib msgs
]
70 ######################################################################
72 ## enable verbose loading?
74 if {![catch
{set _verbose
$env(GITGUI_VERBOSE
)}]} {
76 rename auto_load real__auto_load
77 proc auto_load
{name args
} {
78 puts stderr
"auto_load $name"
79 return [uplevel
1 real__auto_load
$name $args]
81 rename
source real__source
83 puts stderr
"source $name"
84 uplevel
1 real__source
$name
88 ######################################################################
90 ## Internationalization (i18n) through msgcat and gettext. See
91 ## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html
93 package require msgcat
96 set cmk
[string first @@
$fmt]
98 return [string range
$fmt 0 [expr {$cmk - 1}]]
103 proc mc
{en_fmt args
} {
104 set fmt [_mc_trim
[::msgcat
::mc
$en_fmt]]
105 if {[catch
{set msg
[eval [list format
$fmt] $args]} err
]} {
106 set msg
[eval [list format
[_mc_trim
$en_fmt]] $args]
112 return [join $args {}]
115 ::msgcat
::mcload
$oguimsg
118 ######################################################################
122 set _appname
{Git Gui
}
131 set _trace
[lsearch
-exact $argv --trace]
133 set argv
[lreplace
$argv $_trace $_trace]
149 return [eval [list
file join $_gitdir] $args]
152 proc gitexec
{args
} {
154 if {$_gitexec eq
{}} {
155 if {[catch
{set _gitexec
[git
--exec-path]} err
]} {
156 error
"Git not installed?\n\n$err"
159 set _gitexec
[exec cygpath \
164 set _gitexec
[file normalize
$_gitexec]
170 return [eval [list
file join $_gitexec] $args]
173 proc githtmldir
{args
} {
175 if {$_githtmldir eq
{}} {
176 if {[catch
{set _githtmldir
[git
--html-path]}]} {
177 # Git not installed or option not yet supported
181 set _githtmldir
[exec cygpath \
186 set _githtmldir
[file normalize
$_githtmldir]
192 return [eval [list
file join $_githtmldir] $args]
200 if {[tk windowingsystem
] eq
{aqua
}} {
207 if {$
::tcl_platform
(platform
) eq
{windows
}} {
215 if {$_iscygwin eq
{}} {
216 if {$
::tcl_platform
(platform
) eq
{windows
}} {
217 if {[catch
{set p
[exec cygpath
--windir]} err
]} {
229 proc is_enabled
{option
} {
230 global enabled_options
231 if {[catch
{set on
$enabled_options($option)}]} {return 0}
235 proc enable_option
{option
} {
236 global enabled_options
237 set enabled_options
($option) 1
240 proc disable_option
{option
} {
241 global enabled_options
242 set enabled_options
($option) 0
245 ######################################################################
249 proc is_many_config
{name
} {
250 switch
-glob -- $name {
260 proc is_config_true
{name
} {
262 if {[catch
{set v
$repo_config($name)}]} {
264 } elseif
{$v eq
{true
} ||
$v eq
{1} ||
$v eq
{yes}} {
271 proc get_config
{name
} {
273 if {[catch
{set v
$repo_config($name)}]} {
280 ######################################################################
284 proc _trace_exec
{cmd
} {
285 if {!$
::_trace
} return
291 if {[regexp
{[ \t\r\n'"$?*]} $v]} {
299 proc _git_cmd {name} {
302 if {[catch {set v $_git_cmd_path($name)}]} {
306 --exec-path { return [list $::_git $name] }
309 set p [gitexec git-$name$::_search_exe]
310 if {[file exists $p]} {
312 } elseif {[is_Windows] && [file exists [gitexec git-$name]]} {
313 # Try to determine what sort of magic will make
314 # git-$name go and do its thing, because native
315 # Tcl on Windows doesn't know it.
317 set p
[gitexec git-
$name]
322 switch
-glob -- [lindex
$s 0] {
324 #!*perl { set i perl }
325 #!*python { set i python }
326 default
{ error
"git-$name is not supported: $s" }
330 if {![info exists interp
]} {
331 set interp
[_which
$i]
334 error
"git-$name requires $i (not in PATH)"
336 set v
[concat
[list
$interp] [lrange
$s 1 end
] [list
$p]]
338 # Assume it is builtin to git somehow and we
339 # aren't actually able to see a file for it.
341 set v
[list $
::_git
$name]
343 set _git_cmd_path
($name) $v
348 proc _which
{what args
} {
349 global env _search_exe _search_path
351 if {$_search_path eq
{}} {
352 if {[is_Cygwin
] && [regexp
{^
(/|\.
:)} $env(PATH
)]} {
353 set _search_path
[split [exec cygpath \
359 } elseif
{[is_Windows
]} {
360 set gitguidir
[file dirname [info
script]]
361 regsub
-all ";" $gitguidir "\\;" gitguidir
362 set env
(PATH
) "$gitguidir;$env(PATH)"
363 set _search_path
[split $env(PATH
) {;}]
366 set _search_path
[split $env(PATH
) :]
371 if {[is_Windows
] && [lsearch
-exact $args -script] >= 0} {
374 set suffix
$_search_exe
377 foreach p
$_search_path {
378 set p
[file join $p $what$suffix]
379 if {[file exists
$p]} {
380 return [file normalize
$p]
386 proc _lappend_nice
{cmd_var
} {
390 if {![info exists _nice
]} {
391 set _nice
[_which nice
]
402 switch
-- [lindex
$args 0] {
413 set args
[lrange
$args 1 end
]
416 set cmdp
[_git_cmd
[lindex
$args 0]]
417 set args
[lrange
$args 1 end
]
419 _trace_exec
[concat
$opt $cmdp $args]
420 set result
[eval exec $opt $cmdp $args]
422 puts stderr
"< $result"
427 proc _open_stdout_stderr
{cmd
} {
430 set fd
[open
[concat
[list |
] $cmd] r
]
432 if { [lindex
$cmd end
] eq
{2>@
1}
433 && $err eq
{can not
find channel named
"1"}
435 # Older versions of Tcl 8.4 don't have this 2>@1 IO
436 # redirect operator. Fallback to |& cat for those.
437 # The command was not actually started, so its safe
438 # to try to start it a second time.
440 set fd
[open
[concat \
442 [lrange
$cmd 0 end-1
] \
449 fconfigure
$fd -eofchar {}
453 proc git_read
{args
} {
457 switch
-- [lindex
$args 0] {
472 set args
[lrange
$args 1 end
]
475 set cmdp
[_git_cmd
[lindex
$args 0]]
476 set args
[lrange
$args 1 end
]
478 return [_open_stdout_stderr
[concat
$opt $cmdp $args]]
481 proc git_write
{args
} {
485 switch
-- [lindex
$args 0] {
496 set args
[lrange
$args 1 end
]
499 set cmdp
[_git_cmd
[lindex
$args 0]]
500 set args
[lrange
$args 1 end
]
502 _trace_exec
[concat
$opt $cmdp $args]
503 return [open
[concat
[list |
] $opt $cmdp $args] w
]
506 proc githook_read
{hook_name args
} {
507 set pchook
[gitdir hooks
$hook_name]
510 # On Windows [file executable] might lie so we need to ask
511 # the shell if the hook is executable. Yes that's annoying.
515 if {![info exists interp
]} {
516 set interp
[_which sh
]
519 error
"hook execution requires sh (not in PATH)"
522 set scr
{if test -x "$1";then exec "$@";fi}
523 set sh_c
[list
$interp -c $scr $interp $pchook]
524 return [_open_stdout_stderr
[concat
$sh_c $args]]
527 if {[file executable
$pchook]} {
528 return [_open_stdout_stderr
[concat
[list
$pchook] $args]]
534 proc kill_file_process
{fd
} {
535 set process
[pid
$fd]
539 # Use a Cygwin-specific flag to allow killing
540 # native Windows processes
541 exec kill -f $process
548 proc gitattr
{path attr default
} {
549 if {[catch
{set r
[git check-attr
$attr -- $path]}]} {
552 set r
[join [lrange
[split $r :] 2 end
] :]
555 if {$r eq
{unspecified
}} {
562 regsub
-all ' $value "'\\''" value
566 proc load_current_branch {} {
567 global current_branch is_detached
569 set fd [open [gitdir HEAD] r]
570 if {[gets $fd ref] < 1} {
575 set pfx {ref: refs/heads/}
576 set len [string length $pfx]
577 if {[string equal -length $len $pfx $ref]} {
578 # We're on a branch. It might not exist. But
579 # HEAD looks good enough to be a branch.
581 set current_branch [string range $ref $len end]
584 # Assume this is a detached head.
586 set current_branch HEAD
591 auto_load tk_optionMenu
592 rename tk_optionMenu real__tkOptionMenu
593 proc tk_optionMenu {w varName args} {
594 set m [eval real__tkOptionMenu $w $varName $args]
595 $m configure -font font_ui
596 $w configure -font font_ui
600 proc rmsel_tag {text} {
602 -background [$text cget -background] \
603 -foreground [$text cget -foreground] \
605 $text tag conf in_sel -background lightgray
606 bind $text <Motion> break
611 bind . <Visibility> {
612 bind . <Visibility> {}
617 wm iconbitmap . -default $oguilib/git-gui.ico
618 set ::tk::AlwaysShowSelection 1
620 # Spoof an X11 display for SSH
621 if {![info exists env(DISPLAY)]} {
622 set env(DISPLAY) :9999
626 image create photo gitlogo -width 16 -height 16
628 gitlogo put #33CC33 -to 7 0 9 2
629 gitlogo put #33CC33 -to 4 2 12 4
630 gitlogo put #33CC33 -to 7 4 9 6
631 gitlogo put #CC3333 -to 4 6 12 8
632 gitlogo put gray26 -to 4 9 6 10
633 gitlogo put gray26 -to 3 10 6 12
634 gitlogo put gray26 -to 8 9 13 11
635 gitlogo put gray26 -to 8 11 10 12
636 gitlogo put gray26 -to 11 11 13 14
637 gitlogo put gray26 -to 3 12 5 14
638 gitlogo put gray26 -to 5 13
639 gitlogo put gray26 -to 10 13
640 gitlogo put gray26 -to 4 14 12 15
641 gitlogo put gray26 -to 5 15 11 16
644 wm iconphoto . -default gitlogo
648 ######################################################################
653 font create font_diff -family Courier -size 10
657 eval font configure font_ui [font actual [.dummy cget -font]]
661 font create font_uiitalic
662 font create font_uibold
663 font create font_diffbold
664 font create font_diffitalic
666 foreach class {Button Checkbutton Entry Label
667 Labelframe Listbox Message
668 Radiobutton Spinbox Text} {
669 option add *$class.font font_ui
672 option add *Menu.font font_ui
676 if {[is_Windows] || [is_MacOSX]} {
677 option add *Menu.tearOff 0
688 proc bind_button3 {w cmd} {
689 bind $w <Any-Button-3> $cmd
691 # Mac OS X sends Button-2 on right click through three-button mouse,
692 # or through trackpad right-clicking (two-finger touch + click).
693 bind $w <Any-Button-2> $cmd
694 bind $w <Control-Button-1> $cmd
698 proc apply_config {} {
699 global repo_config font_descs
701 foreach option $font_descs {
702 set name [lindex $option 0]
703 set font [lindex $option 1]
706 foreach {cn cv} $repo_config(gui.$name) {
707 if {$cn eq {-weight}} {
710 font configure $font $cn $cv
713 font configure $font -weight normal
716 error_popup [strcat [mc "Invalid font specified
in %s
:" "gui.
$name"] "\n\n$err"]
718 foreach {cn cv} [font configure $font] {
719 font configure ${font}bold $cn $cv
720 font configure ${font}italic $cn $cv
722 font configure ${font}bold -weight bold
723 font configure ${font}italic -slant italic
727 set default_config(branch.autosetupmerge) true
728 set default_config(merge.tool) {}
729 set default_config(mergetool.keepbackup) true
730 set default_config(merge.diffstat) true
731 set default_config(merge.summary) false
732 set default_config(merge.verbosity) 2
733 set default_config(user.name) {}
734 set default_config(user.email) {}
736 set default_config(gui.encoding) [encoding system]
737 set default_config(gui.matchtrackingbranch) false
738 set default_config(gui.pruneduringfetch) false
739 set default_config(gui.trustmtime) false
740 set default_config(gui.fastcopyblame) false
741 set default_config(gui.copyblamethreshold) 40
742 set default_config(gui.blamehistoryctx) 7
743 set default_config(gui.diffcontext) 5
744 set default_config(gui.commitmsgwidth) 75
745 set default_config(gui.newbranchtemplate) {}
746 set default_config(gui.spellingdictionary) {}
747 set default_config(gui.fontui) [font configure font_ui]
748 set default_config(gui.fontdiff) [font configure font_diff]
749 # TODO: this option should be added to the git-config documentation
750 set default_config(gui.maxfilesdisplayed) 5000
752 {fontui font_ui {mc "Main Font
"}}
753 {fontdiff font_diff {mc "Diff
/Console Font
"}}
756 ######################################################################
760 set _git [_which git]
762 catch {wm withdraw .}
766 -title [mc "git-gui
: fatal error
"] \
767 -message [mc "Cannot
find git
in PATH.
"]
771 ######################################################################
775 if {[catch {set _git_version [git --version]} err]} {
776 catch {wm withdraw .}
780 -title [mc "git-gui
: fatal error
"] \
781 -message "Cannot determine Git version
:
785 [appname
] requires Git
1.5.0 or later.
"
788 if {![regsub {^git version } $_git_version {} _git_version]} {
789 catch {wm withdraw .}
793 -title [mc "git-gui
: fatal error
"] \
794 -message [strcat [mc "Cannot parse Git version string
:"] "\n\n$_git_version"]
798 set _real_git_version $_git_version
799 regsub -- {[\-\.]dirty$} $_git_version {} _git_version
800 regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version
801 regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
802 regsub {\.GIT$} $_git_version {} _git_version
803 regsub {\.[a-zA-Z]+\.?[0-9]+$} $_git_version {} _git_version
805 if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} {
806 catch {wm withdraw .}
811 -title "[appname
]: warning
" \
812 -message [mc "Git version cannot be determined.
814 %s claims it is version
'%s'.
816 %s requires
at least Git
1.5.0 or later.
818 Assume
'%s' is version
1.5.0?
819 " $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} {
820 set _git_version 1.5.0
825 unset _real_git_version
827 proc git-version {args} {
830 switch [llength $args] {
836 set op [lindex $args 0]
837 set vr [lindex $args 1]
838 set cm [package vcompare $_git_version $vr]
839 return [expr $cm $op 0]
843 set type [lindex $args 0]
844 set name [lindex $args 1]
845 set parm [lindex $args 2]
846 set body [lindex $args 3]
848 if {($type ne {proc} && $type ne {method})} {
849 error "Invalid arguments to git-version
"
851 if {[llength $body] < 2 || [lindex $body end-1] ne {default}} {
852 error "Last arm of
$type $name must be default
"
855 foreach {op vr cb} [lrange $body 0 end-2] {
856 if {[git-version $op $vr]} {
857 return [uplevel [list $type $name $parm $cb]]
861 return [uplevel [list $type $name $parm [lindex $body end]]]
865 error "git-version
>= x
"
871 if {[git-version < 1.5]} {
872 catch {wm withdraw .}
876 -title [mc "git-gui
: fatal error
"] \
877 -message "[appname
] requires Git
1.5.0 or later.
879 You are using
[git-version
]:
885 ######################################################################
887 ## configure our library
889 set idx [file join $oguilib tclIndex]
890 if {[catch {set fd [open $idx r]} err]} {
891 catch {wm withdraw .}
895 -title [mc "git-gui
: fatal error
"] \
899 if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} {
901 while {[gets $fd n] >= 0} {
902 if {$n ne {} && ![string match #* $n]} {
914 if {[lsearch -exact $loaded $p] >= 0} continue
915 source [file join $oguilib $p]
920 set auto_path [concat [list $oguilib] $auto_path]
922 unset -nocomplain idx fd
924 ######################################################################
926 ## config file parsing
928 git-version proc _parse_config {arr_name args} {
935 [list git_read config] \
937 [list --null --list]]
938 fconfigure $fd_rc -translation binary
939 set buf [read $fd_rc]
942 foreach line [split $buf "\
0"] {
943 if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} {
944 if {[is_many_config $name]} {
945 lappend arr($name) $value
947 set arr($name) $value
956 set fd_rc [eval [list git_read config --list] $args]
957 while {[gets $fd_rc line] >= 0} {
958 if {[regexp {^([^=]+)=(.*)$} $line line name value]} {
959 if {[is_many_config $name]} {
960 lappend arr($name) $value
962 set arr($name) $value
971 proc load_config {include_global} {
972 global repo_config global_config system_config default_config
974 if {$include_global} {
975 _parse_config system_config --system
976 _parse_config global_config --global
978 _parse_config repo_config
980 foreach name [array names default_config] {
981 if {[catch {set v $system_config($name)}]} {
982 set system_config($name) $default_config($name)
985 foreach name [array names system_config] {
986 if {[catch {set v $global_config($name)}]} {
987 set global_config($name) $system_config($name)
989 if {[catch {set v $repo_config($name)}]} {
990 set repo_config($name) $system_config($name)
995 ######################################################################
997 ## feature option selection
999 if {[regexp {^git-(.+)$} [file tail $argv0] _junk subcommand]} {
1004 if {$subcommand eq {gui.sh}} {
1007 if {$subcommand eq {gui} && [llength $argv] > 0} {
1008 set subcommand [lindex $argv 0]
1009 set argv [lrange $argv 1 end]
1012 enable_option multicommit
1013 enable_option branch
1014 enable_option transport
1017 switch -- $subcommand {
1022 disable_option multicommit
1023 disable_option branch
1024 disable_option transport
1027 enable_option singlecommit
1028 enable_option retcode
1030 disable_option multicommit
1031 disable_option branch
1032 disable_option transport
1034 while {[llength $argv] > 0} {
1035 set a [lindex $argv 0]
1038 enable_option initialamend
1041 enable_option nocommit
1042 enable_option nocommitmsg
1045 disable_option nocommitmsg
1052 set argv [lrange $argv 1 end]
1057 ######################################################################
1059 ## execution environment
1061 set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
1063 # Suggest our implementation of askpass, if none is set
1064 if {![info exists env(SSH_ASKPASS)]} {
1065 set env(SSH_ASKPASS) [gitexec git-gui--askpass]
1068 ######################################################################
1074 set _gitdir $env(GIT_DIR)
1078 # beware that from the .git dir this sets _gitdir to .
1079 # and _prefix to the empty string
1080 set _gitdir [git rev-parse --git-dir]
1081 set _prefix [git rev-parse --show-prefix]
1085 choose_repository::pick
1089 # we expand the _gitdir when it's just a single dot (i.e. when we're being
1090 # run from the .git dir itself) lest the routines to find the worktree
1092 if {$_gitdir eq ".
"} {
1096 if {![file isdirectory $_gitdir] && [is_Cygwin]} {
1097 catch {set _gitdir [exec cygpath --windows $_gitdir]}
1099 if {![file isdirectory $_gitdir]} {
1100 catch {wm withdraw .}
1101 error_popup [strcat [mc "Git directory not found
:"] "\n\n$_gitdir"]
1104 # _gitdir exists, so try loading the config
1107 # try to set work tree from environment, falling back to core.worktree
1108 if {[catch { set _gitworktree $env(GIT_WORK_TREE) }]} {
1109 set _gitworktree [get_config core.worktree]
1111 if {$_prefix ne {}} {
1112 if {$_gitworktree eq {}} {
1113 regsub -all {[^/]+/} $_prefix ../ cdup
1115 set cdup $_gitworktree
1117 if {[catch {cd $cdup} err]} {
1118 catch {wm withdraw .}
1119 error_popup [strcat [mc "Cannot move to top of working directory
:"] "\n\n$err"]
1122 set _gitworktree [pwd]
1124 } elseif {![is_enabled bare]} {
1125 if {[lindex [file split $_gitdir] end] ne {.git}} {
1126 catch {wm withdraw .}
1127 error_popup [strcat [mc "Cannot use funny .git directory
:"] "\n\n$_gitdir"]
1130 if {$_gitworktree eq {}} {
1131 set _gitworktree [file dirname $_gitdir]
1133 if {[catch {cd $_gitworktree} err]} {
1134 catch {wm withdraw .}
1135 error_popup [strcat [mc "No working directory
"] " $_gitworktree:\n\n$err"]
1138 set _gitworktree [pwd]
1140 set _reponame [file split [file normalize $_gitdir]]
1141 if {[lindex $_reponame end] eq {.git}} {
1142 set _reponame [lindex $_reponame end-1]
1144 set _reponame [lindex $_reponame end]
1147 ######################################################################
1151 set current_diff_path {}
1152 set current_diff_side {}
1153 set diff_actions [list]
1157 set MERGE_HEAD [list]
1160 set current_branch {}
1162 set current_diff_path {}
1164 set is_submodule_diff 0
1165 set is_conflict_diff 0
1166 set selected_commit_type new
1167 set diff_empty_count 0
1169 set nullid "0000000000000000000000000000000000000000"
1170 set nullid2 "0000000000000000000000000000000000000001"
1172 ######################################################################
1180 set disable_on_lock [list]
1181 set index_lock_type none
1183 proc lock_index {type} {
1184 global index_lock_type disable_on_lock
1186 if {$index_lock_type eq {none}} {
1187 set index_lock_type $type
1188 foreach w $disable_on_lock {
1189 uplevel #0 $w disabled
1192 } elseif {$index_lock_type eq "begin-
$type"} {
1193 set index_lock_type $type
1199 proc unlock_index {} {
1200 global index_lock_type disable_on_lock
1202 set index_lock_type none
1203 foreach w $disable_on_lock {
1204 uplevel #0 $w normal
1208 ######################################################################
1212 proc repository_state {ctvar hdvar mhvar} {
1213 global current_branch
1214 upvar $ctvar ct $hdvar hd $mhvar mh
1219 if {[catch {set hd [git rev-parse --verify HEAD]}]} {
1225 set merge_head [gitdir MERGE_HEAD]
1226 if {[file exists $merge_head]} {
1228 set fd_mh [open $merge_head r]
1229 while {[gets $fd_mh line] >= 0} {
1240 global PARENT empty_tree
1242 set p [lindex $PARENT 0]
1246 if {$empty_tree eq {}} {
1247 set empty_tree [git mktree << {}]
1252 proc force_amend {} {
1253 global selected_commit_type
1254 global HEAD PARENT MERGE_HEAD commit_type
1256 repository_state newType newHEAD newMERGE_HEAD
1259 set MERGE_HEAD $newMERGE_HEAD
1260 set commit_type $newType
1262 set selected_commit_type amend
1263 do_select_commit_type
1266 proc rescan {after {honor_trustmtime 1}} {
1267 global HEAD PARENT MERGE_HEAD commit_type
1268 global ui_index ui_workdir ui_comm
1269 global rescan_active file_states
1272 if {$rescan_active > 0 || ![lock_index read]} return
1274 repository_state newType newHEAD newMERGE_HEAD
1275 if {[string match amend* $commit_type]
1276 && $newType eq {normal}
1277 && $newHEAD eq $HEAD} {
1281 set MERGE_HEAD $newMERGE_HEAD
1282 set commit_type $newType
1285 array unset file_states
1287 if {!$::GITGUI_BCK_exists &&
1288 (![$ui_comm edit modified]
1289 || [string trim [$ui_comm get 0.0 end]] eq {})} {
1290 if {[string match amend* $commit_type]} {
1291 } elseif {[load_message GITGUI_MSG]} {
1292 } elseif {[run_prepare_commit_msg_hook]} {
1293 } elseif {[load_message MERGE_MSG]} {
1294 } elseif {[load_message SQUASH_MSG]} {
1297 $ui_comm edit modified false
1300 if {$honor_trustmtime && $repo_config(gui.trustmtime) eq {true}} {
1301 rescan_stage2 {} $after
1304 ui_status [mc "Refreshing
file status...
"]
1305 set fd_rf [git_read update-index \
1311 fconfigure $fd_rf -blocking 0 -translation binary
1312 fileevent $fd_rf readable \
1313 [list rescan_stage2 $fd_rf $after]
1318 set is_git_info_exclude {}
1319 proc have_info_exclude {} {
1320 global is_git_info_exclude
1322 if {$is_git_info_exclude eq {}} {
1323 if {[catch {exec test -f [gitdir info exclude]}]} {
1324 set is_git_info_exclude 0
1326 set is_git_info_exclude 1
1329 return $is_git_info_exclude
1332 proc have_info_exclude {} {
1333 return [file readable [gitdir info exclude]]
1337 proc rescan_stage2 {fd after} {
1338 global rescan_active buf_rdi buf_rdf buf_rlo
1342 if {![eof $fd]} return
1346 set ls_others [list --exclude-per-directory=.gitignore]
1347 if {[have_info_exclude]} {
1348 lappend ls_others "--exclude-from=[gitdir info exclude
]"
1350 set user_exclude [get_config core.excludesfile]
1351 if {$user_exclude ne {} && [file readable $user_exclude]} {
1352 lappend ls_others "--exclude-from=$user_exclude"
1360 ui_status [mc "Scanning
for modified files ...
"]
1361 set fd_di [git_read diff-index --cached -z [PARENT]]
1362 set fd_df [git_read diff-files -z]
1363 set fd_lo [eval git_read ls-files --others -z $ls_others]
1365 fconfigure $fd_di -blocking 0 -translation binary -encoding binary
1366 fconfigure $fd_df -blocking 0 -translation binary -encoding binary
1367 fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
1368 fileevent $fd_di readable [list read_diff_index $fd_di $after]
1369 fileevent $fd_df readable [list read_diff_files $fd_df $after]
1370 fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
1373 proc load_message {file} {
1376 set f [gitdir $file]
1377 if {[file isfile $f]} {
1378 if {[catch {set fd [open $f r]}]} {
1381 fconfigure $fd -eofchar {}
1382 set content [string trim [read $fd]]
1384 regsub -all -line {[ \r\t]+$} $content {} content
1385 $ui_comm delete 0.0 end
1386 $ui_comm insert end $content
1392 proc run_prepare_commit_msg_hook {} {
1395 # prepare-commit-msg requires PREPARE_COMMIT_MSG exist. From git-gui
1396 # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
1397 # empty file but existant file.
1399 set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
1401 if {[file isfile [gitdir MERGE_MSG]]} {
1402 set pcm_source "merge
"
1403 set fd_mm [open [gitdir MERGE_MSG] r]
1404 puts -nonewline $fd_pcm [read $fd_mm]
1406 } elseif {[file isfile [gitdir SQUASH_MSG]]} {
1407 set pcm_source "squash
"
1408 set fd_sm [open [gitdir SQUASH_MSG] r]
1409 puts -nonewline $fd_pcm [read $fd_sm]
1417 set fd_ph [githook_read prepare-commit-msg \
1418 [gitdir PREPARE_COMMIT_MSG] $pcm_source]
1420 catch {file delete [gitdir PREPARE_COMMIT_MSG]}
1424 ui_status [mc "Calling prepare-commit-msg hook...
"]
1427 fconfigure $fd_ph -blocking 0 -translation binary -eofchar {}
1428 fileevent $fd_ph readable \
1429 [list prepare_commit_msg_hook_wait $fd_ph]
1434 proc prepare_commit_msg_hook_wait {fd_ph} {
1437 append pch_error [read $fd_ph]
1438 fconfigure $fd_ph -blocking 1
1440 if {[catch {close $fd_ph}]} {
1441 ui_status [mc "Commit declined by prepare-commit-msg hook.
"]
1442 hook_failed_popup prepare-commit-msg $pch_error
1443 catch {file delete [gitdir PREPARE_COMMIT_MSG]}
1446 load_message PREPARE_COMMIT_MSG
1449 catch {file delete [gitdir PREPARE_COMMIT_MSG]}
1452 fconfigure $fd_ph -blocking 0
1453 catch {file delete [gitdir PREPARE_COMMIT_MSG]}
1456 proc read_diff_index {fd after} {
1459 append buf_rdi [read $fd]
1461 set n [string length $buf_rdi]
1463 set z1 [string first "\
0" $buf_rdi $c]
1464 if {$z1 == -1} break
1466 set z2 [string first "\
0" $buf_rdi $z1]
1467 if {$z2 == -1} break
1470 set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }]
1471 set p [string range $buf_rdi $z1 [expr {$z2 - 1}]]
1473 [encoding convertfrom $p] \
1475 [list [lindex $i 0] [lindex $i 2]] \
1481 set buf_rdi [string range $buf_rdi $c end]
1486 rescan_done $fd buf_rdi $after
1489 proc read_diff_files {fd after} {
1492 append buf_rdf [read $fd]
1494 set n [string length $buf_rdf]
1496 set z1 [string first "\
0" $buf_rdf $c]
1497 if {$z1 == -1} break
1499 set z2 [string first "\
0" $buf_rdf $z1]
1500 if {$z2 == -1} break
1503 set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }]
1504 set p [string range $buf_rdf $z1 [expr {$z2 - 1}]]
1506 [encoding convertfrom $p] \
1509 [list [lindex $i 0] [lindex $i 2]]
1514 set buf_rdf [string range $buf_rdf $c end]
1519 rescan_done $fd buf_rdf $after
1522 proc read_ls_others {fd after} {
1525 append buf_rlo [read $fd]
1526 set pck [split $buf_rlo "\
0"]
1527 set buf_rlo [lindex $pck end]
1528 foreach p [lrange $pck 0 end-1] {
1529 set p [encoding convertfrom $p]
1530 if {[string index $p end] eq {/}} {
1531 set p [string range $p 0 end-1]
1535 rescan_done $fd buf_rlo $after
1538 proc rescan_done {fd buf after} {
1539 global rescan_active current_diff_path
1540 global file_states repo_config
1543 if {![eof $fd]} return
1546 if {[incr rescan_active -1] > 0} return
1551 if {$current_diff_path ne {}} { reshow_diff $after }
1552 if {$current_diff_path eq {}} { select_first_diff $after }
1555 proc prune_selection {} {
1556 global file_states selected_paths
1558 foreach path [array names selected_paths] {
1559 if {[catch {set still_here $file_states($path)}]} {
1560 unset selected_paths($path)
1565 ######################################################################
1569 proc mapicon {w state path} {
1572 if {[catch {set r $all_icons($state$w)}]} {
1573 puts "error
: no icon
for $w state
={$state} $path"
1579 proc mapdesc {state path} {
1582 if {[catch {set r $all_descs($state)}]} {
1583 puts "error
: no desc
for state
={$state} $path"
1589 proc ui_status {msg} {
1591 if {[info exists main_status]} {
1592 $main_status show $msg
1596 proc ui_ready {{test {}}} {
1598 if {[info exists main_status]} {
1599 $main_status show [mc "Ready.
"] $test
1603 proc escape_path {path} {
1604 regsub -all {\\} $path "\\\\" path
1605 regsub -all "\n" $path "\\n
" path
1609 proc short_path {path} {
1610 return [escape_path [lindex [file split $path] end]]
1614 set null_sha1 [string repeat 0 40]
1616 proc merge_state {path new_state {head_info {}} {index_info {}}} {
1617 global file_states next_icon_id null_sha1
1619 set s0 [string index $new_state 0]
1620 set s1 [string index $new_state 1]
1622 if {[catch {set info $file_states($path)}]} {
1624 set icon n[incr next_icon_id]
1626 set state [lindex $info 0]
1627 set icon [lindex $info 1]
1628 if {$head_info eq {}} {set head_info [lindex $info 2]}
1629 if {$index_info eq {}} {set index_info [lindex $info 3]}
1632 if {$s0 eq {?}} {set s0 [string index $state 0]} \
1633 elseif {$s0 eq {_}} {set s0 _}
1635 if {$s1 eq {?}} {set s1 [string index $state 1]} \
1636 elseif {$s1 eq {_}} {set s1 _}
1638 if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} {
1639 set head_info [list 0 $null_sha1]
1640 } elseif {$s0 ne {_} && [string index $state 0] eq {_}
1641 && $head_info eq {}} {
1642 set head_info $index_info
1643 } elseif {$s0 eq {_} && [string index $state 0] ne {_}} {
1644 set index_info $head_info
1648 set file_states($path) [list $s0$s1 $icon \
1649 $head_info $index_info \
1654 proc display_file_helper {w path icon_name old_m new_m} {
1657 if {$new_m eq {_}} {
1658 set lno [lsearch -sorted -exact $file_lists($w) $path]
1660 set file_lists($w) [lreplace $file_lists($w) $lno $lno]
1662 $w conf -state normal
1663 $w delete $lno.0 [expr {$lno + 1}].0
1664 $w conf -state disabled
1666 } elseif {$old_m eq {_} && $new_m ne {_}} {
1667 lappend file_lists($w) $path
1668 set file_lists($w) [lsort -unique $file_lists($w)]
1669 set lno [lsearch -sorted -exact $file_lists($w) $path]
1671 $w conf -state normal
1672 $w image create $lno.0 \
1673 -align center -padx 5 -pady 1 \
1675 -image [mapicon $w $new_m $path]
1676 $w insert $lno.1 "[escape_path
$path]\n"
1677 $w conf -state disabled
1678 } elseif {$old_m ne $new_m} {
1679 $w conf -state normal
1680 $w image conf $icon_name -image [mapicon $w $new_m $path]
1681 $w conf -state disabled
1685 proc display_file {path state} {
1686 global file_states selected_paths
1687 global ui_index ui_workdir
1689 set old_m [merge_state $path $state]
1690 set s $file_states($path)
1691 set new_m [lindex $s 0]
1692 set icon_name [lindex $s 1]
1694 set o [string index $old_m 0]
1695 set n [string index $new_m 0]
1702 display_file_helper $ui_index $path $icon_name $o $n
1704 if {[string index $old_m 0] eq {U}} {
1707 set o [string index $old_m 1]
1709 if {[string index $new_m 0] eq {U}} {
1712 set n [string index $new_m 1]
1714 display_file_helper $ui_workdir $path $icon_name $o $n
1716 if {$new_m eq {__}} {
1717 unset file_states($path)
1718 catch {unset selected_paths($path)}
1722 proc display_all_files_helper {w path icon_name m} {
1725 lappend file_lists($w) $path
1726 set lno [expr {[lindex [split [$w index end] .] 0] - 1}]
1727 $w image create end \
1728 -align center -padx 5 -pady 1 \
1730 -image [mapicon $w $m $path]
1731 $w insert end "[escape_path
$path]\n"
1735 proc display_all_files {} {
1736 global ui_index ui_workdir
1737 global file_states file_lists
1739 global files_warning
1741 $ui_index conf -state normal
1742 $ui_workdir conf -state normal
1744 $ui_index delete 0.0 end
1745 $ui_workdir delete 0.0 end
1748 set file_lists($ui_index) [list]
1749 set file_lists($ui_workdir) [list]
1751 set to_display [lsort [array names file_states]]
1752 set display_limit [get_config gui.maxfilesdisplayed]
1753 if {[llength $to_display] > $display_limit} {
1754 if {!$files_warning} {
1755 # do not repeatedly warn:
1757 info_popup [mc "Displaying only
%s of
%s files.
" \
1758 $display_limit [llength $to_display]]
1760 set to_display [lrange $to_display 0 [expr {$display_limit-1}]]
1762 foreach path $to_display {
1763 set s $file_states($path)
1765 set icon_name [lindex $s 1]
1767 set s [string index $m 0]
1768 if {$s ne {U} && $s ne {_}} {
1769 display_all_files_helper $ui_index $path \
1773 if {[string index $m 0] eq {U}} {
1776 set s [string index $m 1]
1779 display_all_files_helper $ui_workdir $path \
1784 $ui_index conf -state disabled
1785 $ui_workdir conf -state disabled
1788 ######################################################################
1793 #define mask_width 14
1794 #define mask_height 15
1795 static unsigned char mask_bits[] = {
1796 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1797 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f,
1798 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f};
1801 image create bitmap file_plain -background white -foreground black -data {
1802 #define plain_width 14
1803 #define plain_height 15
1804 static unsigned char plain_bits[] = {
1805 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1806 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10,
1807 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1808 } -maskdata $filemask
1810 image create bitmap file_mod -background white -foreground blue -data {
1811 #define mod_width 14
1812 #define mod_height 15
1813 static unsigned char mod_bits[] = {
1814 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1815 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1816 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1817 } -maskdata $filemask
1819 image create bitmap file_fulltick -background white -foreground "#007000" -data {
1820 #define file_fulltick_width 14
1821 #define file_fulltick_height 15
1822 static unsigned char file_fulltick_bits
[] = {
1823 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16,
1824 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10,
1825 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1826 } -maskdata $filemask
1828 image create bitmap file_parttick
-background white
-foreground "#005050" -data {
1829 #define parttick_width 14
1830 #define parttick_height 15
1831 static unsigned char parttick_bits
[] = {
1832 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10,
1833 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10,
1834 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1835 } -maskdata $filemask
1837 image create bitmap file_question
-background white
-foreground black
-data {
1838 #define file_question_width 14
1839 #define file_question_height 15
1840 static unsigned char file_question_bits
[] = {
1841 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13,
1842 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10,
1843 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1844 } -maskdata $filemask
1846 image create bitmap file_removed
-background white
-foreground red
-data {
1847 #define file_removed_width 14
1848 #define file_removed_height 15
1849 static unsigned char file_removed_bits
[] = {
1850 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10,
1851 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13,
1852 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f};
1853 } -maskdata $filemask
1855 image create bitmap file_merge
-background white
-foreground blue
-data {
1856 #define file_merge_width 14
1857 #define file_merge_height 15
1858 static unsigned char file_merge_bits
[] = {
1859 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10,
1860 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10,
1861 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f};
1862 } -maskdata $filemask
1864 image create bitmap file_statechange
-background white
-foreground green
-data {
1865 #define file_merge_width 14
1866 #define file_merge_height 15
1867 static unsigned char file_statechange_bits
[] = {
1868 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10,
1869 0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10,
1870 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f};
1871 } -maskdata $filemask
1873 set ui_index .vpane.files.index.list
1874 set ui_workdir .vpane.files.workdir.list
1876 set all_icons
(_
$ui_index) file_plain
1877 set all_icons
(A
$ui_index) file_fulltick
1878 set all_icons
(M
$ui_index) file_fulltick
1879 set all_icons
(D
$ui_index) file_removed
1880 set all_icons
(U
$ui_index) file_merge
1881 set all_icons
(T
$ui_index) file_statechange
1883 set all_icons
(_
$ui_workdir) file_plain
1884 set all_icons
(M
$ui_workdir) file_mod
1885 set all_icons
(D
$ui_workdir) file_question
1886 set all_icons
(U
$ui_workdir) file_merge
1887 set all_icons
(O
$ui_workdir) file_plain
1888 set all_icons
(T
$ui_workdir) file_statechange
1890 set max_status_desc
0
1892 {__
{mc
"Unmodified"}}
1894 {_M
{mc
"Modified, not staged"}}
1895 {M_
{mc
"Staged for commit"}}
1896 {MM
{mc
"Portions staged for commit"}}
1897 {MD
{mc
"Staged for commit, missing"}}
1899 {_T
{mc
"File type changed, not staged"}}
1900 {T_
{mc
"File type changed, staged"}}
1902 {_O
{mc
"Untracked, not staged"}}
1903 {A_
{mc
"Staged for commit"}}
1904 {AM
{mc
"Portions staged for commit"}}
1905 {AD
{mc
"Staged for commit, missing"}}
1908 {D_
{mc
"Staged for removal"}}
1909 {DO
{mc
"Staged for removal, still present"}}
1911 {_U
{mc
"Requires merge resolution"}}
1912 {U_
{mc
"Requires merge resolution"}}
1913 {UU
{mc
"Requires merge resolution"}}
1914 {UM
{mc
"Requires merge resolution"}}
1915 {UD
{mc
"Requires merge resolution"}}
1916 {UT
{mc
"Requires merge resolution"}}
1918 set text
[eval [lindex
$i 1]]
1919 if {$max_status_desc < [string length
$text]} {
1920 set max_status_desc
[string length
$text]
1922 set all_descs
([lindex
$i 0]) $text
1926 ######################################################################
1930 proc scrollbar2many
{list mode args
} {
1931 foreach w
$list {eval $w $mode $args}
1934 proc many2scrollbar
{list mode sb top bottom
} {
1935 $sb set $top $bottom
1936 foreach w
$list {$w $mode moveto
$top}
1939 proc incr_font_size
{font
{amt
1}} {
1940 set sz
[font configure
$font -size]
1942 font configure
$font -size $sz
1943 font configure
${font}bold
-size $sz
1944 font configure
${font}italic
-size $sz
1947 ######################################################################
1951 set starting_gitk_msg
[mc
"Starting gitk... please wait..."]
1953 proc do_gitk
{revs
{is_submodule false
}} {
1954 global current_diff_path file_states current_diff_side ui_index
1957 # -- Always start gitk through whatever we were loaded with. This
1958 # lets us bypass using shell process on Windows systems.
1960 set exe
[_which gitk
-script]
1961 set cmd
[list
[info nameofexecutable
] $exe]
1963 error_popup
[mc
"Couldn't find gitk in PATH"]
1967 if {[info exists env
(GIT_DIR
)]} {
1968 set old_GIT_DIR
$env(GIT_DIR
)
1975 if {!$is_submodule} {
1976 if {$_gitworktree ne
{}} {
1979 set env
(GIT_DIR
) [file normalize
[gitdir
]]
1981 cd $current_diff_path
1982 if {$revs eq
{--}} {
1983 set s
$file_states($current_diff_path)
1986 switch
-glob -- [lindex
$s 0] {
1987 M_
{ set old_sha1
[lindex
[lindex
$s 2] 1] }
1988 _M
{ set old_sha1
[lindex
[lindex
$s 3] 1] }
1990 if {$current_diff_side eq
$ui_index} {
1991 set old_sha1
[lindex
[lindex
$s 2] 1]
1992 set new_sha1
[lindex
[lindex
$s 3] 1]
1994 set old_sha1
[lindex
[lindex
$s 3] 1]
1998 set revs
$old_sha1...
$new_sha1
2000 if {[info exists env
(GIT_DIR
)]} {
2004 eval exec $cmd $revs "--" "--" &
2006 if {$old_GIT_DIR ne
{}} {
2007 set env
(GIT_DIR
) $old_GIT_DIR
2011 ui_status $
::starting_gitk_msg
2013 ui_ready
$starting_gitk_msg
2018 proc do_git_gui
{} {
2019 global current_diff_path
2021 # -- Always start git gui through whatever we were loaded with. This
2022 # lets us bypass using shell process on Windows systems.
2024 set exe
[_which git
]
2026 error_popup
[mc
"Couldn't find git gui in PATH"]
2030 if {[info exists env
(GIT_DIR
)]} {
2031 set old_GIT_DIR
$env(GIT_DIR
)
2038 cd $current_diff_path
2040 eval exec $exe gui
&
2042 if {$old_GIT_DIR ne
{}} {
2043 set env
(GIT_DIR
) $old_GIT_DIR
2047 ui_status $
::starting_gitk_msg
2049 ui_ready
$starting_gitk_msg
2054 proc do_explore
{} {
2057 if {[is_Cygwin
] ||
[is_Windows
]} {
2058 set explorer
"explorer.exe"
2059 } elseif
{[is_MacOSX
]} {
2062 # freedesktop.org-conforming system is our best shot
2063 set explorer
"xdg-open"
2065 eval exec $explorer $_gitworktree &
2071 proc terminate_me
{win
} {
2073 if {$win ne
{.
}} return
2077 proc do_quit
{{rc
{1}}} {
2078 global ui_comm is_quitting repo_config commit_type
2079 global GITGUI_BCK_exists GITGUI_BCK_i
2080 global ui_comm_spell
2083 if {$is_quitting} return
2086 if {[winfo exists
$ui_comm]} {
2087 # -- Stash our current commit buffer.
2089 set save
[gitdir GITGUI_MSG
]
2090 if {$GITGUI_BCK_exists && ![$ui_comm edit modified
]} {
2091 file rename
-force [gitdir GITGUI_BCK
] $save
2092 set GITGUI_BCK_exists
0
2094 set msg
[string trim
[$ui_comm get
0.0 end
]]
2095 regsub
-all -line {[ \r\t]+$
} $msg {} msg
2096 if {(![string match amend
* $commit_type]
2097 ||
[$ui_comm edit modified
])
2100 set fd
[open
$save w
]
2101 puts
-nonewline $fd $msg
2105 catch
{file delete
$save}
2109 # -- Cancel our spellchecker if its running.
2111 if {[info exists ui_comm_spell
]} {
2115 # -- Remove our editor backup, its not needed.
2117 after cancel
$GITGUI_BCK_i
2118 if {$GITGUI_BCK_exists} {
2119 catch
{file delete
[gitdir GITGUI_BCK
]}
2122 # -- Stash our current window geometry into this repository.
2124 set cfg_wmstate
[wm state .
]
2125 if {[catch
{set rc_wmstate
$repo_config(gui.wmstate
)}]} {
2128 if {$cfg_wmstate ne
$rc_wmstate} {
2129 catch
{git config gui.wmstate
$cfg_wmstate}
2131 if {$cfg_wmstate eq
{zoomed
}} {
2132 # on Windows wm geometry will lie about window
2133 # position (but not size) when window is zoomed
2134 # restore the window before querying wm geometry
2137 set cfg_geometry
[list
]
2138 lappend cfg_geometry
[wm geometry .
]
2139 lappend cfg_geometry
[lindex
[.vpane sash coord
0] 0]
2140 lappend cfg_geometry
[lindex
[.vpane.files sash coord
0] 1]
2141 if {[catch
{set rc_geometry
$repo_config(gui.geometry
)}]} {
2144 if {$cfg_geometry ne
$rc_geometry} {
2145 catch
{git config gui.geometry
$cfg_geometry}
2151 # Briefly enable send again, working around Tk bug
2152 # http://sourceforge.net/tracker/?func=detail&atid=112997&aid=1821174&group_id=12997
2153 tk appname
[appname
]
2162 proc ui_do_rescan
{} {
2163 rescan
{force_first_diff ui_ready
}
2170 proc next_diff
{{after
{}}} {
2171 global next_diff_p next_diff_w next_diff_i
2172 show_diff
$next_diff_p $next_diff_w {} {} $after
2175 proc find_anchor_pos
{lst name
} {
2176 set lid
[lsearch
-sorted -exact $lst $name]
2180 foreach lname
$lst {
2181 if {$lname >= $name} break
2189 proc find_file_from
{flist idx delta path mmask
} {
2192 set len
[llength
$flist]
2193 while {$idx >= 0 && $idx < $len} {
2194 set name
[lindex
$flist $idx]
2196 if {$name ne
$path && [info exists file_states
($name)]} {
2197 set state
[lindex
$file_states($name) 0]
2199 if {$mmask eq
{} ||
[regexp
$mmask $state]} {
2210 proc find_next_diff
{w path
{lno
{}} {mmask
{}}} {
2211 global next_diff_p next_diff_w next_diff_i
2212 global file_lists ui_index ui_workdir
2214 set flist
$file_lists($w)
2216 set lno
[find_anchor_pos
$flist $path]
2221 if {$mmask ne
{} && ![regexp
{(^\^
)|
(\$$
)} $mmask]} {
2222 if {$w eq
$ui_index} {
2225 set mmask
"$mmask\$"
2229 set idx
[find_file_from
$flist $lno 1 $path $mmask]
2232 set idx
[find_file_from
$flist $lno -1 $path $mmask]
2237 set next_diff_p
[lindex
$flist $idx]
2238 set next_diff_i
[expr {$idx+1}]
2245 proc next_diff_after_action
{w path
{lno
{}} {mmask
{}}} {
2246 global current_diff_path
2248 if {$path ne
$current_diff_path} {
2250 } elseif
{[find_next_diff
$w $path $lno $mmask]} {
2253 return {reshow_diff
;}
2257 proc select_first_diff
{after
} {
2260 if {[find_next_diff
$ui_workdir {} 1 {^_?U
}] ||
2261 [find_next_diff
$ui_workdir {} 1 {[^O
]$
}]} {
2268 proc force_first_diff
{after
} {
2269 global ui_workdir current_diff_path file_states
2271 if {[info exists file_states
($current_diff_path)]} {
2272 set state
[lindex
$file_states($current_diff_path) 0]
2278 if {[string first
{U
} $state] >= 0} {
2279 # Already a conflict, do nothing
2280 } elseif
{[find_next_diff
$ui_workdir $current_diff_path {} {^_?U
}]} {
2282 } elseif
{[string index
$state 1] ne
{O
}} {
2283 # Already a diff & no conflicts, do nothing
2284 } elseif
{[find_next_diff
$ui_workdir $current_diff_path {} {[^O
]$
}]} {
2295 proc toggle_or_diff
{w x y
} {
2296 global file_states file_lists current_diff_path ui_index ui_workdir
2297 global last_clicked selected_paths
2299 set pos
[split [$w index @
$x,$y] .
]
2300 set lno
[lindex
$pos 0]
2301 set col [lindex
$pos 1]
2302 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
2308 set last_clicked
[list
$w $lno]
2309 array
unset selected_paths
2310 $ui_index tag remove in_sel
0.0 end
2311 $ui_workdir tag remove in_sel
0.0 end
2313 # Determine the state of the file
2314 if {[info exists file_states
($path)]} {
2315 set state
[lindex
$file_states($path) 0]
2320 # Restage the file, or simply show the diff
2321 if {$col == 0 && $y > 1} {
2322 # Conflicts need special handling
2323 if {[string first
{U
} $state] >= 0} {
2324 # $w must always be $ui_workdir, but...
2325 if {$w ne
$ui_workdir} { set lno
{} }
2326 merge_stage_workdir
$path $lno
2330 if {[string index
$state 1] eq
{O
}} {
2336 set after
[next_diff_after_action
$w $path $lno $mmask]
2338 if {$w eq
$ui_index} {
2340 "Unstaging [short_path $path] from commit" \
2342 [concat
$after [list ui_ready
]]
2343 } elseif
{$w eq
$ui_workdir} {
2345 "Adding [short_path $path]" \
2347 [concat
$after [list ui_ready
]]
2350 show_diff
$path $w $lno
2354 proc add_one_to_selection
{w x y
} {
2355 global file_lists last_clicked selected_paths
2357 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
2358 set path
[lindex
$file_lists($w) [expr {$lno - 1}]]
2364 if {$last_clicked ne
{}
2365 && [lindex
$last_clicked 0] ne
$w} {
2366 array
unset selected_paths
2367 [lindex
$last_clicked 0] tag remove in_sel
0.0 end
2370 set last_clicked
[list
$w $lno]
2371 if {[catch
{set in_sel
$selected_paths($path)}]} {
2375 unset selected_paths
($path)
2376 $w tag remove in_sel
$lno.0 [expr {$lno + 1}].0
2378 set selected_paths
($path) 1
2379 $w tag add in_sel
$lno.0 [expr {$lno + 1}].0
2383 proc add_range_to_selection
{w x y
} {
2384 global file_lists last_clicked selected_paths
2386 if {[lindex
$last_clicked 0] ne
$w} {
2387 toggle_or_diff
$w $x $y
2391 set lno
[lindex
[split [$w index @
$x,$y] .
] 0]
2392 set lc
[lindex
$last_clicked 1]
2401 foreach path
[lrange
$file_lists($w) \
2402 [expr {$begin - 1}] \
2403 [expr {$end - 1}]] {
2404 set selected_paths
($path) 1
2406 $w tag add in_sel
$begin.0 [expr {$end + 1}].0
2409 proc show_more_context
{} {
2411 if {$repo_config(gui.diffcontext
) < 99} {
2412 incr repo_config
(gui.diffcontext
)
2417 proc show_less_context
{} {
2419 if {$repo_config(gui.diffcontext
) > 1} {
2420 incr repo_config
(gui.diffcontext
) -1
2425 ######################################################################
2433 menu .mbar
-tearoff 0
2435 # -- Apple Menu (Mac OS X only)
2437 .mbar add cascade
-label Apple
-menu .mbar.apple
2440 .mbar add cascade
-label [mc Repository
] -menu .mbar.repository
2441 .mbar add cascade
-label [mc Edit
] -menu .mbar.edit
2442 if {[is_enabled branch
]} {
2443 .mbar add cascade
-label [mc Branch
] -menu .mbar.branch
2445 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
2446 .mbar add cascade
-label [mc Commit@@noun
] -menu .mbar.commit
2448 if {[is_enabled transport
]} {
2449 .mbar add cascade
-label [mc Merge
] -menu .mbar.merge
2450 .mbar add cascade
-label [mc Remote
] -menu .mbar.remote
2452 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
2453 .mbar add cascade
-label [mc Tools
] -menu .mbar.tools
2456 # -- Repository Menu
2458 menu .mbar.repository
2460 .mbar.repository add
command \
2461 -label [mc
"Explore Working Copy"] \
2462 -command {do_explore
}
2463 .mbar.repository add separator
2465 .mbar.repository add
command \
2466 -label [mc
"Browse Current Branch's Files"] \
2467 -command {browser
::new
$current_branch}
2468 set ui_browse_current
[.mbar.repository index last
]
2469 .mbar.repository add
command \
2470 -label [mc
"Browse Branch Files..."] \
2471 -command browser_open
::dialog
2472 .mbar.repository add separator
2474 .mbar.repository add
command \
2475 -label [mc
"Visualize Current Branch's History"] \
2476 -command {do_gitk
$current_branch}
2477 set ui_visualize_current
[.mbar.repository index last
]
2478 .mbar.repository add
command \
2479 -label [mc
"Visualize All Branch History"] \
2480 -command {do_gitk
--all}
2481 .mbar.repository add separator
2483 proc current_branch_write
{args
} {
2484 global current_branch
2485 .mbar.repository entryconf $
::ui_browse_current \
2486 -label [mc
"Browse %s's Files" $current_branch]
2487 .mbar.repository entryconf $
::ui_visualize_current \
2488 -label [mc
"Visualize %s's History" $current_branch]
2490 trace add variable current_branch
write current_branch_write
2492 if {[is_enabled multicommit
]} {
2493 .mbar.repository add
command -label [mc
"Database Statistics"] \
2496 .mbar.repository add
command -label [mc
"Compress Database"] \
2499 .mbar.repository add
command -label [mc
"Verify Database"] \
2500 -command do_fsck_objects
2502 .mbar.repository add separator
2505 .mbar.repository add
command \
2506 -label [mc
"Create Desktop Icon"] \
2507 -command do_cygwin_shortcut
2508 } elseif
{[is_Windows
]} {
2509 .mbar.repository add
command \
2510 -label [mc
"Create Desktop Icon"] \
2511 -command do_windows_shortcut
2512 } elseif
{[is_MacOSX
]} {
2513 .mbar.repository add
command \
2514 -label [mc
"Create Desktop Icon"] \
2515 -command do_macosx_app
2520 proc
::tk
::mac
::Quit
{args
} { do_quit
}
2522 .mbar.repository add
command -label [mc Quit
] \
2530 .mbar.edit add
command -label [mc Undo
] \
2531 -command {catch
{[focus
] edit undo
}} \
2533 .mbar.edit add
command -label [mc Redo
] \
2534 -command {catch
{[focus
] edit redo
}} \
2536 .mbar.edit add separator
2537 .mbar.edit add
command -label [mc Cut
] \
2538 -command {catch
{tk_textCut
[focus
]}} \
2540 .mbar.edit add
command -label [mc Copy
] \
2541 -command {catch
{tk_textCopy
[focus
]}} \
2543 .mbar.edit add
command -label [mc Paste
] \
2544 -command {catch
{tk_textPaste
[focus
]; [focus
] see insert
}} \
2546 .mbar.edit add
command -label [mc Delete
] \
2547 -command {catch
{[focus
] delete sel.first sel.last
}} \
2549 .mbar.edit add separator
2550 .mbar.edit add
command -label [mc
"Select All"] \
2551 -command {catch
{[focus
] tag add sel
0.0 end
}} \
2556 if {[is_enabled branch
]} {
2559 .mbar.branch add
command -label [mc
"Create..."] \
2560 -command branch_create
::dialog \
2562 lappend disable_on_lock
[list .mbar.branch entryconf \
2563 [.mbar.branch index last
] -state]
2565 .mbar.branch add
command -label [mc
"Checkout..."] \
2566 -command branch_checkout
::dialog \
2568 lappend disable_on_lock
[list .mbar.branch entryconf \
2569 [.mbar.branch index last
] -state]
2571 .mbar.branch add
command -label [mc
"Rename..."] \
2572 -command branch_rename
::dialog
2573 lappend disable_on_lock
[list .mbar.branch entryconf \
2574 [.mbar.branch index last
] -state]
2576 .mbar.branch add
command -label [mc
"Delete..."] \
2577 -command branch_delete
::dialog
2578 lappend disable_on_lock
[list .mbar.branch entryconf \
2579 [.mbar.branch index last
] -state]
2581 .mbar.branch add
command -label [mc
"Reset..."] \
2582 -command merge
::reset_hard
2583 lappend disable_on_lock
[list .mbar.branch entryconf \
2584 [.mbar.branch index last
] -state]
2589 proc commit_btn_caption
{} {
2590 if {[is_enabled nocommit
]} {
2593 return [mc Commit@@verb
]
2597 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
2600 if {![is_enabled nocommit
]} {
2601 .mbar.commit add radiobutton \
2602 -label [mc
"New Commit"] \
2603 -command do_select_commit_type \
2604 -variable selected_commit_type \
2606 lappend disable_on_lock \
2607 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2609 .mbar.commit add radiobutton \
2610 -label [mc
"Amend Last Commit"] \
2611 -command do_select_commit_type \
2612 -variable selected_commit_type \
2614 lappend disable_on_lock \
2615 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2617 .mbar.commit add separator
2620 .mbar.commit add
command -label [mc Rescan
] \
2621 -command ui_do_rescan \
2623 lappend disable_on_lock \
2624 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2626 .mbar.commit add
command -label [mc
"Stage To Commit"] \
2627 -command do_add_selection \
2629 lappend disable_on_lock \
2630 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2632 .mbar.commit add
command -label [mc
"Stage Changed Files To Commit"] \
2633 -command do_add_all \
2635 lappend disable_on_lock \
2636 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2638 .mbar.commit add
command -label [mc
"Unstage From Commit"] \
2639 -command do_unstage_selection \
2641 lappend disable_on_lock \
2642 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2644 .mbar.commit add
command -label [mc
"Revert Changes"] \
2645 -command do_revert_selection \
2647 lappend disable_on_lock \
2648 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2650 .mbar.commit add separator
2652 .mbar.commit add
command -label [mc
"Show Less Context"] \
2653 -command show_less_context \
2654 -accelerator $M1T-\
-
2656 .mbar.commit add
command -label [mc
"Show More Context"] \
2657 -command show_more_context \
2660 .mbar.commit add separator
2662 if {![is_enabled nocommitmsg
]} {
2663 .mbar.commit add
command -label [mc
"Sign Off"] \
2664 -command do_signoff \
2668 .mbar.commit add
command -label [commit_btn_caption
] \
2669 -command do_commit \
2670 -accelerator $M1T-Return
2671 lappend disable_on_lock \
2672 [list .mbar.commit entryconf
[.mbar.commit index last
] -state]
2677 if {[is_enabled branch
]} {
2679 .mbar.merge add
command -label [mc
"Local Merge..."] \
2680 -command merge
::dialog \
2682 lappend disable_on_lock \
2683 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
2684 .mbar.merge add
command -label [mc
"Abort Merge..."] \
2685 -command merge
::reset_hard
2686 lappend disable_on_lock \
2687 [list .mbar.merge entryconf
[.mbar.merge index last
] -state]
2692 if {[is_enabled transport
]} {
2695 .mbar.remote add
command \
2696 -label [mc
"Add..."] \
2697 -command remote_add
::dialog \
2699 .mbar.remote add
command \
2700 -label [mc
"Push..."] \
2701 -command do_push_anywhere \
2703 .mbar.remote add
command \
2704 -label [mc
"Delete Branch..."] \
2705 -command remote_branch_delete
::dialog
2709 proc
::tk
::mac
::ShowPreferences
{} {do_options
}
2713 .mbar.edit add separator
2714 .mbar.edit add
command -label [mc
"Options..."] \
2720 if {[is_enabled multicommit
] ||
[is_enabled singlecommit
]} {
2721 set tools_menubar .mbar.tools
2723 $tools_menubar add separator
2724 $tools_menubar add
command -label [mc
"Add..."] -command tools_add
::dialog
2725 $tools_menubar add
command -label [mc
"Remove..."] -command tools_remove
::dialog
2727 if {[array names repo_config guitool.
*.cmd
] ne
{}} {
2734 .mbar add cascade
-label [mc Help
] -menu .mbar.
help
2738 .mbar.apple add
command -label [mc
"About %s" [appname
]] \
2740 .mbar.apple add separator
2742 .mbar.
help add
command -label [mc
"About %s" [appname
]] \
2745 . configure
-menu .mbar
2747 set doc_path
[githtmldir
]
2748 if {$doc_path ne
{}} {
2749 set doc_path
[file join $doc_path index.html
]
2752 set doc_path
[exec cygpath
--mixed $doc_path]
2756 if {[file isfile
$doc_path]} {
2757 set doc_url
"file:$doc_path"
2759 set doc_url
{http
://www.kernel.org
/pub
/software
/scm
/git
/docs
/}
2762 proc start_browser
{url
} {
2763 git
"web--browse" $url
2766 .mbar.
help add
command -label [mc
"Online Documentation"] \
2767 -command [list start_browser
$doc_url]
2769 .mbar.
help add
command -label [mc
"Show SSH Key"] \
2772 unset doc_path doc_url
2774 # -- Standard bindings
2776 wm protocol . WM_DELETE_WINDOW do_quit
2777 bind all
<$M1B-Key-q> do_quit
2778 bind all
<$M1B-Key-Q> do_quit
2779 bind all
<$M1B-Key-w> {destroy
[winfo toplevel
%W
]}
2780 bind all
<$M1B-Key-W> {destroy
[winfo toplevel
%W
]}
2782 set subcommand_args
{}
2784 puts stderr
"usage: $::argv0 $::subcommand $::subcommand_args"
2788 proc normalize_relpath
{path
} {
2790 foreach item
[file split $path] {
2791 if {$item eq
{.
}} continue
2792 if {$item eq
{..
} && [llength
$elements] > 0
2793 && [lindex
$elements end
] ne
{..
}} {
2794 set elements
[lrange
$elements 0 end-1
]
2797 lappend elements
$item
2799 return [eval file join $elements]
2802 # -- Not a normal commit type invocation? Do that instead!
2804 switch
-- $subcommand {
2807 if {$subcommand eq
"blame"} {
2808 set subcommand_args
{[--line=<num
>] rev? path
}
2810 set subcommand_args
{rev? path
}
2812 if {$argv eq
{}} usage
2818 if {$is_path ||
[file exists
$_prefix$a]} {
2819 if {$path ne
{}} usage
2820 set path
[normalize_relpath
$_prefix$a]
2822 } elseif
{$a eq
{--}} {
2824 if {$head ne
{}} usage
2829 } elseif
{[regexp
{^
--line=(\d
+)$
} $a a lnum
]} {
2830 if {$jump_spec ne
{} ||
$head ne
{}} usage
2831 set jump_spec
[list
$lnum]
2832 } elseif
{$head eq
{}} {
2833 if {$head ne
{}} usage
2842 if {$head ne
{} && $path eq
{}} {
2843 set path
[normalize_relpath
$_prefix$head]
2850 if {[regexp
{^
[0-9a-f]{1,39}$
} $head]} {
2852 set head [git rev-parse
--verify $head]
2858 set current_branch
$head
2861 switch
-- $subcommand {
2863 if {$jump_spec ne
{}} usage
2865 if {$path ne
{} && [file isdirectory
$path]} {
2866 set head $current_branch
2872 browser
::new
$head $path
2875 if {$head eq
{} && ![file exists
$path]} {
2876 puts stderr
[mc
"fatal: cannot stat path %s: No such file or directory" $path]
2879 blame
::new
$head $path $jump_spec
2886 if {[llength
$argv] != 0} {
2887 puts
-nonewline stderr
"usage: $argv0"
2888 if {$subcommand ne
{gui
}
2889 && [file tail $argv0] ne
"git-$subcommand"} {
2890 puts
-nonewline stderr
" $subcommand"
2895 # fall through to setup UI for commits
2898 puts stderr
"usage: $argv0 \[{blame|browser|citool}\]"
2909 -text [mc
"Current Branch:"] \
2913 -textvariable current_branch \
2916 pack .branch.l1
-side left
2917 pack .branch.cb
-side left
-fill x
2918 pack .branch
-side top
-fill x
2920 # -- Main Window Layout
2922 panedwindow .vpane
-orient horizontal
2923 panedwindow .vpane.files
-orient vertical
2924 .vpane add .vpane.files
-sticky nsew
-height 100 -width 200
2925 pack .vpane
-anchor n
-side top
-fill both
-expand 1
2927 # -- Index File List
2929 frame .vpane.files.index
-height 100 -width 200
2930 label .vpane.files.index.title
-text [mc
"Staged Changes (Will Commit)"] \
2931 -background lightgreen
-foreground black
2932 text
$ui_index -background white
-foreground black \
2934 -width 20 -height 10 \
2936 -cursor $cursor_ptr \
2937 -xscrollcommand {.vpane.files.index.sx
set} \
2938 -yscrollcommand {.vpane.files.index.sy
set} \
2940 scrollbar .vpane.files.index.sx
-orient h
-command [list
$ui_index xview
]
2941 scrollbar .vpane.files.index.sy
-orient v
-command [list
$ui_index yview
]
2942 pack .vpane.files.index.title
-side top
-fill x
2943 pack .vpane.files.index.sx
-side bottom
-fill x
2944 pack .vpane.files.index.sy
-side right
-fill y
2945 pack
$ui_index -side left
-fill both
-expand 1
2947 # -- Working Directory File List
2949 frame .vpane.files.workdir
-height 100 -width 200
2950 label .vpane.files.workdir.title
-text [mc
"Unstaged Changes"] \
2951 -background lightsalmon
-foreground black
2952 text
$ui_workdir -background white
-foreground black \
2954 -width 20 -height 10 \
2956 -cursor $cursor_ptr \
2957 -xscrollcommand {.vpane.files.workdir.sx
set} \
2958 -yscrollcommand {.vpane.files.workdir.sy
set} \
2960 scrollbar .vpane.files.workdir.sx
-orient h
-command [list
$ui_workdir xview
]
2961 scrollbar .vpane.files.workdir.sy
-orient v
-command [list
$ui_workdir yview
]
2962 pack .vpane.files.workdir.title
-side top
-fill x
2963 pack .vpane.files.workdir.sx
-side bottom
-fill x
2964 pack .vpane.files.workdir.sy
-side right
-fill y
2965 pack
$ui_workdir -side left
-fill both
-expand 1
2967 .vpane.files add .vpane.files.workdir
-sticky nsew
2968 .vpane.files add .vpane.files.index
-sticky nsew
2970 foreach i
[list
$ui_index $ui_workdir] {
2972 $i tag conf in_diff
-background [$i tag cget in_sel
-background]
2976 # -- Diff and Commit Area
2978 frame .vpane.lower
-height 300 -width 400
2979 frame .vpane.lower.commarea
2980 frame .vpane.lower.
diff -relief sunken
-borderwidth 1
2981 pack .vpane.lower.
diff -fill both
-expand 1
2982 pack .vpane.lower.commarea
-side bottom
-fill x
2983 .vpane add .vpane.lower
-sticky nsew
2985 # -- Commit Area Buttons
2987 frame .vpane.lower.commarea.buttons
2988 label .vpane.lower.commarea.buttons.l
-text {} \
2991 pack .vpane.lower.commarea.buttons.l
-side top
-fill x
2992 pack .vpane.lower.commarea.buttons
-side left
-fill y
2994 button .vpane.lower.commarea.buttons.rescan
-text [mc Rescan
] \
2995 -command ui_do_rescan
2996 pack .vpane.lower.commarea.buttons.rescan
-side top
-fill x
2997 lappend disable_on_lock \
2998 {.vpane.lower.commarea.buttons.rescan conf
-state}
3000 button .vpane.lower.commarea.buttons.incall
-text [mc
"Stage Changed"] \
3002 pack .vpane.lower.commarea.buttons.incall
-side top
-fill x
3003 lappend disable_on_lock \
3004 {.vpane.lower.commarea.buttons.incall conf
-state}
3006 if {![is_enabled nocommitmsg
]} {
3007 button .vpane.lower.commarea.buttons.signoff
-text [mc
"Sign Off"] \
3009 pack .vpane.lower.commarea.buttons.signoff
-side top
-fill x
3012 button .vpane.lower.commarea.buttons.commit
-text [commit_btn_caption
] \
3014 pack .vpane.lower.commarea.buttons.commit
-side top
-fill x
3015 lappend disable_on_lock \
3016 {.vpane.lower.commarea.buttons.commit conf
-state}
3018 if {![is_enabled nocommit
]} {
3019 button .vpane.lower.commarea.buttons.push
-text [mc Push
] \
3020 -command do_push_anywhere
3021 pack .vpane.lower.commarea.buttons.push
-side top
-fill x
3024 # -- Commit Message Buffer
3026 frame .vpane.lower.commarea.buffer
3027 frame .vpane.lower.commarea.buffer.header
3028 set ui_comm .vpane.lower.commarea.buffer.t
3029 set ui_coml .vpane.lower.commarea.buffer.header.l
3031 if {![is_enabled nocommit
]} {
3032 radiobutton .vpane.lower.commarea.buffer.header.new \
3033 -text [mc
"New Commit"] \
3034 -command do_select_commit_type \
3035 -variable selected_commit_type \
3037 lappend disable_on_lock \
3038 [list .vpane.lower.commarea.buffer.header.new conf
-state]
3039 radiobutton .vpane.lower.commarea.buffer.header.amend \
3040 -text [mc
"Amend Last Commit"] \
3041 -command do_select_commit_type \
3042 -variable selected_commit_type \
3044 lappend disable_on_lock \
3045 [list .vpane.lower.commarea.buffer.header.amend conf
-state]
3051 proc trace_commit_type
{varname args
} {
3052 global ui_coml commit_type
3053 switch
-glob -- $commit_type {
3054 initial
{set txt
[mc
"Initial Commit Message:"]}
3055 amend
{set txt
[mc
"Amended Commit Message:"]}
3056 amend-initial
{set txt
[mc
"Amended Initial Commit Message:"]}
3057 amend-merge
{set txt
[mc
"Amended Merge Commit Message:"]}
3058 merge
{set txt
[mc
"Merge Commit Message:"]}
3059 * {set txt
[mc
"Commit Message:"]}
3061 $ui_coml conf
-text $txt
3063 trace add variable commit_type
write trace_commit_type
3064 pack
$ui_coml -side left
-fill x
3066 if {![is_enabled nocommit
]} {
3067 pack .vpane.lower.commarea.buffer.header.amend
-side right
3068 pack .vpane.lower.commarea.buffer.header.new
-side right
3071 text
$ui_comm -background white
-foreground black \
3075 -autoseparators true \
3077 -width $repo_config(gui.commitmsgwidth
) -height 9 -wrap none \
3079 -yscrollcommand {.vpane.lower.commarea.buffer.sby
set}
3080 scrollbar .vpane.lower.commarea.buffer.sby \
3081 -command [list
$ui_comm yview
]
3082 pack .vpane.lower.commarea.buffer.header
-side top
-fill x
3083 pack .vpane.lower.commarea.buffer.sby
-side right
-fill y
3084 pack
$ui_comm -side left
-fill y
3085 pack .vpane.lower.commarea.buffer
-side left
-fill y
3087 # -- Commit Message Buffer Context Menu
3089 set ctxm .vpane.lower.commarea.buffer.ctxm
3090 menu
$ctxm -tearoff 0
3093 -command {tk_textCut
$ui_comm}
3096 -command {tk_textCopy
$ui_comm}
3099 -command {tk_textPaste
$ui_comm}
3101 -label [mc Delete
] \
3102 -command {catch
{$ui_comm delete sel.first sel.last
}}
3105 -label [mc
"Select All"] \
3106 -command {focus
$ui_comm;$ui_comm tag add sel
0.0 end
}
3108 -label [mc
"Copy All"] \
3110 $ui_comm tag add sel
0.0 end
3111 tk_textCopy
$ui_comm
3112 $ui_comm tag remove sel
0.0 end
3116 -label [mc
"Sign Off"] \
3118 set ui_comm_ctxm
$ctxm
3122 proc trace_current_diff_path
{varname args
} {
3123 global current_diff_path diff_actions file_states
3124 if {$current_diff_path eq
{}} {
3130 set p
$current_diff_path
3131 set s
[mapdesc
[lindex
$file_states($p) 0] $p]
3133 set p
[escape_path
$p]
3137 .vpane.lower.
diff.header.status configure
-text $s
3138 .vpane.lower.
diff.header.
file configure
-text $f
3139 .vpane.lower.
diff.header.path configure
-text $p
3140 foreach w
$diff_actions {
3144 trace add variable current_diff_path
write trace_current_diff_path
3146 frame .vpane.lower.
diff.header
-background gold
3147 label .vpane.lower.
diff.header.status \
3150 -width $max_status_desc \
3153 label .vpane.lower.
diff.header.
file \
3158 label .vpane.lower.
diff.header.path \
3163 pack .vpane.lower.
diff.header.status
-side left
3164 pack .vpane.lower.
diff.header.
file -side left
3165 pack .vpane.lower.
diff.header.path
-fill x
3166 set ctxm .vpane.lower.
diff.header.ctxm
3167 menu
$ctxm -tearoff 0
3175 -- $current_diff_path
3177 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3178 bind_button3 .vpane.lower.
diff.header.path
"tk_popup $ctxm %X %Y"
3182 frame .vpane.lower.
diff.body
3183 set ui_diff .vpane.lower.
diff.body.t
3184 text
$ui_diff -background white
-foreground black \
3186 -width 80 -height 5 -wrap none \
3188 -xscrollcommand {.vpane.lower.
diff.body.sbx
set} \
3189 -yscrollcommand {.vpane.lower.
diff.body.sby
set} \
3191 scrollbar .vpane.lower.
diff.body.sbx
-orient horizontal \
3192 -command [list
$ui_diff xview
]
3193 scrollbar .vpane.lower.
diff.body.sby
-orient vertical \
3194 -command [list
$ui_diff yview
]
3195 pack .vpane.lower.
diff.body.sbx
-side bottom
-fill x
3196 pack .vpane.lower.
diff.body.sby
-side right
-fill y
3197 pack
$ui_diff -side left
-fill both
-expand 1
3198 pack .vpane.lower.
diff.header
-side top
-fill x
3199 pack .vpane.lower.
diff.body
-side bottom
-fill both
-expand 1
3201 $ui_diff tag conf d_cr
-elide true
3202 $ui_diff tag conf d_@
-foreground blue
-font font_diffbold
3203 $ui_diff tag conf d_
+ -foreground {#00a000}
3204 $ui_diff tag conf d_-
-foreground red
3206 $ui_diff tag conf d_
++ -foreground {#00a000}
3207 $ui_diff tag conf d_--
-foreground red
3208 $ui_diff tag conf d_
+s \
3209 -foreground {#00a000} \
3210 -background {#e2effa}
3211 $ui_diff tag conf d_-s \
3213 -background {#e2effa}
3214 $ui_diff tag conf d_s
+ \
3215 -foreground {#00a000} \
3217 $ui_diff tag conf d_s- \
3221 $ui_diff tag conf d
<<<<<<< \
3222 -foreground orange \
3224 $ui_diff tag conf d
======= \
3225 -foreground orange \
3227 $ui_diff tag conf d
>>>>>>> \
3228 -foreground orange \
3231 $ui_diff tag raise sel
3233 # -- Diff Body Context Menu
3236 proc create_common_diff_popup
{ctxm
} {
3238 -label [mc Refresh
] \
3239 -command reshow_diff
3240 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3243 -command {tk_textCopy
$ui_diff}
3244 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3246 -label [mc
"Select All"] \
3247 -command {focus
$ui_diff;$ui_diff tag add sel
0.0 end
}
3248 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3250 -label [mc
"Copy All"] \
3252 $ui_diff tag add sel
0.0 end
3253 tk_textCopy
$ui_diff
3254 $ui_diff tag remove sel
0.0 end
3256 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3259 -label [mc
"Decrease Font Size"] \
3260 -command {incr_font_size font_diff
-1}
3261 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3263 -label [mc
"Increase Font Size"] \
3264 -command {incr_font_size font_diff
1}
3265 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3269 build_encoding_menu
$emenu [list force_diff_encoding
]
3271 -label [mc
"Encoding"] \
3273 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3275 $ctxm add
command -label [mc
"Options..."] \
3279 set ctxm .vpane.lower.
diff.body.ctxm
3280 menu
$ctxm -tearoff 0
3282 -label [mc
"Apply/Reverse Hunk"] \
3283 -command {apply_hunk
$cursorX $cursorY}
3284 set ui_diff_applyhunk
[$ctxm index last
]
3285 lappend diff_actions
[list
$ctxm entryconf
$ui_diff_applyhunk -state]
3287 -label [mc
"Apply/Reverse Line"] \
3288 -command {apply_range_or_line
$cursorX $cursorY; do_rescan
}
3289 set ui_diff_applyline
[$ctxm index last
]
3290 lappend diff_actions
[list
$ctxm entryconf
$ui_diff_applyline -state]
3293 -label [mc
"Show Less Context"] \
3294 -command show_less_context
3295 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3297 -label [mc
"Show More Context"] \
3298 -command show_more_context
3299 lappend diff_actions
[list
$ctxm entryconf
[$ctxm index last
] -state]
3301 create_common_diff_popup
$ctxm
3303 set ctxmmg .vpane.lower.
diff.body.ctxmmg
3304 menu
$ctxmmg -tearoff 0
3305 $ctxmmg add
command \
3306 -label [mc
"Run Merge Tool"] \
3307 -command {merge_resolve_tool
}
3308 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3309 $ctxmmg add separator
3310 $ctxmmg add
command \
3311 -label [mc
"Use Remote Version"] \
3312 -command {merge_resolve_one
3}
3313 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3314 $ctxmmg add
command \
3315 -label [mc
"Use Local Version"] \
3316 -command {merge_resolve_one
2}
3317 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3318 $ctxmmg add
command \
3319 -label [mc
"Revert To Base"] \
3320 -command {merge_resolve_one
1}
3321 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3322 $ctxmmg add separator
3323 $ctxmmg add
command \
3324 -label [mc
"Show Less Context"] \
3325 -command show_less_context
3326 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3327 $ctxmmg add
command \
3328 -label [mc
"Show More Context"] \
3329 -command show_more_context
3330 lappend diff_actions
[list
$ctxmmg entryconf
[$ctxmmg index last
] -state]
3331 $ctxmmg add separator
3332 create_common_diff_popup
$ctxmmg
3334 set ctxmsm .vpane.lower.
diff.body.ctxmsm
3335 menu
$ctxmsm -tearoff 0
3336 $ctxmsm add
command \
3337 -label [mc
"Visualize These Changes In The Submodule"] \
3338 -command {do_gitk
-- true
}
3339 lappend diff_actions
[list
$ctxmsm entryconf
[$ctxmsm index last
] -state]
3340 $ctxmsm add
command \
3341 -label [mc
"Visualize Current Branch History In The Submodule"] \
3342 -command {do_gitk
{} true
}
3343 lappend diff_actions
[list
$ctxmsm entryconf
[$ctxmsm index last
] -state]
3344 $ctxmsm add
command \
3345 -label [mc
"Visualize All Branch History In The Submodule"] \
3346 -command {do_gitk
--all true
}
3347 lappend diff_actions
[list
$ctxmsm entryconf
[$ctxmsm index last
] -state]
3348 $ctxmsm add separator
3349 $ctxmsm add
command \
3350 -label [mc
"Start git gui In The Submodule"] \
3351 -command {do_git_gui
}
3352 lappend diff_actions
[list
$ctxmsm entryconf
[$ctxmsm index last
] -state]
3353 $ctxmsm add separator
3354 create_common_diff_popup
$ctxmsm
3356 proc popup_diff_menu
{ctxm ctxmmg ctxmsm x y X Y
} {
3357 global current_diff_path file_states
3360 if {[info exists file_states
($current_diff_path)]} {
3361 set state
[lindex
$file_states($current_diff_path) 0]
3365 if {[string first
{U
} $state] >= 0} {
3366 tk_popup
$ctxmmg $X $Y
3367 } elseif
{$
::is_submodule_diff
} {
3368 tk_popup
$ctxmsm $X $Y
3370 set has_range
[expr {[$
::ui_diff tag nextrange sel
0.0] != {}}]
3371 if {$
::ui_index eq $
::current_diff_side
} {
3372 set l
[mc
"Unstage Hunk From Commit"]
3374 set t
[mc
"Unstage Lines From Commit"]
3376 set t
[mc
"Unstage Line From Commit"]
3379 set l
[mc
"Stage Hunk For Commit"]
3381 set t
[mc
"Stage Lines For Commit"]
3383 set t
[mc
"Stage Line For Commit"]
3387 ||
$current_diff_path eq
{}
3391 ||
{T_
} eq
$state} {
3396 $ctxm entryconf $
::ui_diff_applyhunk
-state $s -label $l
3397 $ctxm entryconf $
::ui_diff_applyline
-state $s -label $t
3398 tk_popup
$ctxm $X $Y
3401 bind_button3
$ui_diff [list popup_diff_menu
$ctxm $ctxmmg $ctxmsm %x
%y
%X
%Y
]
3405 set main_status
[::status_bar
::new .status
]
3406 pack .status
-anchor w
-side bottom
-fill x
3407 $main_status show
[mc
"Initializing..."]
3412 set gm
$repo_config(gui.geometry
)
3413 wm geometry .
[lindex
$gm 0]
3414 .vpane sash place
0 \
3416 [lindex
[.vpane sash coord
0] 1]
3417 .vpane.files sash place
0 \
3418 [lindex
[.vpane.files sash coord
0] 0] \
3423 # -- Load window state
3426 set gws
$repo_config(gui.wmstate
)
3433 bind $ui_comm <$M1B-Key-Return> {do_commit
;break}
3434 bind $ui_comm <$M1B-Key-t> {do_add_selection
;break}
3435 bind $ui_comm <$M1B-Key-T> {do_add_selection
;break}
3436 bind $ui_comm <$M1B-Key-u> {do_unstage_selection
;break}
3437 bind $ui_comm <$M1B-Key-U> {do_unstage_selection
;break}
3438 bind $ui_comm <$M1B-Key-j> {do_revert_selection
;break}
3439 bind $ui_comm <$M1B-Key-J> {do_revert_selection
;break}
3440 bind $ui_comm <$M1B-Key-i> {do_add_all
;break}
3441 bind $ui_comm <$M1B-Key-I> {do_add_all
;break}
3442 bind $ui_comm <$M1B-Key-x> {tk_textCut
%W
;break}
3443 bind $ui_comm <$M1B-Key-X> {tk_textCut
%W
;break}
3444 bind $ui_comm <$M1B-Key-c> {tk_textCopy
%W
;break}
3445 bind $ui_comm <$M1B-Key-C> {tk_textCopy
%W
;break}
3446 bind $ui_comm <$M1B-Key-v> {tk_textPaste
%W
; %W see insert
; break}
3447 bind $ui_comm <$M1B-Key-V> {tk_textPaste
%W
; %W see insert
; break}
3448 bind $ui_comm <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
3449 bind $ui_comm <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
3450 bind $ui_comm <$M1B-Key-minus> {show_less_context
;break}
3451 bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context
;break}
3452 bind $ui_comm <$M1B-Key-equal> {show_more_context
;break}
3453 bind $ui_comm <$M1B-Key-plus> {show_more_context
;break}
3454 bind $ui_comm <$M1B-Key-KP_Add> {show_more_context
;break}
3456 bind $ui_diff <$M1B-Key-x> {tk_textCopy
%W
;break}
3457 bind $ui_diff <$M1B-Key-X> {tk_textCopy
%W
;break}
3458 bind $ui_diff <$M1B-Key-c> {tk_textCopy
%W
;break}
3459 bind $ui_diff <$M1B-Key-C> {tk_textCopy
%W
;break}
3460 bind $ui_diff <$M1B-Key-v> {break}
3461 bind $ui_diff <$M1B-Key-V> {break}
3462 bind $ui_diff <$M1B-Key-a> {%W tag add sel
0.0 end
;break}
3463 bind $ui_diff <$M1B-Key-A> {%W tag add sel
0.0 end
;break}
3464 bind $ui_diff <Key-Up
> {catch
{%W yview scroll
-1 units
};break}
3465 bind $ui_diff <Key-Down
> {catch
{%W yview scroll
1 units
};break}
3466 bind $ui_diff <Key-Left
> {catch
{%W xview scroll
-1 units
};break}
3467 bind $ui_diff <Key-Right
> {catch
{%W xview scroll
1 units
};break}
3468 bind $ui_diff <Key-k
> {catch
{%W yview scroll
-1 units
};break}
3469 bind $ui_diff <Key-j
> {catch
{%W yview scroll
1 units
};break}
3470 bind $ui_diff <Key-h
> {catch
{%W xview scroll
-1 units
};break}
3471 bind $ui_diff <Key-l
> {catch
{%W xview scroll
1 units
};break}
3472 bind $ui_diff <Control-Key-b
> {catch
{%W yview scroll
-1 pages
};break}
3473 bind $ui_diff <Control-Key-f
> {catch
{%W yview scroll
1 pages
};break}
3474 bind $ui_diff <Button-1
> {focus
%W
}
3476 if {[is_enabled branch
]} {
3477 bind .
<$M1B-Key-n> branch_create
::dialog
3478 bind .
<$M1B-Key-N> branch_create
::dialog
3479 bind .
<$M1B-Key-o> branch_checkout
::dialog
3480 bind .
<$M1B-Key-O> branch_checkout
::dialog
3481 bind .
<$M1B-Key-m> merge
::dialog
3482 bind .
<$M1B-Key-M> merge
::dialog
3484 if {[is_enabled transport
]} {
3485 bind .
<$M1B-Key-p> do_push_anywhere
3486 bind .
<$M1B-Key-P> do_push_anywhere
3489 bind .
<Key-F5
> ui_do_rescan
3490 bind .
<$M1B-Key-r> ui_do_rescan
3491 bind .
<$M1B-Key-R> ui_do_rescan
3492 bind .
<$M1B-Key-s> do_signoff
3493 bind .
<$M1B-Key-S> do_signoff
3494 bind .
<$M1B-Key-t> do_add_selection
3495 bind .
<$M1B-Key-T> do_add_selection
3496 bind .
<$M1B-Key-i> do_add_all
3497 bind .
<$M1B-Key-I> do_add_all
3498 bind .
<$M1B-Key-minus> {show_less_context
;break}
3499 bind .
<$M1B-Key-KP_Subtract> {show_less_context
;break}
3500 bind .
<$M1B-Key-equal> {show_more_context
;break}
3501 bind .
<$M1B-Key-plus> {show_more_context
;break}
3502 bind .
<$M1B-Key-KP_Add> {show_more_context
;break}
3503 bind .
<$M1B-Key-Return> do_commit
3504 foreach i
[list
$ui_index $ui_workdir] {
3505 bind $i <Button-1
> "toggle_or_diff $i %x %y; break"
3506 bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break"
3507 bind $i <Shift-Button-1
> "add_range_to_selection $i %x %y; break"
3511 set file_lists
($ui_index) [list
]
3512 set file_lists
($ui_workdir) [list
]
3514 wm title .
"[appname] ([reponame]) [file normalize $_gitworktree]"
3515 focus
-force $ui_comm
3517 # -- Warn the user about environmental problems. Cygwin's Tcl
3518 # does *not* pass its env array onto any processes it spawns.
3519 # This means that git processes get none of our environment.
3524 set msg
[mc
"Possible environment issues exist.
3526 The following environment variables are probably
3527 going to be ignored by any Git subprocess run
3531 foreach name
[array names env
] {
3532 switch
-regexp -- $name {
3533 {^GIT_INDEX_FILE$
} -
3534 {^GIT_OBJECT_DIRECTORY$
} -
3535 {^GIT_ALTERNATE_OBJECT_DIRECTORIES$
} -
3537 {^GIT_EXTERNAL_DIFF$
} -
3541 {^GIT_
(AUTHOR|COMMITTER
)_DATE$
} {
3542 append msg
" - $name\n"
3545 {^GIT_
(AUTHOR|COMMITTER
)_
(NAME|EMAIL
)$
} {
3546 append msg
" - $name\n"
3548 set suggest_user
$name
3552 if {$ignored_env > 0} {
3554 This is due to a known issue with the
3555 Tcl binary distributed by Cygwin."]
3557 if {$suggest_user ne
{}} {
3560 A good replacement for %s
3561 is placing values for the user.name and
3562 user.email settings into your personal
3568 unset ignored_env msg suggest_user name
3571 # -- Only initialize complex UI if we are going to stay running.
3573 if {[is_enabled transport
]} {
3576 set n
[.mbar.remote index end
]
3577 populate_remotes_menu
3578 set n
[expr {[.mbar.remote index end
] - $n}]
3580 if {[.mbar.remote
type 0] eq
"tearoff"} { incr n
}
3581 .mbar.remote insert
$n separator
3586 if {[winfo exists
$ui_comm]} {
3587 set GITGUI_BCK_exists
[load_message GITGUI_BCK
]
3589 # -- If both our backup and message files exist use the
3590 # newer of the two files to initialize the buffer.
3592 if {$GITGUI_BCK_exists} {
3593 set m
[gitdir GITGUI_MSG
]
3594 if {[file isfile
$m]} {
3595 if {[file mtime
[gitdir GITGUI_BCK
]] > [file mtime
$m]} {
3596 catch
{file delete
[gitdir GITGUI_MSG
]}
3598 $ui_comm delete
0.0 end
3600 $ui_comm edit modified false
3601 catch
{file delete
[gitdir GITGUI_BCK
]}
3602 set GITGUI_BCK_exists
0
3608 proc backup_commit_buffer
{} {
3609 global ui_comm GITGUI_BCK_exists
3611 set m
[$ui_comm edit modified
]
3612 if {$m ||
$GITGUI_BCK_exists} {
3613 set msg
[string trim
[$ui_comm get
0.0 end
]]
3614 regsub
-all -line {[ \r\t]+$
} $msg {} msg
3617 if {$GITGUI_BCK_exists} {
3618 catch
{file delete
[gitdir GITGUI_BCK
]}
3619 set GITGUI_BCK_exists
0
3623 set fd
[open
[gitdir GITGUI_BCK
] w
]
3624 puts
-nonewline $fd $msg
3626 set GITGUI_BCK_exists
1
3630 $ui_comm edit modified false
3633 set ::GITGUI_BCK_i
[after
2000 backup_commit_buffer
]
3636 backup_commit_buffer
3638 # -- If the user has aspell available we can drive it
3639 # in pipe mode to spellcheck the commit message.
3641 set spell_cmd
[list |
]
3642 set spell_dict
[get_config gui.spellingdictionary
]
3643 lappend spell_cmd aspell
3644 if {$spell_dict ne
{}} {
3645 lappend spell_cmd
--master=$spell_dict
3647 lappend spell_cmd
--mode=none
3648 lappend spell_cmd
--encoding=utf-8
3649 lappend spell_cmd pipe
3650 if {$spell_dict eq
{none
}
3651 ||
[catch
{set spell_fd
[open
$spell_cmd r
+]} spell_err
]} {
3652 bind_button3
$ui_comm [list tk_popup
$ui_comm_ctxm %X
%Y
]
3654 set ui_comm_spell
[spellcheck
::init \
3660 unset -nocomplain spell_cmd spell_fd spell_err spell_dict
3663 lock_index begin-read
3664 if {![winfo ismapped .
]} {
3668 if {[is_enabled initialamend
]} {
3674 if {[is_enabled nocommitmsg
]} {
3675 $ui_comm configure
-state disabled
-background gray
3678 if {[is_enabled multicommit
]} {
3681 if {[is_enabled retcode
]} {
3682 bind .
<Destroy
> {+terminate_me
%W
}
3684 if {$picked && [is_config_true gui.autoexplore
]} {