git-gui: l10n: add Portuguese translation
[gitweb.git] / git-gui.sh
index 5e8378fc3e4af9854f0063cd5df8ddfdf78ab412..11048c7a0e94f598b168de98d18fda9aea420c7d 100755 (executable)
@@ -49,7 +49,11 @@ catch {rename send {}} ; # What an evil concept...
 ##
 ## locate our library
 
-set oguilib {@@GITGUI_LIBDIR@@}
+if { [info exists ::env(GIT_GUI_LIB_DIR) ] } {
+       set oguilib $::env(GIT_GUI_LIB_DIR)
+} else {
+       set oguilib {@@GITGUI_LIBDIR@@}
+}
 set oguirel {@@GITGUI_RELATIVE@@}
 if {$oguirel eq {1}} {
        set oguilib [file dirname [file normalize $argv0]]
@@ -79,9 +83,9 @@ if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} {
                return [uplevel 1 real__auto_load $name $args]
        }
        rename source real__source
-       proc source {name} {
-               puts stderr "source    $name"
-               uplevel 1 real__source $name
+       proc source {args} {
+               puts stderr "source    $args"
+               uplevel 1 [linsert $args 0 real__source]
        }
        if {[tk windowingsystem] eq "win32"} { console show }
 }
@@ -93,6 +97,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 +139,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 +172,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 +318,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 +331,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 +483,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
@@ -595,9 +670,7 @@ proc kill_file_process {fd} {
 
        catch {
                if {[is_Windows]} {
-                       # Use a Cygwin-specific flag to allow killing
-                       # native Windows processes
-                       exec kill -f $process
+                       exec taskkill /pid $process
                } else {
                        exec kill $process
                }
@@ -702,7 +775,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 +896,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 +909,14 @@ 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 default_config(gui.tabsize) 8
 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 +1118,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 +1137,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
@@ -1196,8 +1286,12 @@ load_config 0
 apply_config
 
 # v1.7.0 introduced --show-toplevel to return the canonical work-tree
-if {[package vsatisfies $_git_version 1.7.0]} {
-       set _gitworktree [git rev-parse --show-toplevel]
+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]
+       }
 } 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
@@ -1393,7 +1487,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 +1542,47 @@ 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 vcompare $::_git_version 1.6.3] >= 0} {
+               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]]
+       if {[git-version >= "1.7.2"]} {
+               set fd_di [git_read diff-index --cached --ignore-submodules=dirty -z [PARENT]]
+       } else {
+               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 +1591,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 +1609,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]
 
@@ -1855,20 +1965,22 @@ proc display_all_files {} {
 
        set to_display [lsort [array names file_states]]
        set display_limit [get_config gui.maxfilesdisplayed]
-       if {[llength $to_display] > $display_limit} {
-               if {!$files_warning} {
-                       # do not repeatedly warn:
-                       set files_warning 1
-                       info_popup [mc "Displaying only %s of %s files." \
-                               $display_limit [llength $to_display]]
-               }
-               set to_display [lrange $to_display 0 [expr {$display_limit-1}]]
-       }
+       set displayed 0
        foreach path $to_display {
                set s $file_states($path)
                set m [lindex $s 0]
                set icon_name [lindex $s 1]
 
+               if {$displayed > $display_limit && [string index $m 1] eq {O} } {
+                       if {!$files_warning} {
+                               # do not repeatedly warn:
+                               set files_warning 1
+                               info_popup [mc "Display limit (gui.maxfilesdisplayed = %s) reached, not showing all %s files." \
+                                       $display_limit [llength $to_display]]
+                       }
+                       continue
+               }
+
                set s [string index $m 0]
                if {$s ne {U} && $s ne {_}} {
                        display_all_files_helper $ui_index $path \
@@ -1883,6 +1995,7 @@ proc display_all_files {} {
                if {$s ne {_}} {
                        display_all_files_helper $ui_workdir $path \
                                $icon_name $s
+                       incr displayed
                }
        }
 
@@ -1958,8 +2071,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 +2106,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 +2305,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 +2560,7 @@ proc toggle_or_diff {w x y} {
                                [concat $after [list ui_ready]]
                }
        } else {
+               set selected_paths($path) 1
                show_diff $path $w $lno
        }
 }
@@ -2556,6 +2675,16 @@ if {![is_bare]} {
        .mbar.repository add command \
                -label [mc "Explore Working Copy"] \
                -command {do_explore}
+}
+
+if {[is_Windows]} {
+       .mbar.repository add command \
+               -label [mc "Git Bash"] \
+               -command {eval exec [auto_execok start] \
+                                         [list "Git Bash" bash --login -l &]}
+}
+
+if {[is_Windows] || ![is_bare]} {
        .mbar.repository add separator
 }
 
@@ -2919,9 +3048,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 +3075,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 +3234,29 @@ unset i
 
 # -- Diff and Commit Area
 #
-${NS}::frame .vpane.lower -height 300 -width 400
-${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
-.vpane add .vpane.lower
-if {!$use_ttk} {.vpane paneconfigure .vpane.lower -sticky nsew}
+if {$have_tk85} {
+       ${NS}::panedwindow .vpane.lower -orient vertical
+       ${NS}::frame .vpane.lower.commarea
+       ${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.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
+       }
+} else {
+       frame .vpane.lower -height 300 -width 400
+       frame .vpane.lower.commarea
+       frame .vpane.lower.diff -relief sunken -borderwidth 1
+       pack .vpane.lower.diff -fill both -expand 1
+       pack .vpane.lower.commarea -side bottom -fill x
+       .vpane add .vpane.lower
+       .vpane paneconfigure .vpane.lower -sticky nsew
+}
 
 # -- Commit Area Buttons
 #
@@ -3312,6 +3464,7 @@ text $ui_diff -background white -foreground black \
        -xscrollcommand {.vpane.lower.diff.body.sbx set} \
        -yscrollcommand {.vpane.lower.diff.body.sby set} \
        -state disabled
+catch {$ui_diff configure -tabstyle wordprocessor}
 ${NS}::scrollbar .vpane.lower.diff.body.sbx -orient horizontal \
        -command [list $ui_diff xview]
 ${NS}::scrollbar .vpane.lower.diff.body.sby -orient vertical \
@@ -3322,8 +3475,19 @@ pack $ui_diff -side left -fill both -expand 1
 pack .vpane.lower.diff.header -side top -fill x
 pack .vpane.lower.diff.body -side bottom -fill both -expand 1
 
+foreach {n c} {0 black 1 red4 2 green4 3 yellow4 4 blue4 5 magenta4 6 cyan4 7 grey60} {
+       $ui_diff tag configure clr4$n -background $c
+       $ui_diff tag configure clri4$n -foreground $c
+       $ui_diff tag configure clr3$n -foreground $c
+       $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_@ -foreground blue -font font_diffbold
+$ui_diff tag conf d_@ -font font_diffbold
 $ui_diff tag conf d_+ -foreground {#00a000}
 $ui_diff tag conf d_- -foreground red
 
@@ -3342,13 +3506,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
 
@@ -3524,8 +3688,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 {
@@ -3619,6 +3783,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}
@@ -3651,6 +3817,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
@@ -3744,7 +3912,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.
@@ -3781,6 +3949,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
@@ -3835,7 +4004,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]} {