]> Pileus Git - ~andy/git/blobdiff - git-gui.sh
git-gui: right half window is paned
[~andy/git] / git-gui.sh
index d3acf0d2134b40b8ffb3d0e8c3229f71fa6db663..b62ae4a94995cc3dc7c6b7d5ab8273ffeb4b9555 100755 (executable)
@@ -93,6 +93,25 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
 
 package require msgcat
 
+# Check for Windows 7 MUI language pack (missed by msgcat < 1.4.4)
+if {[tk windowingsystem] eq "win32"
+       && [package vcompare [package provide msgcat] 1.4.4] < 0
+} then {
+       proc _mc_update_locale {} {
+               set key {HKEY_CURRENT_USER\Control Panel\Desktop}
+               if {![catch {
+                       package require registry
+                       set uilocale [registry get $key "PreferredUILanguages"]
+                       msgcat::ConvertLocale [string map {- _} [lindex $uilocale 0]]
+               } uilocale]} {
+                       if {[string length $uilocale] > 0} {
+                               msgcat::mclocale $uilocale
+                       }
+               }
+       }
+       _mc_update_locale
+}
+
 proc _mc_trim {fmt} {
        set cmk [string first @@ $fmt]
        if {$cmk > 0} {
@@ -116,6 +135,20 @@ proc strcat {args} {
 ::msgcat::mcload $oguimsg
 unset oguimsg
 
+######################################################################
+##
+## On Mac, bring the current Wish process window to front
+
+if {[tk windowingsystem] eq "aqua"} {
+       catch {
+               exec osascript -e [format {
+                       tell application "System Events"
+                               set frontmost of processes whose unix id is %d to true
+                       end tell
+               } [pid]]
+       }
+}
+
 ######################################################################
 ##
 ## read only globals
@@ -135,10 +168,15 @@ set _trace [lsearch -exact $argv --trace]
 if {$_trace >= 0} {
        set argv [lreplace $argv $_trace $_trace]
        set _trace 1
+       if {[tk windowingsystem] eq "win32"} { console show }
 } else {
        set _trace 0
 }
 
+# variable for the last merged branch (useful for a default when deleting
+# branches).
+set _last_merged_branch {}
+
 proc shellpath {} {
        global _shellpath env
        if {[string match @@* $_shellpath]} {
@@ -276,7 +314,9 @@ proc is_config_true {name} {
        global repo_config
        if {[catch {set v $repo_config($name)}]} {
                return 0
-       } elseif {$v eq {true} || $v eq {1} || $v eq {yes}} {
+       }
+       set v [string tolower $v]
+       if {$v eq {} || $v eq {true} || $v eq {1} || $v eq {yes} || $v eq {on}} {
                return 1
        } else {
                return 0
@@ -287,7 +327,9 @@ proc is_config_false {name} {
        global repo_config
        if {[catch {set v $repo_config($name)}]} {
                return 0
-       } elseif {$v eq {false} || $v eq {0} || $v eq {no}} {
+       }
+       set v [string tolower $v]
+       if {$v eq {false} || $v eq {0} || $v eq {no} || $v eq {off}} {
                return 1
        } else {
                return 0
@@ -437,6 +479,35 @@ proc _which {what args} {
        return {}
 }
 
+# Test a file for a hashbang to identify executable scripts on Windows.
+proc is_shellscript {filename} {
+       if {![file exists $filename]} {return 0}
+       set f [open $filename r]
+       fconfigure $f -encoding binary
+       set magic [read $f 2]
+       close $f
+       return [expr {$magic eq "#!"}]
+}
+
+# Run a command connected via pipes on stdout.
+# This is for use with textconv filters and uses sh -c "..." to allow it to
+# contain a command with arguments. On windows we must check for shell
+# scripts specifically otherwise just call the filter command.
+proc open_cmd_pipe {cmd path} {
+       global env
+       if {![file executable [shellpath]]} {
+               set exe [auto_execok [lindex $cmd 0]]
+               if {[is_shellscript [lindex $exe 0]]} {
+                       set run [linsert [auto_execok sh] end -c "$cmd \"\$0\"" $path]
+               } else {
+                       set run [concat $exe [lrange $cmd 1 end] $path]
+               }
+       } else {
+               set run [list [shellpath] -c "$cmd \"\$0\"" $path]
+       }
+       return [open |$run r]
+}
+
 proc _lappend_nice {cmd_var} {
        global _nice
        upvar $cmd_var cmd
@@ -702,7 +773,10 @@ if {[is_Windows]} {
                gitlogo put gray26  -to  5 15 11 16
                gitlogo redither
 
-               wm iconphoto . -default gitlogo
+               image create photo gitlogo32 -width 32 -height 32
+               gitlogo32 copy gitlogo -zoom 2 2
+
+               wm iconphoto . -default gitlogo gitlogo32
        }
 }
 
@@ -820,9 +894,11 @@ set default_config(gui.textconv) true
 set default_config(gui.pruneduringfetch) false
 set default_config(gui.trustmtime) false
 set default_config(gui.fastcopyblame) false
+set default_config(gui.maxrecentrepo) 10
 set default_config(gui.copyblamethreshold) 40
 set default_config(gui.blamehistoryctx) 7
 set default_config(gui.diffcontext) 5
+set default_config(gui.diffopts) {}
 set default_config(gui.commitmsgwidth) 75
 set default_config(gui.newbranchtemplate) {}
 set default_config(gui.spellingdictionary) {}
@@ -831,10 +907,13 @@ set default_config(gui.fontdiff) [font configure font_diff]
 # TODO: this option should be added to the git-config documentation
 set default_config(gui.maxfilesdisplayed) 5000
 set default_config(gui.usettk) 1
+set default_config(gui.warndetachedcommit) 1
 set font_descs {
        {fontui   font_ui   {mc "Main Font"}}
        {fontdiff font_diff {mc "Diff/Console Font"}}
 }
+set default_config(gui.stageuntracked) ask
+set default_config(gui.displayuntracked) true
 
 ######################################################################
 ##
@@ -1036,6 +1115,10 @@ git-version proc _parse_config {arr_name args} {
                                } else {
                                        set arr($name) $value
                                }
+                       } elseif {[regexp {^([^\n]+)$} $line line name]} {
+                               # no value given, but interpreting them as
+                               # boolean will be handled as true
+                               set arr($name) {}
                        }
                }
        }
@@ -1051,6 +1134,10 @@ git-version proc _parse_config {arr_name args} {
                                        } else {
                                                set arr($name) $value
                                        }
+                               } elseif {[regexp {^([^=]+)$} $line line name]} {
+                                       # no value given, but interpreting them as
+                                       # boolean will be handled as true
+                                       set arr($name) {}
                                }
                        }
                        close $fd_rc
@@ -1393,7 +1480,7 @@ proc rescan {after {honor_trustmtime 1}} {
                (![$ui_comm edit modified]
                || [string trim [$ui_comm get 0.0 end]] eq {})} {
                if {[string match amend* $commit_type]} {
-               } elseif {[load_message GITGUI_MSG]} {
+               } elseif {[load_message GITGUI_MSG utf-8]} {
                } elseif {[run_prepare_commit_msg_hook]} {
                } elseif {[load_message MERGE_MSG]} {
                } elseif {[load_message SQUASH_MSG]} {
@@ -1448,34 +1535,43 @@ proc rescan_stage2 {fd after} {
                close $fd
        }
 
-       set ls_others [list --exclude-per-directory=.gitignore]
-       if {[have_info_exclude]} {
-               lappend ls_others "--exclude-from=[gitdir info exclude]"
-       }
-       set user_exclude [get_config core.excludesfile]
-       if {$user_exclude ne {} && [file readable $user_exclude]} {
-               lappend ls_others "--exclude-from=$user_exclude"
+       if {[package vsatisfies $::_git_version 1.6.3]} {
+               set ls_others [list --exclude-standard]
+       } else {
+               set ls_others [list --exclude-per-directory=.gitignore]
+               if {[have_info_exclude]} {
+                       lappend ls_others "--exclude-from=[gitdir info exclude]"
+               }
+               set user_exclude [get_config core.excludesfile]
+               if {$user_exclude ne {} && [file readable $user_exclude]} {
+                       lappend ls_others "--exclude-from=[file normalize $user_exclude]"
+               }
        }
 
        set buf_rdi {}
        set buf_rdf {}
        set buf_rlo {}
 
-       set rescan_active 3
+       set rescan_active 2
        ui_status [mc "Scanning for modified files ..."]
        set fd_di [git_read diff-index --cached -z [PARENT]]
        set fd_df [git_read diff-files -z]
-       set fd_lo [eval git_read ls-files --others -z $ls_others]
 
        fconfigure $fd_di -blocking 0 -translation binary -encoding binary
        fconfigure $fd_df -blocking 0 -translation binary -encoding binary
-       fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
+
        fileevent $fd_di readable [list read_diff_index $fd_di $after]
        fileevent $fd_df readable [list read_diff_files $fd_df $after]
-       fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
+
+       if {[is_config_true gui.displayuntracked]} {
+               set fd_lo [eval git_read ls-files --others -z $ls_others]
+               fconfigure $fd_lo -blocking 0 -translation binary -encoding binary
+               fileevent $fd_lo readable [list read_ls_others $fd_lo $after]
+               incr rescan_active
+       }
 }
 
-proc load_message {file} {
+proc load_message {file {encoding {}}} {
        global ui_comm
 
        set f [gitdir $file]
@@ -1484,6 +1580,9 @@ proc load_message {file} {
                        return 0
                }
                fconfigure $fd -eofchar {}
+               if {$encoding ne {}} {
+                       fconfigure $fd -encoding $encoding
+               }
                set content [string trim [read $fd]]
                close $fd
                regsub -all -line {[ \r\t]+$} $content {} content
@@ -1499,7 +1598,7 @@ proc run_prepare_commit_msg_hook {} {
 
        # prepare-commit-msg requires PREPARE_COMMIT_MSG exist.  From git-gui
        # it will be .git/MERGE_MSG (merge), .git/SQUASH_MSG (squash), or an
-       # empty file but existant file.
+       # empty file but existent file.
 
        set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a]
 
@@ -1958,8 +2057,8 @@ static unsigned char file_merge_bits[] = {
 } -maskdata $filemask
 
 image create bitmap file_statechange -background white -foreground green -data {
-#define file_merge_width 14
-#define file_merge_height 15
+#define file_statechange_width 14
+#define file_statechange_height 15
 static unsigned char file_statechange_bits[] = {
    0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x62, 0x10,
    0x62, 0x10, 0xba, 0x11, 0xba, 0x11, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10,
@@ -1993,7 +2092,11 @@ foreach i {
                {MD {mc "Staged for commit, missing"}}
 
                {_T {mc "File type changed, not staged"}}
+               {MT {mc "File type changed, old type staged for commit"}}
+               {AT {mc "File type changed, old type staged for commit"}}
                {T_ {mc "File type changed, staged"}}
+               {TM {mc "File type change staged, modification not staged"}}
+               {TD {mc "File type change staged, file missing"}}
 
                {_O {mc "Untracked, not staged"}}
                {A_ {mc "Staged for commit"}}
@@ -2188,6 +2291,7 @@ proc do_quit {{rc {1}}} {
                                && $msg ne {}} {
                                catch {
                                        set fd [open $save w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                }
@@ -2442,6 +2546,7 @@ proc toggle_or_diff {w x y} {
                                [concat $after [list ui_ready]]
                }
        } else {
+               set selected_paths($path) 1
                show_diff $path $w $lno
        }
 }
@@ -2919,9 +3024,11 @@ blame {
        set jump_spec {}
        set is_path 0
        foreach a $argv {
-               if {$is_path || [file exists $_prefix$a]} {
+               set p [file join $_prefix $a]
+
+               if {$is_path || [file exists $p]} {
                        if {$path ne {}} usage
-                       set path [normalize_relpath $_prefix$a]
+                       set path [normalize_relpath $p]
                        break
                } elseif {$a eq {--}} {
                        if {$path ne {}} {
@@ -2944,8 +3051,13 @@ blame {
        unset is_path
 
        if {$head ne {} && $path eq {}} {
-               set path [normalize_relpath $_prefix$head]
-               set head {}
+               if {[string index $head 0] eq {/}} {
+                       set path [normalize_relpath $head]
+                       set head {}
+               } else {
+                       set path [normalize_relpath $_prefix$head]
+                       set head {}
+               }
        }
 
        if {$head eq {}} {
@@ -3098,13 +3210,19 @@ unset i
 
 # -- Diff and Commit Area
 #
-${NS}::frame .vpane.lower -height 300 -width 400
+${NS}::panedwindow .vpane.lower -orient vertical
 ${NS}::frame .vpane.lower.commarea
-${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1
-pack .vpane.lower.diff -fill both -expand 1
-pack .vpane.lower.commarea -side bottom -fill x
+${NS}::frame .vpane.lower.diff -relief sunken -borderwidth 1 -height 500
+.vpane.lower add .vpane.lower.diff
+.vpane.lower add .vpane.lower.commarea
 .vpane add .vpane.lower
-if {!$use_ttk} {.vpane paneconfigure .vpane.lower -sticky nsew}
+if {$use_ttk} {
+       .vpane.lower pane .vpane.lower.diff -weight 1
+       .vpane.lower pane .vpane.lower.commarea -weight 0
+} else {
+       .vpane.lower paneconfigure .vpane.lower.diff -stretch always
+       .vpane.lower paneconfigure .vpane.lower.commarea -stretch never
+}
 
 # -- Commit Area Buttons
 #
@@ -3330,6 +3448,9 @@ foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 gr
        $ui_diff tag configure clri3$n -background $c
 }
 $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_cr -elide true
 $ui_diff tag conf d_@ -font font_diffbold
@@ -3351,13 +3472,13 @@ $ui_diff tag conf d_s- \
        -foreground red \
        -background ivory1
 
-$ui_diff tag conf d<<<<<<< \
+$ui_diff tag conf d< \
        -foreground orange \
        -font font_diffbold
-$ui_diff tag conf d======= \
+$ui_diff tag conf d= \
        -foreground orange \
        -font font_diffbold
-$ui_diff tag conf d>>>>>>> \
+$ui_diff tag conf d> \
        -foreground orange \
        -font font_diffbold
 
@@ -3533,8 +3654,8 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
                        || $current_diff_path eq {}
                        || {__} eq $state
                        || {_O} eq $state
-                       || {_T} eq $state
-                       || {T_} eq $state
+                       || [string match {?T} $state]
+                       || [string match {T?} $state]
                        || [has_textconv $current_diff_path]} {
                        set s disabled
                } else {
@@ -3628,6 +3749,8 @@ bind $ui_diff <$M1B-Key-v> {break}
 bind $ui_diff <$M1B-Key-V> {break}
 bind $ui_diff <$M1B-Key-a> {%W tag add sel 0.0 end;break}
 bind $ui_diff <$M1B-Key-A> {%W tag add sel 0.0 end;break}
+bind $ui_diff <$M1B-Key-j> {do_revert_selection;break}
+bind $ui_diff <$M1B-Key-J> {do_revert_selection;break}
 bind $ui_diff <Key-Up>     {catch {%W yview scroll -1 units};break}
 bind $ui_diff <Key-Down>   {catch {%W yview scroll  1 units};break}
 bind $ui_diff <Key-Left>   {catch {%W xview scroll -1 units};break}
@@ -3660,6 +3783,8 @@ bind .   <$M1B-Key-s> do_signoff
 bind .   <$M1B-Key-S> do_signoff
 bind .   <$M1B-Key-t> do_add_selection
 bind .   <$M1B-Key-T> do_add_selection
+bind .   <$M1B-Key-u> do_unstage_selection
+bind .   <$M1B-Key-U> do_unstage_selection
 bind .   <$M1B-Key-j> do_revert_selection
 bind .   <$M1B-Key-J> do_revert_selection
 bind .   <$M1B-Key-i> do_add_all
@@ -3753,7 +3878,7 @@ if {[is_enabled transport]} {
 }
 
 if {[winfo exists $ui_comm]} {
-       set GITGUI_BCK_exists [load_message GITGUI_BCK]
+       set GITGUI_BCK_exists [load_message GITGUI_BCK utf-8]
 
        # -- If both our backup and message files exist use the
        #    newer of the two files to initialize the buffer.
@@ -3790,6 +3915,7 @@ if {[winfo exists $ui_comm]} {
                        } elseif {$m} {
                                catch {
                                        set fd [open [gitdir GITGUI_BCK] w]
+                                       fconfigure $fd -encoding utf-8
                                        puts -nonewline $fd $msg
                                        close $fd
                                        set GITGUI_BCK_exists 1
@@ -3844,7 +3970,7 @@ after 1 {
                $ui_comm configure -state disabled -background gray
        }
 }
-if {[is_enabled multicommit]} {
+if {[is_enabled multicommit] && ![is_config_false gui.gcwarning]} {
        after 1000 hint_gc
 }
 if {[is_enabled retcode]} {