diff options
Diffstat (limited to 'git-gui/git-gui.sh')
| -rwxr-xr-x | git-gui/git-gui.sh | 377 |
1 files changed, 163 insertions, 214 deletions
diff --git a/git-gui/git-gui.sh b/git-gui/git-gui.sh index 867b8cea46..887d6d596c 100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@ -24,7 +24,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with this program; if not, see <http://www.gnu.org/licenses/>.}] +along with this program; if not, see <https://www.gnu.org/licenses/>.}] ###################################################################### ## @@ -46,6 +46,132 @@ catch {rename send {}} ; # What an evil concept... ###################################################################### ## +## Enabling platform-specific code paths + +proc is_MacOSX {} { + if {[tk windowingsystem] eq {aqua}} { + return 1 + } + return 0 +} + +proc is_Windows {} { + if {$::tcl_platform(platform) eq {windows}} { + return 1 + } + return 0 +} + +set _iscygwin {} +proc is_Cygwin {} { + global _iscygwin + if {$_iscygwin eq {}} { + if {[string match "CYGWIN_*" $::tcl_platform(os)]} { + set _iscygwin 1 + } else { + set _iscygwin 0 + } + } + return $_iscygwin +} + +###################################################################### +## +## PATH lookup + +set _search_path {} +proc _which {what args} { + global env _search_exe _search_path + + if {$_search_path eq {}} { + if {[is_Windows]} { + set gitguidir [file dirname [info script]] + regsub -all ";" $gitguidir "\\;" gitguidir + set env(PATH) "$gitguidir;$env(PATH)" + set _search_path [split $env(PATH) {;}] + # Skip empty `PATH` elements + set _search_path [lsearch -all -inline -not -exact \ + $_search_path ""] + set _search_exe .exe + } else { + set _search_path [split $env(PATH) :] + set _search_exe {} + } + } + + if {[is_Windows] && [lsearch -exact $args -script] >= 0} { + set suffix {} + } else { + set suffix $_search_exe + } + + foreach p $_search_path { + set p [file join $p $what$suffix] + if {[file exists $p]} { + return [file normalize $p] + } + } + return {} +} + +proc sanitize_command_line {command_line from_index} { + set i $from_index + while {$i < [llength $command_line]} { + set cmd [lindex $command_line $i] + if {[llength [file split $cmd]] < 2} { + set fullpath [_which $cmd] + if {$fullpath eq ""} { + throw {NOT-FOUND} "$cmd not found in PATH" + } + lset command_line $i $fullpath + } + + # handle piped commands, e.g. `exec A | B` + for {incr i} {$i < [llength $command_line]} {incr i} { + if {[lindex $command_line $i] eq "|"} { + incr i + break + } + } + } + return $command_line +} + +# Override `exec` to avoid unsafe PATH lookup + +rename exec real_exec + +proc exec {args} { + # skip options + for {set i 0} {$i < [llength $args]} {incr i} { + set arg [lindex $args $i] + if {$arg eq "--"} { + incr i + break + } + if {[string range $arg 0 0] ne "-"} { + break + } + } + set args [sanitize_command_line $args $i] + uplevel 1 real_exec $args +} + +# Override `open` to avoid unsafe PATH lookup + +rename open real_open + +proc open {args} { + set arg0 [lindex $args 0] + if {[string range $arg0 0 0] eq "|"} { + set command_line [string trim [string range $arg0 1 end]] + lset args 0 "| [sanitize_command_line $command_line 0]" + } + uplevel 1 real_open $args +} + +###################################################################### +## ## locate our library if { [info exists ::env(GIT_GUI_LIB_DIR) ] } { @@ -163,8 +289,6 @@ set _isbare {} set _gitexec {} set _githtmldir {} set _reponame {} -set _iscygwin {} -set _search_path {} set _shellpath {@@SHELL_PATH@@} set _trace [lsearch -exact $argv --trace] @@ -211,14 +335,7 @@ proc gitexec {args} { if {[catch {set _gitexec [git --exec-path]} err]} { error "Git not installed?\n\n$err" } - if {[is_Cygwin]} { - set _gitexec [exec cygpath \ - --windows \ - --absolute \ - $_gitexec] - } else { - set _gitexec [file normalize $_gitexec] - } + set _gitexec [file normalize $_gitexec] } if {$args eq {}} { return $_gitexec @@ -233,14 +350,7 @@ proc githtmldir {args} { # Git not installed or option not yet supported return {} } - if {[is_Cygwin]} { - set _githtmldir [exec cygpath \ - --windows \ - --absolute \ - $_githtmldir] - } else { - set _githtmldir [file normalize $_githtmldir] - } + set _githtmldir [file normalize $_githtmldir] } if {$args eq {}} { return $_githtmldir @@ -252,40 +362,6 @@ proc reponame {} { return $::_reponame } -proc is_MacOSX {} { - if {[tk windowingsystem] eq {aqua}} { - return 1 - } - return 0 -} - -proc is_Windows {} { - if {$::tcl_platform(platform) eq {windows}} { - return 1 - } - return 0 -} - -proc is_Cygwin {} { - global _iscygwin - if {$_iscygwin eq {}} { - if {$::tcl_platform(platform) eq {windows}} { - if {[catch {set p [exec cygpath --windir]} err]} { - set _iscygwin 0 - } else { - set _iscygwin 1 - # Handle MSys2 which is only cygwin when MSYSTEM is MSYS. - if {[info exists ::env(MSYSTEM)] && $::env(MSYSTEM) ne "MSYS"} { - set _iscygwin 0 - } - } - } else { - set _iscygwin 0 - } - } - return $_iscygwin -} - proc is_enabled {option} { global enabled_options if {[catch {set on $enabled_options($option)}]} {return 0} @@ -448,44 +524,6 @@ proc _git_cmd {name} { return $v } -proc _which {what args} { - global env _search_exe _search_path - - if {$_search_path eq {}} { - if {[is_Cygwin] && [regexp {^(/|\.:)} $env(PATH)]} { - set _search_path [split [exec cygpath \ - --windows \ - --path \ - --absolute \ - $env(PATH)] {;}] - set _search_exe .exe - } elseif {[is_Windows]} { - set gitguidir [file dirname [info script]] - regsub -all ";" $gitguidir "\\;" gitguidir - set env(PATH) "$gitguidir;$env(PATH)" - set _search_path [split $env(PATH) {;}] - set _search_exe .exe - } else { - set _search_path [split $env(PATH) :] - set _search_exe {} - } - } - - if {[is_Windows] && [lsearch -exact $args -script] >= 0} { - set suffix {} - } else { - set suffix $_search_exe - } - - foreach p $_search_path { - set p [file join $p $what$suffix] - if {[file exists $p]} { - return [file normalize $p] - } - } - return {} -} - # Test a file for a hashbang to identify executable scripts on Windows. proc is_shellscript {filename} { if {![file exists $filename]} {return 0} @@ -623,31 +661,8 @@ proc git_write {args} { } proc githook_read {hook_name args} { - set pchook [gitdir hooks $hook_name] - lappend args 2>@1 - - # On Windows [file executable] might lie so we need to ask - # the shell if the hook is executable. Yes that's annoying. - # - if {[is_Windows]} { - upvar #0 _sh interp - if {![info exists interp]} { - set interp [_which sh] - } - if {$interp eq {}} { - error "hook execution requires sh (not in PATH)" - } - - set scr {if test -x "$1";then exec "$@";fi} - set sh_c [list $interp -c $scr $interp $pchook] - return [_open_stdout_stderr [concat $sh_c $args]] - } - - if {[file executable $pchook]} { - return [_open_stdout_stderr [concat [list $pchook] $args]] - } - - return {} + set cmd [concat git hook run --ignore-missing $hook_name -- $args 2>@1] + return [_open_stdout_stderr $cmd] } proc kill_file_process {fd} { @@ -720,9 +735,6 @@ proc rmsel_tag {text} { -background [$text cget -background] \ -foreground [$text cget -foreground] \ -borderwidth 0 - $text tag conf in_sel\ - -background $color::select_bg \ - -foreground $color::select_fg bind $text <Motion> break return $text } @@ -1262,9 +1274,6 @@ if {$_gitdir eq "."} { set _gitdir [pwd] } -if {![file isdirectory $_gitdir] && [is_Cygwin]} { - catch {set _gitdir [exec cygpath --windows $_gitdir]} -} if {![file isdirectory $_gitdir]} { catch {wm withdraw .} error_popup [strcat [mc "Git directory not found:"] "\n\n$_gitdir"] @@ -1276,11 +1285,7 @@ apply_config # v1.7.0 introduced --show-toplevel to return the canonical work-tree if {[package vcompare $_git_version 1.7.0] >= 0} { - if { [is_Cygwin] } { - catch {set _gitworktree [exec cygpath --windows [git rev-parse --show-toplevel]]} - } else { - set _gitworktree [git rev-parse --show-toplevel] - } + set _gitworktree [git rev-parse --show-toplevel] } else { # try to set work tree from environment, core.worktree or use # cdup to obtain a relative path to the top of the worktree. If @@ -1352,7 +1357,6 @@ set current_diff_path {} set is_3way_diff 0 set is_submodule_diff 0 set is_conflict_diff 0 -set diff_empty_count 0 set last_revert {} set last_revert_enc {} @@ -1482,6 +1486,7 @@ proc rescan {after {honor_trustmtime 1}} { } elseif {[run_prepare_commit_msg_hook]} { } elseif {[load_message MERGE_MSG]} { } elseif {[load_message SQUASH_MSG]} { + } elseif {[load_message [get_config commit.template]]} { } $ui_comm edit reset $ui_comm edit modified false @@ -1504,24 +1509,8 @@ proc rescan {after {honor_trustmtime 1}} { } } -if {[is_Cygwin]} { - set is_git_info_exclude {} - proc have_info_exclude {} { - global is_git_info_exclude - - if {$is_git_info_exclude eq {}} { - if {[catch {exec test -f [gitdir info exclude]}]} { - set is_git_info_exclude 0 - } else { - set is_git_info_exclude 1 - } - } - return $is_git_info_exclude - } -} else { - proc have_info_exclude {} { - return [file readable [gitdir info exclude]] - } +proc have_info_exclude {} { + return [file readable [gitdir info exclude]] } proc rescan_stage2 {fd after} { @@ -1616,6 +1605,12 @@ proc run_prepare_commit_msg_hook {} { fconfigure $fd_sm -encoding utf-8 puts -nonewline $fd_pcm [read $fd_sm] close $fd_sm + } elseif {[file isfile [get_config commit.template]]} { + set pcm_source "template" + set fd_sm [open [get_config commit.template] r] + fconfigure $fd_sm -encoding utf-8 + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm } else { set pcm_source "" } @@ -2255,7 +2250,9 @@ proc do_git_gui {} { # Get the system-specific explorer app/command. proc get_explorer {} { - if {[is_Cygwin] || [is_Windows]} { + if {[is_Cygwin]} { + set explorer "/bin/cygstart.exe --explore" + } elseif {[is_Windows]} { set explorer "explorer.exe" } elseif {[is_MacOSX]} { set explorer "open" @@ -2303,13 +2300,12 @@ proc do_quit {{rc {1}}} { # set save [gitdir GITGUI_MSG] if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} { - file rename -force [gitdir GITGUI_BCK] $save + catch { file rename -force [gitdir GITGUI_BCK] $save } set GITGUI_BCK_exists 0 - } else { + } elseif {[$ui_comm edit modified]} { set msg [string trim [$ui_comm get 0.0 end]] regsub -all -line {[ \r\t]+$} $msg {} msg - if {(![string match amend* $commit_type] - || [$ui_comm edit modified]) + if {![string match amend* $commit_type] && $msg ne {}} { catch { set fd [open $save w] @@ -2370,7 +2366,7 @@ proc do_quit {{rc {1}}} { set ret_code $rc # Briefly enable send again, working around Tk bug - # http://sourceforge.net/tracker/?func=detail&atid=112997&aid=1821174&group_id=12997 + # https://sourceforge.net/p/tktoolkit/bugs/2343/ tk appname [appname] destroy . @@ -3050,16 +3046,12 @@ if {[is_MacOSX]} { set doc_path [githtmldir] if {$doc_path ne {}} { set doc_path [file join $doc_path index.html] - - if {[is_Cygwin]} { - set doc_path [exec cygpath --mixed $doc_path] - } } if {[file isfile $doc_path]} { set doc_url "file:$doc_path" } else { - set doc_url {http://www.kernel.org/pub/software/scm/git/docs/} + set doc_url {https://www.kernel.org/pub/software/scm/git/docs/} } proc start_browser {url} { @@ -3322,11 +3314,20 @@ if {!$use_ttk} { .vpane.files paneconfigure .vpane.files.index -sticky news } +proc set_selection_colors {w has_focus} { + foreach tag [list in_diff in_sel] { + $w tag conf $tag \ + -background [expr {$has_focus ? $color::select_bg : $color::inactive_select_bg}] \ + -foreground [expr {$has_focus ? $color::select_fg : $color::inactive_select_fg}] + } +} + foreach i [list $ui_index $ui_workdir] { rmsel_tag $i - $i tag conf in_diff \ - -background $color::select_bg \ - -foreground $color::select_fg + + set_selection_colors $i 0 + bind $i <FocusIn> { set_selection_colors %W 1 } + bind $i <FocusOut> { set_selection_colors %W 0 } } unset i @@ -3592,6 +3593,8 @@ $ui_diff tag configure clr1 -font font_diffbold $ui_diff tag configure clr4 -underline 1 $ui_diff tag conf d_info -foreground blue -font font_diffbold +$ui_diff tag conf d_rescan -foreground blue -underline 1 -font font_diffbold +$ui_diff tag bind d_rescan <Button-1> { clear_diff; rescan ui_ready 0 } $ui_diff tag conf d_cr -elide true $ui_diff tag conf d_@ -font font_diffbold @@ -4016,60 +4019,6 @@ set file_lists($ui_workdir) [list] wm title . "[appname] ([reponame]) [file normalize $_gitworktree]" focus -force $ui_comm -# -- Warn the user about environmental problems. Cygwin's Tcl -# does *not* pass its env array onto any processes it spawns. -# This means that git processes get none of our environment. -# -if {[is_Cygwin]} { - set ignored_env 0 - set suggest_user {} - set msg [mc "Possible environment issues exist. - -The following environment variables are probably -going to be ignored by any Git subprocess run -by %s: - -" [appname]] - foreach name [array names env] { - switch -regexp -- $name { - {^GIT_INDEX_FILE$} - - {^GIT_OBJECT_DIRECTORY$} - - {^GIT_ALTERNATE_OBJECT_DIRECTORIES$} - - {^GIT_DIFF_OPTS$} - - {^GIT_EXTERNAL_DIFF$} - - {^GIT_PAGER$} - - {^GIT_TRACE$} - - {^GIT_CONFIG$} - - {^GIT_(AUTHOR|COMMITTER)_DATE$} { - append msg " - $name\n" - incr ignored_env - } - {^GIT_(AUTHOR|COMMITTER)_(NAME|EMAIL)$} { - append msg " - $name\n" - incr ignored_env - set suggest_user $name - } - } - } - if {$ignored_env > 0} { - append msg [mc " -This is due to a known issue with the -Tcl binary distributed by Cygwin."] - - if {$suggest_user ne {}} { - append msg [mc " - -A good replacement for %s -is placing values for the user.name and -user.email settings into your personal -~/.gitconfig file. -" $suggest_user] - } - warn_popup $msg - } - unset ignored_env msg suggest_user name -} - # -- Only initialize complex UI if we are going to stay running. # if {[is_enabled transport]} { |
