From: Junio C Hamano Date: Sun, 16 Nov 2008 23:51:11 +0000 (-0800) Subject: Merge git://repo.or.cz/git-gui X-Git-Tag: v1.6.1-rc1~39 X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=6e13921b4f7adcc7316a76c0c4955b85b1589a65;p=git.git Merge git://repo.or.cz/git-gui * git://repo.or.cz/git-gui: git-gui: Fix the search bar destruction handler. Update the po template git-gui: Implement automatic rescan after Tool execution. git-gui: Allow Tools request arguments from the user. git-gui: Add a Tools menu for arbitrary commands. git-gui: Fix the after callback execution in rescan. git-gui: Implement system-wide configuration handling. git-gui: try to provide a window icon under X --- 6e13921b4f7adcc7316a76c0c4955b85b1589a65 diff --cc git-gui/git-gui.sh index cf9ef6ee0,000000000..8a4b42dbd mode 100755,000000..100755 --- a/git-gui/git-gui.sh +++ b/git-gui/git-gui.sh @@@ -1,3404 -1,0 +1,3464 @@@ +#!/bin/sh +# Tcl ignores the next line -*- tcl -*- \ + if test "z$*" = zversion \ + || test "z$*" = z--version; \ + then \ + echo 'git-gui version @@GITGUI_VERSION@@'; \ + exit; \ + fi; \ + argv0=$0; \ + exec wish "$argv0" -- "$@" + +set appvers {@@GITGUI_VERSION@@} +set copyright [encoding convertfrom utf-8 { +Copyright © 2006, 2007 Shawn Pearce, et. al. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA}] + +###################################################################### +## +## Tcl/Tk sanity check + +if {[catch {package require Tcl 8.4} err] + || [catch {package require Tk 8.4} err] +} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message $err + exit 1 +} + +catch {rename send {}} ; # What an evil concept... + +###################################################################### +## +## locate our library + +set oguilib {@@GITGUI_LIBDIR@@} +set oguirel {@@GITGUI_RELATIVE@@} +if {$oguirel eq {1}} { + set oguilib [file dirname [file normalize $argv0]] + if {[file tail $oguilib] eq {git-core}} { + set oguilib [file dirname $oguilib] + } + set oguilib [file dirname $oguilib] + set oguilib [file join $oguilib share git-gui lib] + set oguimsg [file join $oguilib msgs] +} elseif {[string match @@* $oguirel]} { + set oguilib [file join [file dirname [file normalize $argv0]] lib] + set oguimsg [file join [file dirname [file normalize $argv0]] po] +} else { + set oguimsg [file join $oguilib msgs] +} +unset oguirel + +###################################################################### +## +## enable verbose loading? + +if {![catch {set _verbose $env(GITGUI_VERBOSE)}]} { + unset _verbose + rename auto_load real__auto_load + proc auto_load {name args} { + puts stderr "auto_load $name" + return [uplevel 1 real__auto_load $name $args] + } + rename source real__source + proc source {name} { + puts stderr "source $name" + uplevel 1 real__source $name + } +} + +###################################################################### +## +## Internationalization (i18n) through msgcat and gettext. See +## http://www.gnu.org/software/gettext/manual/html_node/Tcl.html + +package require msgcat + +proc _mc_trim {fmt} { + set cmk [string first @@ $fmt] + if {$cmk > 0} { + return [string range $fmt 0 [expr {$cmk - 1}]] + } + return $fmt +} + +proc mc {en_fmt args} { + set fmt [_mc_trim [::msgcat::mc $en_fmt]] + if {[catch {set msg [eval [list format $fmt] $args]} err]} { + set msg [eval [list format [_mc_trim $en_fmt]] $args] + } + return $msg +} + +proc strcat {args} { + return [join $args {}] +} + +::msgcat::mcload $oguimsg +unset oguimsg + +###################################################################### +## +## read only globals + +set _appname {Git Gui} +set _gitdir {} +set _gitexec {} +set _reponame {} +set _iscygwin {} +set _search_path {} + +set _trace [lsearch -exact $argv --trace] +if {$_trace >= 0} { + set argv [lreplace $argv $_trace $_trace] + set _trace 1 +} else { + set _trace 0 +} + +proc appname {} { + global _appname + return $_appname +} + +proc gitdir {args} { + global _gitdir + if {$args eq {}} { + return $_gitdir + } + return [eval [list file join $_gitdir] $args] +} + +proc gitexec {args} { + global _gitexec + if {$_gitexec eq {}} { + 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] + } + } + if {$args eq {}} { + return $_gitexec + } + return [eval [list file join $_gitexec] $args] +} + +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 + } + } else { + set _iscygwin 0 + } + } + return $_iscygwin +} + +proc is_enabled {option} { + global enabled_options + if {[catch {set on $enabled_options($option)}]} {return 0} + return $on +} + +proc enable_option {option} { + global enabled_options + set enabled_options($option) 1 +} + +proc disable_option {option} { + global enabled_options + set enabled_options($option) 0 +} + +###################################################################### +## +## config + +proc is_many_config {name} { + switch -glob -- $name { + gui.recentrepo - + remote.*.fetch - + remote.*.push + {return 1} + * + {return 0} + } +} + +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}} { + return 1 + } else { + return 0 + } +} + +proc get_config {name} { + global repo_config + if {[catch {set v $repo_config($name)}]} { + return {} + } else { + return $v + } +} + +###################################################################### +## +## handy utils + +proc _trace_exec {cmd} { + if {!$::_trace} return + set d {} + foreach v $cmd { + if {$d ne {}} { + append d { } + } + if {[regexp {[ \t\r\n'"$?*]} $v]} { + set v [sq $v] + } + append d $v + } + puts stderr $d +} + +proc _git_cmd {name} { + global _git_cmd_path + + if {[catch {set v $_git_cmd_path($name)}]} { + switch -- $name { + version - + --version - + --exec-path { return [list $::_git $name] } + } + + set p [gitexec git-$name$::_search_exe] + if {[file exists $p]} { + set v [list $p] + } elseif {[is_Windows] && [file exists [gitexec git-$name]]} { + # Try to determine what sort of magic will make + # git-$name go and do its thing, because native + # Tcl on Windows doesn't know it. + # + set p [gitexec git-$name] + set f [open $p r] + set s [gets $f] + close $f + + switch -glob -- [lindex $s 0] { + #!*sh { set i sh } + #!*perl { set i perl } + #!*python { set i python } + default { error "git-$name is not supported: $s" } + } + + upvar #0 _$i interp + if {![info exists interp]} { + set interp [_which $i] + } + if {$interp eq {}} { + error "git-$name requires $i (not in PATH)" + } + set v [concat [list $interp] [lrange $s 1 end] [list $p]] + } else { + # Assume it is builtin to git somehow and we + # aren't actually able to see a file for it. + # + set v [list $::_git $name] + } + set _git_cmd_path($name) $v + } + 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 {} +} + +proc _lappend_nice {cmd_var} { + global _nice + upvar $cmd_var cmd + + if {![info exists _nice]} { + set _nice [_which nice] + } + if {$_nice ne {}} { + lappend cmd $_nice + } +} + +proc git {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + _trace_exec [concat $opt $cmdp $args] + set result [eval exec $opt $cmdp $args] + if {$::_trace} { + puts stderr "< $result" + } + return $result +} + +proc _open_stdout_stderr {cmd} { + _trace_exec $cmd + if {[catch { + set fd [open [concat [list | ] $cmd] r] + } err]} { + if { [lindex $cmd end] eq {2>@1} + && $err eq {can not find channel named "1"} + } { + # Older versions of Tcl 8.4 don't have this 2>@1 IO + # redirect operator. Fallback to |& cat for those. + # The command was not actually started, so its safe + # to try to start it a second time. + # + set fd [open [concat \ + [list | ] \ + [lrange $cmd 0 end-1] \ + [list |& cat] \ + ] r] + } else { + error $err + } + } + fconfigure $fd -eofchar {} + return $fd +} + +proc git_read {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + --stderr { + lappend args 2>@1 + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + return [_open_stdout_stderr [concat $opt $cmdp $args]] +} + +proc git_write {args} { + set opt [list] + + while {1} { + switch -- [lindex $args 0] { + --nice { + _lappend_nice opt + } + + default { + break + } + + } + + set args [lrange $args 1 end] + } + + set cmdp [_git_cmd [lindex $args 0]] + set args [lrange $args 1 end] + + _trace_exec [concat $opt $cmdp $args] + return [open [concat [list | ] $opt $cmdp $args] w] +} + +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 {} +} + +proc kill_file_process {fd} { + set process [pid $fd] + + catch { + if {[is_Windows]} { + # Use a Cygwin-specific flag to allow killing + # native Windows processes + exec kill -f $process + } else { + exec kill $process + } + } +} + +proc gitattr {path attr default} { + if {[catch {set r [git check-attr $attr -- $path]}]} { + set r unspecified + } else { + set r [join [lrange [split $r :] 2 end] :] + regsub {^ } $r {} r + } + if {$r eq {unspecified}} { + return $default + } + return $r +} + +proc sq {value} { + regsub -all ' $value "'\\''" value + return "'$value'" +} + +proc load_current_branch {} { + global current_branch is_detached + + set fd [open [gitdir HEAD] r] + if {[gets $fd ref] < 1} { + set ref {} + } + close $fd + + set pfx {ref: refs/heads/} + set len [string length $pfx] + if {[string equal -length $len $pfx $ref]} { + # We're on a branch. It might not exist. But + # HEAD looks good enough to be a branch. + # + set current_branch [string range $ref $len end] + set is_detached 0 + } else { + # Assume this is a detached head. + # + set current_branch HEAD + set is_detached 1 + } +} + +auto_load tk_optionMenu +rename tk_optionMenu real__tkOptionMenu +proc tk_optionMenu {w varName args} { + set m [eval real__tkOptionMenu $w $varName $args] + $m configure -font font_ui + $w configure -font font_ui + return $m +} + +proc rmsel_tag {text} { + $text tag conf sel \ + -background [$text cget -background] \ + -foreground [$text cget -foreground] \ + -borderwidth 0 + $text tag conf in_sel -background lightgray + bind $text break + return $text +} + +set root_exists 0 +bind . { + bind . {} + set root_exists 1 +} + +if {[is_Windows]} { + wm iconbitmap . -default $oguilib/git-gui.ico + set ::tk::AlwaysShowSelection 1 + + # Spoof an X11 display for SSH + if {![info exists env(DISPLAY)]} { + set env(DISPLAY) :9999 + } ++} else { ++ catch { ++ image create photo gitlogo -width 16 -height 16 ++ ++ gitlogo put #33CC33 -to 7 0 9 2 ++ gitlogo put #33CC33 -to 4 2 12 4 ++ gitlogo put #33CC33 -to 7 4 9 6 ++ gitlogo put #CC3333 -to 4 6 12 8 ++ gitlogo put gray26 -to 4 9 6 10 ++ gitlogo put gray26 -to 3 10 6 12 ++ gitlogo put gray26 -to 8 9 13 11 ++ gitlogo put gray26 -to 8 11 10 12 ++ gitlogo put gray26 -to 11 11 13 14 ++ gitlogo put gray26 -to 3 12 5 14 ++ gitlogo put gray26 -to 5 13 ++ gitlogo put gray26 -to 10 13 ++ gitlogo put gray26 -to 4 14 12 15 ++ gitlogo put gray26 -to 5 15 11 16 ++ gitlogo redither ++ ++ wm iconphoto . -default gitlogo ++ } +} + +###################################################################### +## +## config defaults + +set cursor_ptr arrow +font create font_diff -family Courier -size 10 +font create font_ui +catch { + label .dummy + eval font configure font_ui [font actual [.dummy cget -font]] + destroy .dummy +} + +font create font_uiitalic +font create font_uibold +font create font_diffbold +font create font_diffitalic + +foreach class {Button Checkbutton Entry Label + Labelframe Listbox Menu Message + Radiobutton Spinbox Text} { + option add *$class.font font_ui +} +unset class + +if {[is_Windows] || [is_MacOSX]} { + option add *Menu.tearOff 0 +} + +if {[is_MacOSX]} { + set M1B M1 + set M1T Cmd +} else { + set M1B Control + set M1T Ctrl +} + +proc bind_button3 {w cmd} { + bind $w $cmd + if {[is_MacOSX]} { + # Mac OS X sends Button-2 on right click through three-button mouse, + # or through trackpad right-clicking (two-finger touch + click). + bind $w $cmd + bind $w $cmd + } +} + +proc apply_config {} { + global repo_config font_descs + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + if {[catch { + set need_weight 1 + foreach {cn cv} $repo_config(gui.$name) { + if {$cn eq {-weight}} { + set need_weight 0 + } + font configure $font $cn $cv + } + if {$need_weight} { + font configure $font -weight normal + } + } err]} { + error_popup [strcat [mc "Invalid font specified in %s:" "gui.$name"] "\n\n$err"] + } + foreach {cn cv} [font configure $font] { + font configure ${font}bold $cn $cv + font configure ${font}italic $cn $cv + } + font configure ${font}bold -weight bold + font configure ${font}italic -slant italic + } +} + +set default_config(branch.autosetupmerge) true +set default_config(merge.tool) {} +set default_config(merge.keepbackup) true +set default_config(merge.diffstat) true +set default_config(merge.summary) false +set default_config(merge.verbosity) 2 +set default_config(user.name) {} +set default_config(user.email) {} + +set default_config(gui.encoding) [encoding system] +set default_config(gui.matchtrackingbranch) false +set default_config(gui.pruneduringfetch) false +set default_config(gui.trustmtime) false +set default_config(gui.fastcopyblame) false +set default_config(gui.copyblamethreshold) 40 +set default_config(gui.blamehistoryctx) 7 +set default_config(gui.diffcontext) 5 +set default_config(gui.commitmsgwidth) 75 +set default_config(gui.newbranchtemplate) {} +set default_config(gui.spellingdictionary) {} +set default_config(gui.fontui) [font configure font_ui] +set default_config(gui.fontdiff) [font configure font_diff] +set font_descs { + {fontui font_ui {mc "Main Font"}} + {fontdiff font_diff {mc "Diff/Console Font"}} +} + +###################################################################### +## +## find git + +set _git [_which git] +if {$_git eq {}} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message [mc "Cannot find git in PATH."] + exit 1 +} + +###################################################################### +## +## version check + +if {[catch {set _git_version [git --version]} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message "Cannot determine Git version: + +$err + +[appname] requires Git 1.5.0 or later." + exit 1 +} +if {![regsub {^git version } $_git_version {} _git_version]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message [strcat [mc "Cannot parse Git version string:"] "\n\n$_git_version"] + exit 1 +} + +set _real_git_version $_git_version +regsub -- {[\-\.]dirty$} $_git_version {} _git_version +regsub {\.[0-9]+\.g[0-9a-f]+$} $_git_version {} _git_version +regsub {\.rc[0-9]+$} $_git_version {} _git_version +regsub {\.GIT$} $_git_version {} _git_version +regsub {\.[a-zA-Z]+\.[0-9]+$} $_git_version {} _git_version + +if {![regexp {^[1-9]+(\.[0-9]+)+$} $_git_version]} { + catch {wm withdraw .} + if {[tk_messageBox \ + -icon warning \ + -type yesno \ + -default no \ + -title "[appname]: warning" \ + -message [mc "Git version cannot be determined. + +%s claims it is version '%s'. + +%s requires at least Git 1.5.0 or later. + +Assume '%s' is version 1.5.0? +" $_git $_real_git_version [appname] $_real_git_version]] eq {yes}} { + set _git_version 1.5.0 + } else { + exit 1 + } +} +unset _real_git_version + +proc git-version {args} { + global _git_version + + switch [llength $args] { + 0 { + return $_git_version + } + + 2 { + set op [lindex $args 0] + set vr [lindex $args 1] + set cm [package vcompare $_git_version $vr] + return [expr $cm $op 0] + } + + 4 { + set type [lindex $args 0] + set name [lindex $args 1] + set parm [lindex $args 2] + set body [lindex $args 3] + + if {($type ne {proc} && $type ne {method})} { + error "Invalid arguments to git-version" + } + if {[llength $body] < 2 || [lindex $body end-1] ne {default}} { + error "Last arm of $type $name must be default" + } + + foreach {op vr cb} [lrange $body 0 end-2] { + if {[git-version $op $vr]} { + return [uplevel [list $type $name $parm $cb]] + } + } + + return [uplevel [list $type $name $parm [lindex $body end]]] + } + + default { + error "git-version >= x" + } + + } +} + +if {[git-version < 1.5]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message "[appname] requires Git 1.5.0 or later. + +You are using [git-version]: + +[git --version]" + exit 1 +} + +###################################################################### +## +## configure our library + +set idx [file join $oguilib tclIndex] +if {[catch {set fd [open $idx r]} err]} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title [mc "git-gui: fatal error"] \ + -message $err + exit 1 +} +if {[gets $fd] eq {# Autogenerated by git-gui Makefile}} { + set idx [list] + while {[gets $fd n] >= 0} { + if {$n ne {} && ![string match #* $n]} { + lappend idx $n + } + } +} else { + set idx {} +} +close $fd + +if {$idx ne {}} { + set loaded [list] + foreach p $idx { + if {[lsearch -exact $loaded $p] >= 0} continue + source [file join $oguilib $p] + lappend loaded $p + } + unset loaded p +} else { + set auto_path [concat [list $oguilib] $auto_path] +} +unset -nocomplain idx fd + +###################################################################### +## +## config file parsing + +git-version proc _parse_config {arr_name args} { + >= 1.5.3 { + upvar $arr_name arr + array unset arr + set buf {} + catch { + set fd_rc [eval \ + [list git_read config] \ + $args \ + [list --null --list]] + fconfigure $fd_rc -translation binary + set buf [read $fd_rc] + close $fd_rc + } + foreach line [split $buf "\0"] { + if {[regexp {^([^\n]+)\n(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend arr($name) $value + } else { + set arr($name) $value + } + } + } + } + default { + upvar $arr_name arr + array unset arr + catch { + set fd_rc [eval [list git_read config --list] $args] + while {[gets $fd_rc line] >= 0} { + if {[regexp {^([^=]+)=(.*)$} $line line name value]} { + if {[is_many_config $name]} { + lappend arr($name) $value + } else { + set arr($name) $value + } + } + } + close $fd_rc + } + } +} + +proc load_config {include_global} { - global repo_config global_config default_config ++ global repo_config global_config system_config default_config + + if {$include_global} { ++ _parse_config system_config --system + _parse_config global_config --global + } + _parse_config repo_config + + foreach name [array names default_config] { ++ if {[catch {set v $system_config($name)}]} { ++ set system_config($name) $default_config($name) ++ } ++ } ++ foreach name [array names system_config] { + if {[catch {set v $global_config($name)}]} { - set global_config($name) $default_config($name) ++ set global_config($name) $system_config($name) + } + if {[catch {set v $repo_config($name)}]} { - set repo_config($name) $default_config($name) ++ set repo_config($name) $system_config($name) + } + } +} + +###################################################################### +## +## feature option selection + +if {[regexp {^git-(.+)$} [file tail $argv0] _junk subcommand]} { + unset _junk +} else { + set subcommand gui +} +if {$subcommand eq {gui.sh}} { + set subcommand gui +} +if {$subcommand eq {gui} && [llength $argv] > 0} { + set subcommand [lindex $argv 0] + set argv [lrange $argv 1 end] +} + +enable_option multicommit +enable_option branch +enable_option transport +disable_option bare + +switch -- $subcommand { +browser - +blame { + enable_option bare + + disable_option multicommit + disable_option branch + disable_option transport +} +citool { + enable_option singlecommit + enable_option retcode + + disable_option multicommit + disable_option branch + disable_option transport + + while {[llength $argv] > 0} { + set a [lindex $argv 0] + switch -- $a { + --amend { + enable_option initialamend + } + --nocommit { + enable_option nocommit + enable_option nocommitmsg + } + --commitmsg { + disable_option nocommitmsg + } + default { + break + } + } + + set argv [lrange $argv 1 end] + } +} +} + +###################################################################### +## +## execution environment + +set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}] + +# Suggest our implementation of askpass, if none is set +if {![info exists env(SSH_ASKPASS)]} { + set env(SSH_ASKPASS) [gitexec git-gui--askpass] +} + +###################################################################### +## +## repository setup + +set picked 0 +if {[catch { + set _gitdir $env(GIT_DIR) + set _prefix {} + }] + && [catch { + set _gitdir [git rev-parse --git-dir] + set _prefix [git rev-parse --show-prefix] + } err]} { + load_config 1 + apply_config + choose_repository::pick + set picked 1 +} +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"] + exit 1 +} +if {$_prefix ne {}} { + regsub -all {[^/]+/} $_prefix ../ cdup + if {[catch {cd $cdup} err]} { + catch {wm withdraw .} + error_popup [strcat [mc "Cannot move to top of working directory:"] "\n\n$err"] + exit 1 + } + unset cdup +} elseif {![is_enabled bare]} { + if {[lindex [file split $_gitdir] end] ne {.git}} { + catch {wm withdraw .} + error_popup [strcat [mc "Cannot use funny .git directory:"] "\n\n$_gitdir"] + exit 1 + } + if {[catch {cd [file dirname $_gitdir]} err]} { + catch {wm withdraw .} + error_popup [strcat [mc "No working directory"] " [file dirname $_gitdir]:\n\n$err"] + exit 1 + } +} +set _reponame [file split [file normalize $_gitdir]] +if {[lindex $_reponame end] eq {.git}} { + set _reponame [lindex $_reponame end-1] +} else { + set _reponame [lindex $_reponame end] +} + +###################################################################### +## +## global init + +set current_diff_path {} +set current_diff_side {} +set diff_actions [list] + +set HEAD {} +set PARENT {} +set MERGE_HEAD [list] +set commit_type {} +set empty_tree {} +set current_branch {} +set is_detached 0 +set current_diff_path {} +set is_3way_diff 0 +set is_conflict_diff 0 +set selected_commit_type new + +set nullid "0000000000000000000000000000000000000000" +set nullid2 "0000000000000000000000000000000000000001" + +###################################################################### +## +## task management + +set rescan_active 0 +set diff_active 0 +set last_clicked {} + +set disable_on_lock [list] +set index_lock_type none + +proc lock_index {type} { + global index_lock_type disable_on_lock + + if {$index_lock_type eq {none}} { + set index_lock_type $type + foreach w $disable_on_lock { + uplevel #0 $w disabled + } + return 1 + } elseif {$index_lock_type eq "begin-$type"} { + set index_lock_type $type + return 1 + } + return 0 +} + +proc unlock_index {} { + global index_lock_type disable_on_lock + + set index_lock_type none + foreach w $disable_on_lock { + uplevel #0 $w normal + } +} + +###################################################################### +## +## status + +proc repository_state {ctvar hdvar mhvar} { + global current_branch + upvar $ctvar ct $hdvar hd $mhvar mh + + set mh [list] + + load_current_branch + if {[catch {set hd [git rev-parse --verify HEAD]}]} { + set hd {} + set ct initial + return + } + + set merge_head [gitdir MERGE_HEAD] + if {[file exists $merge_head]} { + set ct merge + set fd_mh [open $merge_head r] + while {[gets $fd_mh line] >= 0} { + lappend mh $line + } + close $fd_mh + return + } + + set ct normal +} + +proc PARENT {} { + global PARENT empty_tree + + set p [lindex $PARENT 0] + if {$p ne {}} { + return $p + } + if {$empty_tree eq {}} { + set empty_tree [git mktree << {}] + } + return $empty_tree +} + +proc force_amend {} { + global selected_commit_type + global HEAD PARENT MERGE_HEAD commit_type + + repository_state newType newHEAD newMERGE_HEAD + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType + + set selected_commit_type amend + do_select_commit_type +} + +proc rescan {after {honor_trustmtime 1}} { + global HEAD PARENT MERGE_HEAD commit_type + global ui_index ui_workdir ui_comm + global rescan_active file_states + global repo_config + + if {$rescan_active > 0 || ![lock_index read]} return + + repository_state newType newHEAD newMERGE_HEAD + if {[string match amend* $commit_type] + && $newType eq {normal} + && $newHEAD eq $HEAD} { + } else { + set HEAD $newHEAD + set PARENT $newHEAD + set MERGE_HEAD $newMERGE_HEAD + set commit_type $newType + } + + array unset file_states + + if {!$::GITGUI_BCK_exists && + (![$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 {[run_prepare_commit_msg_hook]} { + } elseif {[load_message MERGE_MSG]} { + } elseif {[load_message SQUASH_MSG]} { + } + $ui_comm edit reset + $ui_comm edit modified false + } + + if {$honor_trustmtime && $repo_config(gui.trustmtime) eq {true}} { + rescan_stage2 {} $after + } else { + set rescan_active 1 + ui_status [mc "Refreshing file status..."] + set fd_rf [git_read update-index \ + -q \ + --unmerged \ + --ignore-missing \ + --refresh \ + ] + fconfigure $fd_rf -blocking 0 -translation binary + fileevent $fd_rf readable \ + [list rescan_stage2 $fd_rf $after] + } +} + +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 rescan_stage2 {fd after} { + global rescan_active buf_rdi buf_rdf buf_rlo + + if {$fd ne {}} { + read $fd + if {![eof $fd]} return + 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" + } + + set buf_rdi {} + set buf_rdf {} + set buf_rlo {} + + set rescan_active 3 + 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] +} + +proc load_message {file} { + global ui_comm + + set f [gitdir $file] + if {[file isfile $f]} { + if {[catch {set fd [open $f r]}]} { + return 0 + } + fconfigure $fd -eofchar {} + set content [string trim [read $fd]] + close $fd + regsub -all -line {[ \r\t]+$} $content {} content + $ui_comm delete 0.0 end + $ui_comm insert end $content + return 1 + } + return 0 +} + +proc run_prepare_commit_msg_hook {} { + global pch_error + + # 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. + + set fd_pcm [open [gitdir PREPARE_COMMIT_MSG] a] + + if {[file isfile [gitdir MERGE_MSG]]} { + set pcm_source "merge" + set fd_mm [open [gitdir MERGE_MSG] r] + puts -nonewline $fd_pcm [read $fd_mm] + close $fd_mm + } elseif {[file isfile [gitdir SQUASH_MSG]]} { + set pcm_source "squash" + set fd_sm [open [gitdir SQUASH_MSG] r] + puts -nonewline $fd_pcm [read $fd_sm] + close $fd_sm + } else { + set pcm_source "" + } + + close $fd_pcm + + set fd_ph [githook_read prepare-commit-msg \ + [gitdir PREPARE_COMMIT_MSG] $pcm_source] + if {$fd_ph eq {}} { + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return 0; + } + + ui_status [mc "Calling prepare-commit-msg hook..."] + set pch_error {} + + fconfigure $fd_ph -blocking 0 -translation binary -eofchar {} + fileevent $fd_ph readable \ + [list prepare_commit_msg_hook_wait $fd_ph] + + return 1; +} + +proc prepare_commit_msg_hook_wait {fd_ph} { + global pch_error + + append pch_error [read $fd_ph] + fconfigure $fd_ph -blocking 1 + if {[eof $fd_ph]} { + if {[catch {close $fd_ph}]} { + ui_status [mc "Commit declined by prepare-commit-msg hook."] + hook_failed_popup prepare-commit-msg $pch_error + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + exit 1 + } else { + load_message PREPARE_COMMIT_MSG + } + set pch_error {} + catch {file delete [gitdir PREPARE_COMMIT_MSG]} + return + } + fconfigure $fd_ph -blocking 0 + catch {file delete [gitdir PREPARE_COMMIT_MSG]} +} + +proc read_diff_index {fd after} { + global buf_rdi + + append buf_rdi [read $fd] + set c 0 + set n [string length $buf_rdi] + while {$c < $n} { + set z1 [string first "\0" $buf_rdi $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdi $z1] + if {$z2 == -1} break + + incr c + set i [split [string range $buf_rdi $c [expr {$z1 - 2}]] { }] + set p [string range $buf_rdi $z1 [expr {$z2 - 1}]] + merge_state \ + [encoding convertfrom $p] \ + [lindex $i 4]? \ + [list [lindex $i 0] [lindex $i 2]] \ + [list] + set c $z2 + incr c + } + if {$c < $n} { + set buf_rdi [string range $buf_rdi $c end] + } else { + set buf_rdi {} + } + + rescan_done $fd buf_rdi $after +} + +proc read_diff_files {fd after} { + global buf_rdf + + append buf_rdf [read $fd] + set c 0 + set n [string length $buf_rdf] + while {$c < $n} { + set z1 [string first "\0" $buf_rdf $c] + if {$z1 == -1} break + incr z1 + set z2 [string first "\0" $buf_rdf $z1] + if {$z2 == -1} break + + incr c + set i [split [string range $buf_rdf $c [expr {$z1 - 2}]] { }] + set p [string range $buf_rdf $z1 [expr {$z2 - 1}]] + merge_state \ + [encoding convertfrom $p] \ + ?[lindex $i 4] \ + [list] \ + [list [lindex $i 0] [lindex $i 2]] + set c $z2 + incr c + } + if {$c < $n} { + set buf_rdf [string range $buf_rdf $c end] + } else { + set buf_rdf {} + } + + rescan_done $fd buf_rdf $after +} + +proc read_ls_others {fd after} { + global buf_rlo + + append buf_rlo [read $fd] + set pck [split $buf_rlo "\0"] + set buf_rlo [lindex $pck end] + foreach p [lrange $pck 0 end-1] { + set p [encoding convertfrom $p] + if {[string index $p end] eq {/}} { + set p [string range $p 0 end-1] + } + merge_state $p ?O + } + rescan_done $fd buf_rlo $after +} + +proc rescan_done {fd buf after} { + global rescan_active current_diff_path + global file_states repo_config + upvar $buf to_clear + + if {![eof $fd]} return + set to_clear {} + close $fd + if {[incr rescan_active -1] > 0} return + + prune_selection + unlock_index + display_all_files - if {$current_diff_path ne {}} reshow_diff - if {$current_diff_path eq {}} select_first_diff - - uplevel #0 $after ++ if {$current_diff_path ne {}} { reshow_diff $after } ++ if {$current_diff_path eq {}} { select_first_diff $after } +} + +proc prune_selection {} { + global file_states selected_paths + + foreach path [array names selected_paths] { + if {[catch {set still_here $file_states($path)}]} { + unset selected_paths($path) + } + } +} + +###################################################################### +## +## ui helpers + +proc mapicon {w state path} { + global all_icons + + if {[catch {set r $all_icons($state$w)}]} { + puts "error: no icon for $w state={$state} $path" + return file_plain + } + return $r +} + +proc mapdesc {state path} { + global all_descs + + if {[catch {set r $all_descs($state)}]} { + puts "error: no desc for state={$state} $path" + return $state + } + return $r +} + +proc ui_status {msg} { + global main_status + if {[info exists main_status]} { + $main_status show $msg + } +} + +proc ui_ready {{test {}}} { + global main_status + if {[info exists main_status]} { + $main_status show [mc "Ready."] $test + } +} + +proc escape_path {path} { + regsub -all {\\} $path "\\\\" path + regsub -all "\n" $path "\\n" path + return $path +} + +proc short_path {path} { + return [escape_path [lindex [file split $path] end]] +} + +set next_icon_id 0 +set null_sha1 [string repeat 0 40] + +proc merge_state {path new_state {head_info {}} {index_info {}}} { + global file_states next_icon_id null_sha1 + + set s0 [string index $new_state 0] + set s1 [string index $new_state 1] + + if {[catch {set info $file_states($path)}]} { + set state __ + set icon n[incr next_icon_id] + } else { + set state [lindex $info 0] + set icon [lindex $info 1] + if {$head_info eq {}} {set head_info [lindex $info 2]} + if {$index_info eq {}} {set index_info [lindex $info 3]} + } + + if {$s0 eq {?}} {set s0 [string index $state 0]} \ + elseif {$s0 eq {_}} {set s0 _} + + if {$s1 eq {?}} {set s1 [string index $state 1]} \ + elseif {$s1 eq {_}} {set s1 _} + + if {$s0 eq {A} && $s1 eq {_} && $head_info eq {}} { + set head_info [list 0 $null_sha1] + } elseif {$s0 ne {_} && [string index $state 0] eq {_} + && $head_info eq {}} { + set head_info $index_info + } + + set file_states($path) [list $s0$s1 $icon \ + $head_info $index_info \ + ] + return $state +} + +proc display_file_helper {w path icon_name old_m new_m} { + global file_lists + + if {$new_m eq {_}} { + set lno [lsearch -sorted -exact $file_lists($w) $path] + if {$lno >= 0} { + set file_lists($w) [lreplace $file_lists($w) $lno $lno] + incr lno + $w conf -state normal + $w delete $lno.0 [expr {$lno + 1}].0 + $w conf -state disabled + } + } elseif {$old_m eq {_} && $new_m ne {_}} { + lappend file_lists($w) $path + set file_lists($w) [lsort -unique $file_lists($w)] + set lno [lsearch -sorted -exact $file_lists($w) $path] + incr lno + $w conf -state normal + $w image create $lno.0 \ + -align center -padx 5 -pady 1 \ + -name $icon_name \ + -image [mapicon $w $new_m $path] + $w insert $lno.1 "[escape_path $path]\n" + $w conf -state disabled + } elseif {$old_m ne $new_m} { + $w conf -state normal + $w image conf $icon_name -image [mapicon $w $new_m $path] + $w conf -state disabled + } +} + +proc display_file {path state} { + global file_states selected_paths + global ui_index ui_workdir + + set old_m [merge_state $path $state] + set s $file_states($path) + set new_m [lindex $s 0] + set icon_name [lindex $s 1] + + set o [string index $old_m 0] + set n [string index $new_m 0] + if {$o eq {U}} { + set o _ + } + if {$n eq {U}} { + set n _ + } + display_file_helper $ui_index $path $icon_name $o $n + + if {[string index $old_m 0] eq {U}} { + set o U + } else { + set o [string index $old_m 1] + } + if {[string index $new_m 0] eq {U}} { + set n U + } else { + set n [string index $new_m 1] + } + display_file_helper $ui_workdir $path $icon_name $o $n + + if {$new_m eq {__}} { + unset file_states($path) + catch {unset selected_paths($path)} + } +} + +proc display_all_files_helper {w path icon_name m} { + global file_lists + + lappend file_lists($w) $path + set lno [expr {[lindex [split [$w index end] .] 0] - 1}] + $w image create end \ + -align center -padx 5 -pady 1 \ + -name $icon_name \ + -image [mapicon $w $m $path] + $w insert end "[escape_path $path]\n" +} + +proc display_all_files {} { + global ui_index ui_workdir + global file_states file_lists + global last_clicked + + $ui_index conf -state normal + $ui_workdir conf -state normal + + $ui_index delete 0.0 end + $ui_workdir delete 0.0 end + set last_clicked {} + + set file_lists($ui_index) [list] + set file_lists($ui_workdir) [list] + + foreach path [lsort [array names file_states]] { + set s $file_states($path) + set m [lindex $s 0] + set icon_name [lindex $s 1] + + set s [string index $m 0] + if {$s ne {U} && $s ne {_}} { + display_all_files_helper $ui_index $path \ + $icon_name $s + } + + if {[string index $m 0] eq {U}} { + set s U + } else { + set s [string index $m 1] + } + if {$s ne {_}} { + display_all_files_helper $ui_workdir $path \ + $icon_name $s + } + } + + $ui_index conf -state disabled + $ui_workdir conf -state disabled +} + +###################################################################### +## +## icons + +set filemask { +#define mask_width 14 +#define mask_height 15 +static unsigned char mask_bits[] = { + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f, + 0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x1f}; +} + +image create bitmap file_plain -background white -foreground black -data { +#define plain_width 14 +#define plain_height 15 +static unsigned char plain_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, 0x02, 0x10, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_mod -background white -foreground blue -data { +#define mod_width 14 +#define mod_height 15 +static unsigned char mod_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_fulltick -background white -foreground "#007000" -data { +#define file_fulltick_width 14 +#define file_fulltick_height 15 +static unsigned char file_fulltick_bits[] = { + 0xfe, 0x01, 0x02, 0x1a, 0x02, 0x0c, 0x02, 0x0c, 0x02, 0x16, 0x02, 0x16, + 0x02, 0x13, 0x00, 0x13, 0x86, 0x11, 0x8c, 0x11, 0xd8, 0x10, 0xf2, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_parttick -background white -foreground "#005050" -data { +#define parttick_width 14 +#define parttick_height 15 +static unsigned char parttick_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x7a, 0x05, 0x02, 0x09, 0x7a, 0x1f, 0x02, 0x10, + 0x7a, 0x14, 0x02, 0x16, 0x02, 0x13, 0x8a, 0x11, 0xda, 0x10, 0x72, 0x10, + 0x22, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_question -background white -foreground black -data { +#define file_question_width 14 +#define file_question_height 15 +static unsigned char file_question_bits[] = { + 0xfe, 0x01, 0x02, 0x02, 0xe2, 0x04, 0xf2, 0x09, 0x1a, 0x1b, 0x0a, 0x13, + 0x82, 0x11, 0xc2, 0x10, 0x62, 0x10, 0x62, 0x10, 0x02, 0x10, 0x62, 0x10, + 0x62, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_removed -background white -foreground red -data { +#define file_removed_width 14 +#define file_removed_height 15 +static unsigned char file_removed_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x02, 0x05, 0x02, 0x09, 0x02, 0x1f, 0x02, 0x10, + 0x1a, 0x16, 0x32, 0x13, 0xe2, 0x11, 0xc2, 0x10, 0xe2, 0x11, 0x32, 0x13, + 0x1a, 0x16, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_merge -background white -foreground blue -data { +#define file_merge_width 14 +#define file_merge_height 15 +static unsigned char file_merge_bits[] = { + 0xfe, 0x01, 0x02, 0x03, 0x62, 0x05, 0x62, 0x09, 0x62, 0x1f, 0x62, 0x10, + 0xfa, 0x11, 0xf2, 0x10, 0x62, 0x10, 0x02, 0x10, 0xfa, 0x17, 0x02, 0x10, + 0xfa, 0x17, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +image create bitmap file_statechange -background white -foreground green -data { +#define file_merge_width 14 +#define file_merge_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, + 0x02, 0x10, 0x02, 0x10, 0xfe, 0x1f}; +} -maskdata $filemask + +set ui_index .vpane.files.index.list +set ui_workdir .vpane.files.workdir.list + +set all_icons(_$ui_index) file_plain +set all_icons(A$ui_index) file_fulltick +set all_icons(M$ui_index) file_fulltick +set all_icons(D$ui_index) file_removed +set all_icons(U$ui_index) file_merge +set all_icons(T$ui_index) file_statechange + +set all_icons(_$ui_workdir) file_plain +set all_icons(M$ui_workdir) file_mod +set all_icons(D$ui_workdir) file_question +set all_icons(U$ui_workdir) file_merge +set all_icons(O$ui_workdir) file_plain +set all_icons(T$ui_workdir) file_statechange + +set max_status_desc 0 +foreach i { + {__ {mc "Unmodified"}} + + {_M {mc "Modified, not staged"}} + {M_ {mc "Staged for commit"}} + {MM {mc "Portions staged for commit"}} + {MD {mc "Staged for commit, missing"}} + + {_T {mc "File type changed, not staged"}} + {T_ {mc "File type changed, staged"}} + + {_O {mc "Untracked, not staged"}} + {A_ {mc "Staged for commit"}} + {AM {mc "Portions staged for commit"}} + {AD {mc "Staged for commit, missing"}} + + {_D {mc "Missing"}} + {D_ {mc "Staged for removal"}} + {DO {mc "Staged for removal, still present"}} + + {_U {mc "Requires merge resolution"}} + {U_ {mc "Requires merge resolution"}} + {UU {mc "Requires merge resolution"}} + {UM {mc "Requires merge resolution"}} + {UD {mc "Requires merge resolution"}} + {UT {mc "Requires merge resolution"}} + } { + set text [eval [lindex $i 1]] + if {$max_status_desc < [string length $text]} { + set max_status_desc [string length $text] + } + set all_descs([lindex $i 0]) $text +} +unset i + +###################################################################### +## +## util + +proc scrollbar2many {list mode args} { + foreach w $list {eval $w $mode $args} +} + +proc many2scrollbar {list mode sb top bottom} { + $sb set $top $bottom + foreach w $list {$w $mode moveto $top} +} + +proc incr_font_size {font {amt 1}} { + set sz [font configure $font -size] + incr sz $amt + font configure $font -size $sz + font configure ${font}bold -size $sz + font configure ${font}italic -size $sz +} + +###################################################################### +## +## ui commands + +set starting_gitk_msg [mc "Starting gitk... please wait..."] + +proc do_gitk {revs} { + # -- Always start gitk through whatever we were loaded with. This + # lets us bypass using shell process on Windows systems. + # + set exe [_which gitk -script] + set cmd [list [info nameofexecutable] $exe] + if {$exe eq {}} { + error_popup [mc "Couldn't find gitk in PATH"] + } else { + global env + + if {[info exists env(GIT_DIR)]} { + set old_GIT_DIR $env(GIT_DIR) + } else { + set old_GIT_DIR {} + } + + set pwd [pwd] + cd [file dirname [gitdir]] + set env(GIT_DIR) [file tail [gitdir]] + + eval exec $cmd $revs & + + if {$old_GIT_DIR eq {}} { + unset env(GIT_DIR) + } else { + set env(GIT_DIR) $old_GIT_DIR + } + cd $pwd + + ui_status $::starting_gitk_msg + after 10000 { + ui_ready $starting_gitk_msg + } + } +} + +proc do_explore {} { + set explorer {} + if {[is_Cygwin] || [is_Windows]} { + set explorer "explorer.exe" + } elseif {[is_MacOSX]} { + set explorer "open" + } else { + # freedesktop.org-conforming system is our best shot + set explorer "xdg-open" + } + eval exec $explorer [file dirname [gitdir]] & +} + +set is_quitting 0 +set ret_code 1 + +proc terminate_me {win} { + global ret_code + if {$win ne {.}} return + exit $ret_code +} + +proc do_quit {{rc {1}}} { + global ui_comm is_quitting repo_config commit_type + global GITGUI_BCK_exists GITGUI_BCK_i + global ui_comm_spell + global ret_code + + if {$is_quitting} return + set is_quitting 1 + + if {[winfo exists $ui_comm]} { + # -- Stash our current commit buffer. + # + set save [gitdir GITGUI_MSG] + if {$GITGUI_BCK_exists && ![$ui_comm edit modified]} { + file rename -force [gitdir GITGUI_BCK] $save + set GITGUI_BCK_exists 0 + } else { + 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]) + && $msg ne {}} { + catch { + set fd [open $save w] + puts -nonewline $fd $msg + close $fd + } + } else { + catch {file delete $save} + } + } + + # -- Cancel our spellchecker if its running. + # + if {[info exists ui_comm_spell]} { + $ui_comm_spell stop + } + + # -- Remove our editor backup, its not needed. + # + after cancel $GITGUI_BCK_i + if {$GITGUI_BCK_exists} { + catch {file delete [gitdir GITGUI_BCK]} + } + + # -- Stash our current window geometry into this repository. + # + set cfg_geometry [list] + lappend cfg_geometry [wm geometry .] + lappend cfg_geometry [lindex [.vpane sash coord 0] 0] + lappend cfg_geometry [lindex [.vpane.files sash coord 0] 1] + if {[catch {set rc_geometry $repo_config(gui.geometry)}]} { + set rc_geometry {} + } + if {$cfg_geometry ne $rc_geometry} { + catch {git config gui.geometry $cfg_geometry} + } + } + + set ret_code $rc + destroy . +} + +proc do_rescan {} { + rescan ui_ready +} + +proc ui_do_rescan {} { - rescan {force_first_diff; ui_ready} ++ rescan {force_first_diff ui_ready} +} + +proc do_commit {} { + commit_tree +} + - proc next_diff {} { ++proc next_diff {{after {}}} { + global next_diff_p next_diff_w next_diff_i - show_diff $next_diff_p $next_diff_w {} ++ show_diff $next_diff_p $next_diff_w {} {} $after +} + +proc find_anchor_pos {lst name} { + set lid [lsearch -sorted -exact $lst $name] + + if {$lid == -1} { + set lid 0 + foreach lname $lst { + if {$lname >= $name} break + incr lid + } + } + + return $lid +} + +proc find_file_from {flist idx delta path mmask} { + global file_states + + set len [llength $flist] + while {$idx >= 0 && $idx < $len} { + set name [lindex $flist $idx] + + if {$name ne $path && [info exists file_states($name)]} { + set state [lindex $file_states($name) 0] + + if {$mmask eq {} || [regexp $mmask $state]} { + return $idx + } + } + + incr idx $delta + } + + return {} +} + +proc find_next_diff {w path {lno {}} {mmask {}}} { + global next_diff_p next_diff_w next_diff_i + global file_lists ui_index ui_workdir + + set flist $file_lists($w) + if {$lno eq {}} { + set lno [find_anchor_pos $flist $path] + } else { + incr lno -1 + } + + if {$mmask ne {} && ![regexp {(^\^)|(\$$)} $mmask]} { + if {$w eq $ui_index} { + set mmask "^$mmask" + } else { + set mmask "$mmask\$" + } + } + + set idx [find_file_from $flist $lno 1 $path $mmask] + if {$idx eq {}} { + incr lno -1 + set idx [find_file_from $flist $lno -1 $path $mmask] + } + + if {$idx ne {}} { + set next_diff_w $w + set next_diff_p [lindex $flist $idx] + set next_diff_i [expr {$idx+1}] + return 1 + } else { + return 0 + } +} + +proc next_diff_after_action {w path {lno {}} {mmask {}}} { + global current_diff_path + + if {$path ne $current_diff_path} { + return {} + } elseif {[find_next_diff $w $path $lno $mmask]} { + return {next_diff;} + } else { + return {reshow_diff;} + } +} + - proc select_first_diff {} { ++proc select_first_diff {after} { + global ui_workdir + + if {[find_next_diff $ui_workdir {} 1 {^_?U}] || + [find_next_diff $ui_workdir {} 1 {[^O]$}]} { - next_diff ++ next_diff $after ++ } else { ++ uplevel #0 $after + } +} + - proc force_first_diff {} { - global current_diff_path ++proc force_first_diff {after} { ++ global ui_workdir current_diff_path file_states + + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] ++ } else { ++ set state {OO} ++ } + - if {[string index $state 1] ne {O}} return ++ set reselect 0 ++ if {[string first {U} $state] >= 0} { ++ # Already a conflict, do nothing ++ } elseif {[find_next_diff $ui_workdir $current_diff_path {} {^_?U}]} { ++ set reselect 1 ++ } elseif {[string index $state 1] ne {O}} { ++ # Already a diff & no conflicts, do nothing ++ } elseif {[find_next_diff $ui_workdir $current_diff_path {} {[^O]$}]} { ++ set reselect 1 + } + - select_first_diff ++ if {$reselect} { ++ next_diff $after ++ } else { ++ uplevel #0 $after ++ } +} + +proc toggle_or_diff {w x y} { + global file_states file_lists current_diff_path ui_index ui_workdir + global last_clicked selected_paths + + set pos [split [$w index @$x,$y] .] + set lno [lindex $pos 0] + set col [lindex $pos 1] + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + set last_clicked [list $w $lno] + array unset selected_paths + $ui_index tag remove in_sel 0.0 end + $ui_workdir tag remove in_sel 0.0 end + + # Determine the state of the file + if {[info exists file_states($path)]} { + set state [lindex $file_states($path) 0] + } else { + set state {__} + } + + # Restage the file, or simply show the diff + if {$col == 0 && $y > 1} { + # Conflicts need special handling + if {[string first {U} $state] >= 0} { + # $w must always be $ui_workdir, but... + if {$w ne $ui_workdir} { set lno {} } + merge_stage_workdir $path $lno + return + } + + if {[string index $state 1] eq {O}} { + set mmask {} + } else { + set mmask {[^O]} + } + + set after [next_diff_after_action $w $path $lno $mmask] + + if {$w eq $ui_index} { + update_indexinfo \ + "Unstaging [short_path $path] from commit" \ + [list $path] \ + [concat $after [list ui_ready]] + } elseif {$w eq $ui_workdir} { + update_index \ + "Adding [short_path $path]" \ + [list $path] \ + [concat $after [list ui_ready]] + } + } else { + show_diff $path $w $lno + } +} + +proc add_one_to_selection {w x y} { + global file_lists last_clicked selected_paths + + set lno [lindex [split [$w index @$x,$y] .] 0] + set path [lindex $file_lists($w) [expr {$lno - 1}]] + if {$path eq {}} { + set last_clicked {} + return + } + + if {$last_clicked ne {} + && [lindex $last_clicked 0] ne $w} { + array unset selected_paths + [lindex $last_clicked 0] tag remove in_sel 0.0 end + } + + set last_clicked [list $w $lno] + if {[catch {set in_sel $selected_paths($path)}]} { + set in_sel 0 + } + if {$in_sel} { + unset selected_paths($path) + $w tag remove in_sel $lno.0 [expr {$lno + 1}].0 + } else { + set selected_paths($path) 1 + $w tag add in_sel $lno.0 [expr {$lno + 1}].0 + } +} + +proc add_range_to_selection {w x y} { + global file_lists last_clicked selected_paths + + if {[lindex $last_clicked 0] ne $w} { + toggle_or_diff $w $x $y + return + } + + set lno [lindex [split [$w index @$x,$y] .] 0] + set lc [lindex $last_clicked 1] + if {$lc < $lno} { + set begin $lc + set end $lno + } else { + set begin $lno + set end $lc + } + + foreach path [lrange $file_lists($w) \ + [expr {$begin - 1}] \ + [expr {$end - 1}]] { + set selected_paths($path) 1 + } + $w tag add in_sel $begin.0 [expr {$end + 1}].0 +} + +proc show_more_context {} { + global repo_config + if {$repo_config(gui.diffcontext) < 99} { + incr repo_config(gui.diffcontext) + reshow_diff + } +} + +proc show_less_context {} { + global repo_config + if {$repo_config(gui.diffcontext) > 1} { + incr repo_config(gui.diffcontext) -1 + reshow_diff + } +} + +###################################################################### +## +## ui construction + +load_config 0 +apply_config +set ui_comm {} + +# -- Menu Bar +# +menu .mbar -tearoff 0 +.mbar add cascade -label [mc Repository] -menu .mbar.repository +.mbar add cascade -label [mc Edit] -menu .mbar.edit +if {[is_enabled branch]} { + .mbar add cascade -label [mc Branch] -menu .mbar.branch +} +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + .mbar add cascade -label [mc Commit@@noun] -menu .mbar.commit +} +if {[is_enabled transport]} { + .mbar add cascade -label [mc Merge] -menu .mbar.merge + .mbar add cascade -label [mc Remote] -menu .mbar.remote +} ++if {[is_enabled multicommit] || [is_enabled singlecommit]} { ++ .mbar add cascade -label [mc Tools] -menu .mbar.tools ++} +. configure -menu .mbar + +# -- Repository Menu +# +menu .mbar.repository + +.mbar.repository add command \ + -label [mc "Explore Working Copy"] \ + -command {do_explore} +.mbar.repository add separator + +.mbar.repository add command \ + -label [mc "Browse Current Branch's Files"] \ + -command {browser::new $current_branch} +set ui_browse_current [.mbar.repository index last] +.mbar.repository add command \ + -label [mc "Browse Branch Files..."] \ + -command browser_open::dialog +.mbar.repository add separator + +.mbar.repository add command \ + -label [mc "Visualize Current Branch's History"] \ + -command {do_gitk $current_branch} +set ui_visualize_current [.mbar.repository index last] +.mbar.repository add command \ + -label [mc "Visualize All Branch History"] \ + -command {do_gitk --all} +.mbar.repository add separator + +proc current_branch_write {args} { + global current_branch + .mbar.repository entryconf $::ui_browse_current \ + -label [mc "Browse %s's Files" $current_branch] + .mbar.repository entryconf $::ui_visualize_current \ + -label [mc "Visualize %s's History" $current_branch] +} +trace add variable current_branch write current_branch_write + +if {[is_enabled multicommit]} { + .mbar.repository add command -label [mc "Database Statistics"] \ + -command do_stats + + .mbar.repository add command -label [mc "Compress Database"] \ + -command do_gc + + .mbar.repository add command -label [mc "Verify Database"] \ + -command do_fsck_objects + + .mbar.repository add separator + + if {[is_Cygwin]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_cygwin_shortcut + } elseif {[is_Windows]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_windows_shortcut + } elseif {[is_MacOSX]} { + .mbar.repository add command \ + -label [mc "Create Desktop Icon"] \ + -command do_macosx_app + } +} + +if {[is_MacOSX]} { + proc ::tk::mac::Quit {args} { do_quit } +} else { + .mbar.repository add command -label [mc Quit] \ + -command do_quit \ + -accelerator $M1T-Q +} + +# -- Edit Menu +# +menu .mbar.edit +.mbar.edit add command -label [mc Undo] \ + -command {catch {[focus] edit undo}} \ + -accelerator $M1T-Z +.mbar.edit add command -label [mc Redo] \ + -command {catch {[focus] edit redo}} \ + -accelerator $M1T-Y +.mbar.edit add separator +.mbar.edit add command -label [mc Cut] \ + -command {catch {tk_textCut [focus]}} \ + -accelerator $M1T-X +.mbar.edit add command -label [mc Copy] \ + -command {catch {tk_textCopy [focus]}} \ + -accelerator $M1T-C +.mbar.edit add command -label [mc Paste] \ + -command {catch {tk_textPaste [focus]; [focus] see insert}} \ + -accelerator $M1T-V +.mbar.edit add command -label [mc Delete] \ + -command {catch {[focus] delete sel.first sel.last}} \ + -accelerator Del +.mbar.edit add separator +.mbar.edit add command -label [mc "Select All"] \ + -command {catch {[focus] tag add sel 0.0 end}} \ + -accelerator $M1T-A + +# -- Branch Menu +# +if {[is_enabled branch]} { + menu .mbar.branch + + .mbar.branch add command -label [mc "Create..."] \ + -command branch_create::dialog \ + -accelerator $M1T-N + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Checkout..."] \ + -command branch_checkout::dialog \ + -accelerator $M1T-O + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Rename..."] \ + -command branch_rename::dialog + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Delete..."] \ + -command branch_delete::dialog + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] + + .mbar.branch add command -label [mc "Reset..."] \ + -command merge::reset_hard + lappend disable_on_lock [list .mbar.branch entryconf \ + [.mbar.branch index last] -state] +} + +# -- Commit Menu +# +proc commit_btn_caption {} { + if {[is_enabled nocommit]} { + return [mc "Done"] + } else { + return [mc Commit@@verb] + } +} + +if {[is_enabled multicommit] || [is_enabled singlecommit]} { + menu .mbar.commit + + if {![is_enabled nocommit]} { + .mbar.commit add radiobutton \ + -label [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add radiobutton \ + -label [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add separator + } + + .mbar.commit add command -label [mc Rescan] \ + -command ui_do_rescan \ + -accelerator F5 + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Stage To Commit"] \ + -command do_add_selection \ + -accelerator $M1T-T + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Stage Changed Files To Commit"] \ + -command do_add_all \ + -accelerator $M1T-I + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Unstage From Commit"] \ + -command do_unstage_selection + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add command -label [mc "Revert Changes"] \ + -command do_revert_selection + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] + + .mbar.commit add separator + + .mbar.commit add command -label [mc "Show Less Context"] \ + -command show_less_context \ + -accelerator $M1T-\- + + .mbar.commit add command -label [mc "Show More Context"] \ + -command show_more_context \ + -accelerator $M1T-= + + .mbar.commit add separator + + if {![is_enabled nocommitmsg]} { + .mbar.commit add command -label [mc "Sign Off"] \ + -command do_signoff \ + -accelerator $M1T-S + } + + .mbar.commit add command -label [commit_btn_caption] \ + -command do_commit \ + -accelerator $M1T-Return + lappend disable_on_lock \ + [list .mbar.commit entryconf [.mbar.commit index last] -state] +} + +# -- Merge Menu +# +if {[is_enabled branch]} { + menu .mbar.merge + .mbar.merge add command -label [mc "Local Merge..."] \ + -command merge::dialog \ + -accelerator $M1T-M + lappend disable_on_lock \ + [list .mbar.merge entryconf [.mbar.merge index last] -state] + .mbar.merge add command -label [mc "Abort Merge..."] \ + -command merge::reset_hard + lappend disable_on_lock \ + [list .mbar.merge entryconf [.mbar.merge index last] -state] +} + +# -- Transport Menu +# +if {[is_enabled transport]} { + menu .mbar.remote + + .mbar.remote add command \ + -label [mc "Add..."] \ + -command remote_add::dialog \ + -accelerator $M1T-A + .mbar.remote add command \ + -label [mc "Push..."] \ + -command do_push_anywhere \ + -accelerator $M1T-P + .mbar.remote add command \ + -label [mc "Delete Branch..."] \ + -command remote_branch_delete::dialog +} + +if {[is_MacOSX]} { + # -- Apple Menu (Mac OS X only) + # + .mbar add cascade -label Apple -menu .mbar.apple + menu .mbar.apple + + .mbar.apple add command -label [mc "About %s" [appname]] \ + -command do_about + .mbar.apple add separator + .mbar.apple add command \ + -label [mc "Preferences..."] \ + -command do_options \ + -accelerator $M1T-, + bind . <$M1B-,> do_options +} else { + # -- Edit Menu + # + .mbar.edit add separator + .mbar.edit add command -label [mc "Options..."] \ + -command do_options +} + ++# -- Tools Menu ++# ++if {[is_enabled multicommit] || [is_enabled singlecommit]} { ++ set tools_menubar .mbar.tools ++ menu $tools_menubar ++ $tools_menubar add separator ++ $tools_menubar add command -label [mc "Add..."] -command tools_add::dialog ++ $tools_menubar add command -label [mc "Remove..."] -command tools_remove::dialog ++ set tools_tailcnt 3 ++ if {[array names repo_config guitool.*.cmd] ne {}} { ++ tools_populate_all ++ } ++} ++ +# -- Help Menu +# +.mbar add cascade -label [mc Help] -menu .mbar.help +menu .mbar.help + +if {![is_MacOSX]} { + .mbar.help add command -label [mc "About %s" [appname]] \ + -command do_about +} + + +set doc_path [file dirname [gitexec]] +set doc_path [file join $doc_path Documentation 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/} +} + +proc start_browser {url} { + git "web--browse" $url +} + +.mbar.help add command -label [mc "Online Documentation"] \ + -command [list start_browser $doc_url] + +.mbar.help add command -label [mc "Show SSH Key"] \ + -command do_ssh_key + +unset doc_path doc_url + +# -- Standard bindings +# +wm protocol . WM_DELETE_WINDOW do_quit +bind all <$M1B-Key-q> do_quit +bind all <$M1B-Key-Q> do_quit +bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} +bind all <$M1B-Key-W> {destroy [winfo toplevel %W]} + +set subcommand_args {} +proc usage {} { + puts stderr "usage: $::argv0 $::subcommand $::subcommand_args" + exit 1 +} + +# -- Not a normal commit type invocation? Do that instead! +# +switch -- $subcommand { +browser - +blame { + if {$subcommand eq "blame"} { + set subcommand_args {[--line=] rev? path} + } else { + set subcommand_args {rev? path} + } + if {$argv eq {}} usage + set head {} + set path {} + set jump_spec {} + set is_path 0 + foreach a $argv { + if {$is_path || [file exists $_prefix$a]} { + if {$path ne {}} usage + set path $_prefix$a + break + } elseif {$a eq {--}} { + if {$path ne {}} { + if {$head ne {}} usage + set head $path + set path {} + } + set is_path 1 + } elseif {[regexp {^--line=(\d+)$} $a a lnum]} { + if {$jump_spec ne {} || $head ne {}} usage + set jump_spec [list $lnum] + } elseif {$head eq {}} { + if {$head ne {}} usage + set head $a + set is_path 1 + } else { + usage + } + } + unset is_path + + if {$head ne {} && $path eq {}} { + set path $_prefix$head + set head {} + } + + if {$head eq {}} { + load_current_branch + } else { + if {[regexp {^[0-9a-f]{1,39}$} $head]} { + if {[catch { + set head [git rev-parse --verify $head] + } err]} { + puts stderr $err + exit 1 + } + } + set current_branch $head + } + + switch -- $subcommand { + browser { + if {$jump_spec ne {}} usage + if {$head eq {}} { + if {$path ne {} && [file isdirectory $path]} { + set head $current_branch + } else { + set head $path + set path {} + } + } + browser::new $head $path + } + blame { + if {$head eq {} && ![file exists $path]} { + puts stderr [mc "fatal: cannot stat path %s: No such file or directory" $path] + exit 1 + } + blame::new $head $path $jump_spec + } + } + return +} +citool - +gui { + if {[llength $argv] != 0} { + puts -nonewline stderr "usage: $argv0" + if {$subcommand ne {gui} + && [file tail $argv0] ne "git-$subcommand"} { + puts -nonewline stderr " $subcommand" + } + puts stderr {} + exit 1 + } + # fall through to setup UI for commits +} +default { + puts stderr "usage: $argv0 \[{blame|browser|citool}\]" + exit 1 +} +} + +# -- Branch Control +# +frame .branch \ + -borderwidth 1 \ + -relief sunken +label .branch.l1 \ + -text [mc "Current Branch:"] \ + -anchor w \ + -justify left +label .branch.cb \ + -textvariable current_branch \ + -anchor w \ + -justify left +pack .branch.l1 -side left +pack .branch.cb -side left -fill x +pack .branch -side top -fill x + +# -- Main Window Layout +# +panedwindow .vpane -orient horizontal +panedwindow .vpane.files -orient vertical +.vpane add .vpane.files -sticky nsew -height 100 -width 200 +pack .vpane -anchor n -side top -fill both -expand 1 + +# -- Index File List +# +frame .vpane.files.index -height 100 -width 200 +label .vpane.files.index.title -text [mc "Staged Changes (Will Commit)"] \ + -background lightgreen -foreground black +text $ui_index -background white -foreground black \ + -borderwidth 0 \ + -width 20 -height 10 \ + -wrap none \ + -cursor $cursor_ptr \ + -xscrollcommand {.vpane.files.index.sx set} \ + -yscrollcommand {.vpane.files.index.sy set} \ + -state disabled +scrollbar .vpane.files.index.sx -orient h -command [list $ui_index xview] +scrollbar .vpane.files.index.sy -orient v -command [list $ui_index yview] +pack .vpane.files.index.title -side top -fill x +pack .vpane.files.index.sx -side bottom -fill x +pack .vpane.files.index.sy -side right -fill y +pack $ui_index -side left -fill both -expand 1 + +# -- Working Directory File List +# +frame .vpane.files.workdir -height 100 -width 200 +label .vpane.files.workdir.title -text [mc "Unstaged Changes"] \ + -background lightsalmon -foreground black +text $ui_workdir -background white -foreground black \ + -borderwidth 0 \ + -width 20 -height 10 \ + -wrap none \ + -cursor $cursor_ptr \ + -xscrollcommand {.vpane.files.workdir.sx set} \ + -yscrollcommand {.vpane.files.workdir.sy set} \ + -state disabled +scrollbar .vpane.files.workdir.sx -orient h -command [list $ui_workdir xview] +scrollbar .vpane.files.workdir.sy -orient v -command [list $ui_workdir yview] +pack .vpane.files.workdir.title -side top -fill x +pack .vpane.files.workdir.sx -side bottom -fill x +pack .vpane.files.workdir.sy -side right -fill y +pack $ui_workdir -side left -fill both -expand 1 + +.vpane.files add .vpane.files.workdir -sticky nsew +.vpane.files add .vpane.files.index -sticky nsew + +foreach i [list $ui_index $ui_workdir] { + rmsel_tag $i + $i tag conf in_diff -background [$i tag cget in_sel -background] +} +unset i + +# -- Diff and Commit Area +# +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 -sticky nsew + +# -- Commit Area Buttons +# +frame .vpane.lower.commarea.buttons +label .vpane.lower.commarea.buttons.l -text {} \ + -anchor w \ + -justify left +pack .vpane.lower.commarea.buttons.l -side top -fill x +pack .vpane.lower.commarea.buttons -side left -fill y + +button .vpane.lower.commarea.buttons.rescan -text [mc Rescan] \ + -command ui_do_rescan +pack .vpane.lower.commarea.buttons.rescan -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.rescan conf -state} + +button .vpane.lower.commarea.buttons.incall -text [mc "Stage Changed"] \ + -command do_add_all +pack .vpane.lower.commarea.buttons.incall -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.incall conf -state} + +if {![is_enabled nocommitmsg]} { + button .vpane.lower.commarea.buttons.signoff -text [mc "Sign Off"] \ + -command do_signoff + pack .vpane.lower.commarea.buttons.signoff -side top -fill x +} + +button .vpane.lower.commarea.buttons.commit -text [commit_btn_caption] \ + -command do_commit +pack .vpane.lower.commarea.buttons.commit -side top -fill x +lappend disable_on_lock \ + {.vpane.lower.commarea.buttons.commit conf -state} + +if {![is_enabled nocommit]} { + button .vpane.lower.commarea.buttons.push -text [mc Push] \ + -command do_push_anywhere + pack .vpane.lower.commarea.buttons.push -side top -fill x +} + +# -- Commit Message Buffer +# +frame .vpane.lower.commarea.buffer +frame .vpane.lower.commarea.buffer.header +set ui_comm .vpane.lower.commarea.buffer.t +set ui_coml .vpane.lower.commarea.buffer.header.l + +if {![is_enabled nocommit]} { + radiobutton .vpane.lower.commarea.buffer.header.new \ + -text [mc "New Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value new + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.new conf -state] + radiobutton .vpane.lower.commarea.buffer.header.amend \ + -text [mc "Amend Last Commit"] \ + -command do_select_commit_type \ + -variable selected_commit_type \ + -value amend + lappend disable_on_lock \ + [list .vpane.lower.commarea.buffer.header.amend conf -state] +} + +label $ui_coml \ + -anchor w \ + -justify left +proc trace_commit_type {varname args} { + global ui_coml commit_type + switch -glob -- $commit_type { + initial {set txt [mc "Initial Commit Message:"]} + amend {set txt [mc "Amended Commit Message:"]} + amend-initial {set txt [mc "Amended Initial Commit Message:"]} + amend-merge {set txt [mc "Amended Merge Commit Message:"]} + merge {set txt [mc "Merge Commit Message:"]} + * {set txt [mc "Commit Message:"]} + } + $ui_coml conf -text $txt +} +trace add variable commit_type write trace_commit_type +pack $ui_coml -side left -fill x + +if {![is_enabled nocommit]} { + pack .vpane.lower.commarea.buffer.header.amend -side right + pack .vpane.lower.commarea.buffer.header.new -side right +} + +text $ui_comm -background white -foreground black \ + -borderwidth 1 \ + -undo true \ + -maxundo 20 \ + -autoseparators true \ + -relief sunken \ + -width $repo_config(gui.commitmsgwidth) -height 9 -wrap none \ + -font font_diff \ + -yscrollcommand {.vpane.lower.commarea.buffer.sby set} +scrollbar .vpane.lower.commarea.buffer.sby \ + -command [list $ui_comm yview] +pack .vpane.lower.commarea.buffer.header -side top -fill x +pack .vpane.lower.commarea.buffer.sby -side right -fill y +pack $ui_comm -side left -fill y +pack .vpane.lower.commarea.buffer -side left -fill y + +# -- Commit Message Buffer Context Menu +# +set ctxm .vpane.lower.commarea.buffer.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc Cut] \ + -command {tk_textCut $ui_comm} +$ctxm add command \ + -label [mc Copy] \ + -command {tk_textCopy $ui_comm} +$ctxm add command \ + -label [mc Paste] \ + -command {tk_textPaste $ui_comm} +$ctxm add command \ + -label [mc Delete] \ + -command {$ui_comm delete sel.first sel.last} +$ctxm add separator +$ctxm add command \ + -label [mc "Select All"] \ + -command {focus $ui_comm;$ui_comm tag add sel 0.0 end} +$ctxm add command \ + -label [mc "Copy All"] \ + -command { + $ui_comm tag add sel 0.0 end + tk_textCopy $ui_comm + $ui_comm tag remove sel 0.0 end + } +$ctxm add separator +$ctxm add command \ + -label [mc "Sign Off"] \ + -command do_signoff +set ui_comm_ctxm $ctxm + +# -- Diff Header +# +proc trace_current_diff_path {varname args} { + global current_diff_path diff_actions file_states + if {$current_diff_path eq {}} { + set s {} + set f {} + set p {} + set o disabled + } else { + set p $current_diff_path + set s [mapdesc [lindex $file_states($p) 0] $p] + set f [mc "File:"] + set p [escape_path $p] + set o normal + } + + .vpane.lower.diff.header.status configure -text $s + .vpane.lower.diff.header.file configure -text $f + .vpane.lower.diff.header.path configure -text $p + foreach w $diff_actions { + uplevel #0 $w $o + } +} +trace add variable current_diff_path write trace_current_diff_path + +frame .vpane.lower.diff.header -background gold +label .vpane.lower.diff.header.status \ + -background gold \ + -foreground black \ + -width $max_status_desc \ + -anchor w \ + -justify left +label .vpane.lower.diff.header.file \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left +label .vpane.lower.diff.header.path \ + -background gold \ + -foreground black \ + -anchor w \ + -justify left +pack .vpane.lower.diff.header.status -side left +pack .vpane.lower.diff.header.file -side left +pack .vpane.lower.diff.header.path -fill x +set ctxm .vpane.lower.diff.header.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc Copy] \ + -command { + clipboard clear + clipboard append \ + -format STRING \ + -type STRING \ + -- $current_diff_path + } +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] +bind_button3 .vpane.lower.diff.header.path "tk_popup $ctxm %X %Y" + +# -- Diff Body +# +frame .vpane.lower.diff.body +set ui_diff .vpane.lower.diff.body.t +text $ui_diff -background white -foreground black \ + -borderwidth 0 \ + -width 80 -height 15 -wrap none \ + -font font_diff \ + -xscrollcommand {.vpane.lower.diff.body.sbx set} \ + -yscrollcommand {.vpane.lower.diff.body.sby set} \ + -state disabled +scrollbar .vpane.lower.diff.body.sbx -orient horizontal \ + -command [list $ui_diff xview] +scrollbar .vpane.lower.diff.body.sby -orient vertical \ + -command [list $ui_diff yview] +pack .vpane.lower.diff.body.sbx -side bottom -fill x +pack .vpane.lower.diff.body.sby -side right -fill y +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 + +$ui_diff tag conf d_cr -elide true +$ui_diff tag conf d_@ -foreground blue -font font_diffbold +$ui_diff tag conf d_+ -foreground {#00a000} +$ui_diff tag conf d_- -foreground red + +$ui_diff tag conf d_++ -foreground {#00a000} +$ui_diff tag conf d_-- -foreground red +$ui_diff tag conf d_+s \ + -foreground {#00a000} \ + -background {#e2effa} +$ui_diff tag conf d_-s \ + -foreground red \ + -background {#e2effa} +$ui_diff tag conf d_s+ \ + -foreground {#00a000} \ + -background ivory1 +$ui_diff tag conf d_s- \ + -foreground red \ + -background ivory1 + +$ui_diff tag conf d<<<<<<< \ + -foreground orange \ + -font font_diffbold +$ui_diff tag conf d======= \ + -foreground orange \ + -font font_diffbold +$ui_diff tag conf d>>>>>>> \ + -foreground orange \ + -font font_diffbold + +$ui_diff tag raise sel + +# -- Diff Body Context Menu +# + +proc create_common_diff_popup {ctxm} { + $ctxm add command \ + -label [mc "Show Less Context"] \ + -command show_less_context + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Show More Context"] \ + -command show_more_context + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command \ + -label [mc Refresh] \ + -command reshow_diff + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc Copy] \ + -command {tk_textCopy $ui_diff} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Select All"] \ + -command {focus $ui_diff;$ui_diff tag add sel 0.0 end} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Copy All"] \ + -command { + $ui_diff tag add sel 0.0 end + tk_textCopy $ui_diff + $ui_diff tag remove sel 0.0 end + } + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command \ + -label [mc "Decrease Font Size"] \ + -command {incr_font_size font_diff -1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add command \ + -label [mc "Increase Font Size"] \ + -command {incr_font_size font_diff 1} + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + set emenu $ctxm.enc + menu $emenu + build_encoding_menu $emenu [list force_diff_encoding] + $ctxm add cascade \ + -label [mc "Encoding"] \ + -menu $emenu + lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] + $ctxm add separator + $ctxm add command -label [mc "Options..."] \ + -command do_options +} + +set ctxm .vpane.lower.diff.body.ctxm +menu $ctxm -tearoff 0 +$ctxm add command \ + -label [mc "Apply/Reverse Hunk"] \ + -command {apply_hunk $cursorX $cursorY} +set ui_diff_applyhunk [$ctxm index last] +lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state] +$ctxm add command \ + -label [mc "Apply/Reverse Line"] \ + -command {apply_line $cursorX $cursorY; do_rescan} +set ui_diff_applyline [$ctxm index last] +lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state] +$ctxm add separator +create_common_diff_popup $ctxm + +set ctxmmg .vpane.lower.diff.body.ctxmmg +menu $ctxmmg -tearoff 0 +$ctxmmg add command \ + -label [mc "Run Merge Tool"] \ + -command {merge_resolve_tool} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +$ctxmmg add command \ + -label [mc "Use Remote Version"] \ + -command {merge_resolve_one 3} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Use Local Version"] \ + -command {merge_resolve_one 2} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add command \ + -label [mc "Revert To Base"] \ + -command {merge_resolve_one 1} +lappend diff_actions [list $ctxmmg entryconf [$ctxmmg index last] -state] +$ctxmmg add separator +create_common_diff_popup $ctxmmg + +proc popup_diff_menu {ctxm ctxmmg x y X Y} { + global current_diff_path file_states + set ::cursorX $x + set ::cursorY $y + if {[info exists file_states($current_diff_path)]} { + set state [lindex $file_states($current_diff_path) 0] + } else { + set state {__} + } + if {[string first {U} $state] >= 0} { + tk_popup $ctxmmg $X $Y + } else { + if {$::ui_index eq $::current_diff_side} { + set l [mc "Unstage Hunk From Commit"] + set t [mc "Unstage Line From Commit"] + } else { + set l [mc "Stage Hunk For Commit"] + set t [mc "Stage Line For Commit"] + } + if {$::is_3way_diff + || $current_diff_path eq {} + || {__} eq $state + || {_O} eq $state + || {_T} eq $state + || {T_} eq $state} { + set s disabled + } else { + set s normal + } + $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l + $ctxm entryconf $::ui_diff_applyline -state $s -label $t + tk_popup $ctxm $X $Y + } +} +bind_button3 $ui_diff [list popup_diff_menu $ctxm $ctxmmg %x %y %X %Y] + +# -- Status Bar +# +set main_status [::status_bar::new .status] +pack .status -anchor w -side bottom -fill x +$main_status show [mc "Initializing..."] + +# -- Load geometry +# +catch { +set gm $repo_config(gui.geometry) +wm geometry . [lindex $gm 0] +.vpane sash place 0 \ + [lindex $gm 1] \ + [lindex [.vpane sash coord 0] 1] +.vpane.files sash place 0 \ + [lindex [.vpane.files sash coord 0] 0] \ + [lindex $gm 2] +unset gm +} + +# -- Key Bindings +# +bind $ui_comm <$M1B-Key-Return> {do_commit;break} +bind $ui_comm <$M1B-Key-t> {do_add_selection;break} +bind $ui_comm <$M1B-Key-T> {do_add_selection;break} +bind $ui_comm <$M1B-Key-i> {do_add_all;break} +bind $ui_comm <$M1B-Key-I> {do_add_all;break} +bind $ui_comm <$M1B-Key-x> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-X> {tk_textCut %W;break} +bind $ui_comm <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-C> {tk_textCopy %W;break} +bind $ui_comm <$M1B-Key-v> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-V> {tk_textPaste %W; %W see insert; break} +bind $ui_comm <$M1B-Key-a> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-A> {%W tag add sel 0.0 end;break} +bind $ui_comm <$M1B-Key-minus> {show_less_context;break} +bind $ui_comm <$M1B-Key-KP_Subtract> {show_less_context;break} +bind $ui_comm <$M1B-Key-equal> {show_more_context;break} +bind $ui_comm <$M1B-Key-plus> {show_more_context;break} +bind $ui_comm <$M1B-Key-KP_Add> {show_more_context;break} + +bind $ui_diff <$M1B-Key-x> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-X> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-c> {tk_textCopy %W;break} +bind $ui_diff <$M1B-Key-C> {tk_textCopy %W;break} +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 {catch {%W yview scroll -1 units};break} +bind $ui_diff {catch {%W yview scroll 1 units};break} +bind $ui_diff {catch {%W xview scroll -1 units};break} +bind $ui_diff {catch {%W xview scroll 1 units};break} +bind $ui_diff {catch {%W yview scroll -1 units};break} +bind $ui_diff {catch {%W yview scroll 1 units};break} +bind $ui_diff {catch {%W xview scroll -1 units};break} +bind $ui_diff {catch {%W xview scroll 1 units};break} +bind $ui_diff {catch {%W yview scroll -1 pages};break} +bind $ui_diff {catch {%W yview scroll 1 pages};break} +bind $ui_diff {focus %W} + +if {[is_enabled branch]} { + bind . <$M1B-Key-n> branch_create::dialog + bind . <$M1B-Key-N> branch_create::dialog + bind . <$M1B-Key-o> branch_checkout::dialog + bind . <$M1B-Key-O> branch_checkout::dialog + bind . <$M1B-Key-m> merge::dialog + bind . <$M1B-Key-M> merge::dialog +} +if {[is_enabled transport]} { + bind . <$M1B-Key-p> do_push_anywhere + bind . <$M1B-Key-P> do_push_anywhere +} + +bind . ui_do_rescan +bind . <$M1B-Key-r> ui_do_rescan +bind . <$M1B-Key-R> ui_do_rescan +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-i> do_add_all +bind . <$M1B-Key-I> do_add_all +bind . <$M1B-Key-minus> {show_less_context;break} +bind . <$M1B-Key-KP_Subtract> {show_less_context;break} +bind . <$M1B-Key-equal> {show_more_context;break} +bind . <$M1B-Key-plus> {show_more_context;break} +bind . <$M1B-Key-KP_Add> {show_more_context;break} +bind . <$M1B-Key-Return> do_commit +foreach i [list $ui_index $ui_workdir] { + bind $i "toggle_or_diff $i %x %y; break" + bind $i <$M1B-Button-1> "add_one_to_selection $i %x %y; break" + bind $i "add_range_to_selection $i %x %y; break" +} +unset i + +set file_lists($ui_index) [list] +set file_lists($ui_workdir) [list] + +wm title . "[appname] ([reponame]) [file normalize [file dirname [gitdir]]]" +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_CONFIG_LOCAL$} - + {^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]} { + load_all_remotes + + set n [.mbar.remote index end] + populate_remotes_menu + set n [expr {[.mbar.remote index end] - $n}] + if {$n > 0} { + if {[.mbar.remote type 0] eq "tearoff"} { incr n } + .mbar.remote insert $n separator + } + unset n +} + +if {[winfo exists $ui_comm]} { + set GITGUI_BCK_exists [load_message GITGUI_BCK] + + # -- If both our backup and message files exist use the + # newer of the two files to initialize the buffer. + # + if {$GITGUI_BCK_exists} { + set m [gitdir GITGUI_MSG] + if {[file isfile $m]} { + if {[file mtime [gitdir GITGUI_BCK]] > [file mtime $m]} { + catch {file delete [gitdir GITGUI_MSG]} + } else { + $ui_comm delete 0.0 end + $ui_comm edit reset + $ui_comm edit modified false + catch {file delete [gitdir GITGUI_BCK]} + set GITGUI_BCK_exists 0 + } + } + unset m + } + + proc backup_commit_buffer {} { + global ui_comm GITGUI_BCK_exists + + set m [$ui_comm edit modified] + if {$m || $GITGUI_BCK_exists} { + set msg [string trim [$ui_comm get 0.0 end]] + regsub -all -line {[ \r\t]+$} $msg {} msg + + if {$msg eq {}} { + if {$GITGUI_BCK_exists} { + catch {file delete [gitdir GITGUI_BCK]} + set GITGUI_BCK_exists 0 + } + } elseif {$m} { + catch { + set fd [open [gitdir GITGUI_BCK] w] + puts -nonewline $fd $msg + close $fd + set GITGUI_BCK_exists 1 + } + } + + $ui_comm edit modified false + } + + set ::GITGUI_BCK_i [after 2000 backup_commit_buffer] + } + + backup_commit_buffer + + # -- If the user has aspell available we can drive it + # in pipe mode to spellcheck the commit message. + # + set spell_cmd [list |] + set spell_dict [get_config gui.spellingdictionary] + lappend spell_cmd aspell + if {$spell_dict ne {}} { + lappend spell_cmd --master=$spell_dict + } + lappend spell_cmd --mode=none + lappend spell_cmd --encoding=utf-8 + lappend spell_cmd pipe + if {$spell_dict eq {none} + || [catch {set spell_fd [open $spell_cmd r+]} spell_err]} { + bind_button3 $ui_comm [list tk_popup $ui_comm_ctxm %X %Y] + } else { + set ui_comm_spell [spellcheck::init \ + $spell_fd \ + $ui_comm \ + $ui_comm_ctxm \ + ] + } + unset -nocomplain spell_cmd spell_fd spell_err spell_dict +} + +lock_index begin-read +if {![winfo ismapped .]} { + wm deiconify . +} +after 1 { + if {[is_enabled initialamend]} { + force_amend + } else { + do_rescan + } + + if {[is_enabled nocommitmsg]} { + $ui_comm configure -state disabled -background gray + } +} +if {[is_enabled multicommit]} { + after 1000 hint_gc +} +if {[is_enabled retcode]} { + bind . {+terminate_me %W} +} +if {$picked && [is_config_true gui.autoexplore]} { + do_explore +} diff --cc git-gui/lib/diff.tcl index 94ee38ccc,000000000..bbbf15c87 mode 100644,000000..100644 --- a/git-gui/lib/diff.tcl +++ b/git-gui/lib/diff.tcl @@@ -1,643 -1,0 +1,643 @@@ +# git-gui diff viewer +# Copyright (C) 2006, 2007 Shawn Pearce + +proc clear_diff {} { + global ui_diff current_diff_path current_diff_header + global ui_index ui_workdir + + $ui_diff conf -state normal + $ui_diff delete 0.0 end + $ui_diff conf -state disabled + + set current_diff_path {} + set current_diff_header {} + + $ui_index tag remove in_diff 0.0 end + $ui_workdir tag remove in_diff 0.0 end +} + - proc reshow_diff {} { ++proc reshow_diff {{after {}}} { + global file_states file_lists + global current_diff_path current_diff_side + global ui_diff + + set p $current_diff_path + if {$p eq {}} { + # No diff is being shown. + } elseif {$current_diff_side eq {}} { + clear_diff + } elseif {[catch {set s $file_states($p)}] + || [lsearch -sorted -exact $file_lists($current_diff_side) $p] == -1} { + + if {[find_next_diff $current_diff_side $p {} {[^O]}]} { - next_diff ++ next_diff $after + } else { + clear_diff + } + } else { + set save_pos [lindex [$ui_diff yview] 0] - show_diff $p $current_diff_side {} $save_pos ++ show_diff $p $current_diff_side {} $save_pos $after + } +} + +proc force_diff_encoding {enc} { + global current_diff_path + + if {$current_diff_path ne {}} { + force_path_encoding $current_diff_path $enc + reshow_diff + } +} + +proc handle_empty_diff {} { + global current_diff_path file_states file_lists + + set path $current_diff_path + set s $file_states($path) + if {[lindex $s 0] ne {_M}} return + + info_popup [mc "No differences detected. + +%s has no changes. + +The modification date of this file was updated by another application, but the content within the file was not changed. + +A rescan will be automatically started to find other files which may have the same state." [short_path $path]] + + clear_diff + display_file $path __ + rescan ui_ready 0 +} + +proc show_diff {path w {lno {}} {scroll_pos {}} {callback {}}} { + global file_states file_lists + global is_3way_diff is_conflict_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + global current_diff_queue + + if {$diff_active || ![lock_index read]} return + + clear_diff + if {$lno == {}} { + set lno [lsearch -sorted -exact $file_lists($w) $path] + if {$lno >= 0} { + incr lno + } + } + if {$lno >= 1} { + $w tag add in_diff $lno.0 [expr {$lno + 1}].0 + $w see $lno.0 + } + + set s $file_states($path) + set m [lindex $s 0] + set is_conflict_diff 0 + set current_diff_path $path + set current_diff_side $w + set current_diff_queue {} + ui_status [mc "Loading diff of %s..." [escape_path $path]] + + set cont_info [list $scroll_pos $callback] + + if {[string first {U} $m] >= 0} { + merge_load_stages $path [list show_unmerged_diff $cont_info] + } elseif {$m eq {_O}} { + show_other_diff $path $w $m $cont_info + } else { + start_show_diff $cont_info + } +} + +proc show_unmerged_diff {cont_info} { + global current_diff_path current_diff_side + global merge_stages ui_diff is_conflict_diff + global current_diff_queue + + if {$merge_stages(2) eq {}} { + set is_conflict_diff 1 + lappend current_diff_queue \ + [list [mc "LOCAL: deleted\nREMOTE:\n"] d======= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } elseif {$merge_stages(3) eq {}} { + set is_conflict_diff 1 + lappend current_diff_queue \ + [list [mc "REMOTE: deleted\nLOCAL:\n"] d======= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + } elseif {[lindex $merge_stages(1) 0] eq {120000} + || [lindex $merge_stages(2) 0] eq {120000} + || [lindex $merge_stages(3) 0] eq {120000}} { + set is_conflict_diff 1 + lappend current_diff_queue \ + [list [mc "LOCAL:\n"] d======= \ + [list ":1:$current_diff_path" ":2:$current_diff_path"]] + lappend current_diff_queue \ + [list [mc "REMOTE:\n"] d======= \ + [list ":1:$current_diff_path" ":3:$current_diff_path"]] + } else { + start_show_diff $cont_info + return + } + + advance_diff_queue $cont_info +} + +proc advance_diff_queue {cont_info} { + global current_diff_queue ui_diff + + set item [lindex $current_diff_queue 0] + set current_diff_queue [lrange $current_diff_queue 1 end] + + $ui_diff conf -state normal + $ui_diff insert end [lindex $item 0] [lindex $item 1] + $ui_diff conf -state disabled + + start_show_diff $cont_info [lindex $item 2] +} + +proc show_other_diff {path w m cont_info} { + global file_states file_lists + global is_3way_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + + # - Git won't give us the diff, there's nothing to compare to! + # + if {$m eq {_O}} { + set max_sz 100000 + set type unknown + if {[catch { + set type [file type $path] + switch -- $type { + directory { + set type submodule + set content {} + set sz 0 + } + link { + set content [file readlink $path] + set sz [string length $content] + } + file { + set fd [open $path r] + fconfigure $fd \ + -eofchar {} \ + -encoding [get_path_encoding $path] + set content [read $fd $max_sz] + close $fd + set sz [file size $path] + } + default { + error "'$type' not supported" + } + } + } err ]} { + set diff_active 0 + unlock_index + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading file:"] "\n\n$err"] + return + } + $ui_diff conf -state normal + if {$type eq {submodule}} { + $ui_diff insert end [append \ + "* " \ + [mc "Git Repository (subproject)"] \ + "\n"] d_@ + } elseif {![catch {set type [exec file $path]}]} { + set n [string length $path] + if {[string equal -length $n $path $type]} { + set type [string range $type $n end] + regsub {^:?\s*} $type {} type + } + $ui_diff insert end "* $type\n" d_@ + } + if {[string first "\0" $content] != -1} { + $ui_diff insert end \ + [mc "* Binary file (not showing content)."] \ + d_@ + } else { + if {$sz > $max_sz} { + $ui_diff insert end [mc \ +"* Untracked file is %d bytes. +* Showing only first %d bytes. +" $sz $max_sz] d_@ + } + $ui_diff insert end $content + if {$sz > $max_sz} { + $ui_diff insert end [mc " +* Untracked file clipped here by %s. +* To see the entire file, use an external editor. +" [appname]] d_@ + } + } + $ui_diff conf -state disabled + set diff_active 0 + unlock_index + set scroll_pos [lindex $cont_info 0] + if {$scroll_pos ne {}} { + update + $ui_diff yview moveto $scroll_pos + } + ui_ready + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } + return + } +} + +proc start_show_diff {cont_info {add_opts {}}} { + global file_states file_lists + global is_3way_diff diff_active repo_config + global ui_diff ui_index ui_workdir + global current_diff_path current_diff_side current_diff_header + + set path $current_diff_path + set w $current_diff_side + + set s $file_states($path) + set m [lindex $s 0] + set is_3way_diff 0 + set diff_active 1 + set current_diff_header {} + + set cmd [list] + if {$w eq $ui_index} { + lappend cmd diff-index + lappend cmd --cached + } elseif {$w eq $ui_workdir} { + if {[string first {U} $m] >= 0} { + lappend cmd diff + } else { + lappend cmd diff-files + } + } + + lappend cmd -p + lappend cmd --no-color + if {$repo_config(gui.diffcontext) >= 1} { + lappend cmd "-U$repo_config(gui.diffcontext)" + } + if {$w eq $ui_index} { + lappend cmd [PARENT] + } + if {$add_opts ne {}} { + eval lappend cmd $add_opts + } else { + lappend cmd -- + lappend cmd $path + } + + if {[catch {set fd [eval git_read --nice $cmd]} err]} { + set diff_active 0 + unlock_index + ui_status [mc "Unable to display %s" [escape_path $path]] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return + } + + set ::current_diff_inheader 1 + fconfigure $fd \ + -blocking 0 \ + -encoding [get_path_encoding $path] \ + -translation lf + fileevent $fd readable [list read_diff $fd $cont_info] +} + +proc read_diff {fd cont_info} { + global ui_diff diff_active + global is_3way_diff is_conflict_diff current_diff_header + global current_diff_queue + + $ui_diff conf -state normal + while {[gets $fd line] >= 0} { + # -- Cleanup uninteresting diff header lines. + # + if {$::current_diff_inheader} { + if { [string match {diff --git *} $line] + || [string match {diff --cc *} $line] + || [string match {diff --combined *} $line] + || [string match {--- *} $line] + || [string match {+++ *} $line]} { + append current_diff_header $line "\n" + continue + } + } + if {[string match {index *} $line]} continue + if {$line eq {deleted file mode 120000}} { + set line "deleted symlink" + } + set ::current_diff_inheader 0 + + # -- Automatically detect if this is a 3 way diff. + # + if {[string match {@@@ *} $line]} {set is_3way_diff 1} + + if {[string match {mode *} $line] + || [string match {new file *} $line] + || [regexp {^(old|new) mode *} $line] + || [string match {deleted file *} $line] + || [string match {deleted symlink} $line] + || [string match {Binary files * and * differ} $line] + || $line eq {\ No newline at end of file} + || [regexp {^\* Unmerged path } $line]} { + set tags {} + } elseif {$is_3way_diff} { + set op [string range $line 0 1] + switch -- $op { + { } {set tags {}} + {@@} {set tags d_@} + { +} {set tags d_s+} + { -} {set tags d_s-} + {+ } {set tags d_+s} + {- } {set tags d_-s} + {--} {set tags d_--} + {++} { + if {[regexp {^\+\+([<>]{7} |={7})} $line _g op]} { + set is_conflict_diff 1 + set line [string replace $line 0 1 { }] + set tags d$op + } else { + set tags d_++ + } + } + default { + puts "error: Unhandled 3 way diff marker: {$op}" + set tags {} + } + } + } else { + set op [string index $line 0] + switch -- $op { + { } {set tags {}} + {@} {set tags d_@} + {-} {set tags d_-} + {+} { + if {[regexp {^\+([<>]{7} |={7})} $line _g op]} { + set is_conflict_diff 1 + set tags d$op + } else { + set tags d_+ + } + } + default { + puts "error: Unhandled 2 way diff marker: {$op}" + set tags {} + } + } + } + $ui_diff insert end $line $tags + if {[string index $line end] eq "\r"} { + $ui_diff tag add d_cr {end - 2c} + } + $ui_diff insert end "\n" $tags + } + $ui_diff conf -state disabled + + if {[eof $fd]} { + close $fd + + if {$current_diff_queue ne {}} { + advance_diff_queue $cont_info + return + } + + set diff_active 0 + unlock_index + set scroll_pos [lindex $cont_info 0] + if {$scroll_pos ne {}} { + update + $ui_diff yview moveto $scroll_pos + } + ui_ready + + if {[$ui_diff index end] eq {2.0}} { + handle_empty_diff + } + set callback [lindex $cont_info 1] + if {$callback ne {}} { + eval $callback + } + } +} + +proc apply_hunk {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set apply_cmd {apply --cached --whitespace=nowarn} + set mi [lindex $file_states($current_diff_path) 0] + if {$current_diff_side eq $ui_index} { + set failed_msg [mc "Failed to unstage selected hunk."] + lappend apply_cmd --reverse + if {[string index $mi 0] ne {M}} { + unlock_index + return + } + } else { + set failed_msg [mc "Failed to stage selected hunk."] + if {[string index $mi 1] ne {M}} { + unlock_index + return + } + } + + set s_lno [lindex [split [$ui_diff index @$x,$y] .] 0] + set s_lno [$ui_diff search -backwards -regexp ^@@ $s_lno.0 0.0] + if {$s_lno eq {}} { + unlock_index + return + } + + set e_lno [$ui_diff search -forwards -regexp ^@@ "$s_lno + 1 lines" end] + if {$e_lno eq {}} { + set e_lno end + } + + if {[catch { + set enc [get_path_encoding $current_diff_path] + set p [eval git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $current_diff_header + puts -nonewline $p [$ui_diff get $s_lno $e_lno] + close $p} err]} { + error_popup [append $failed_msg "\n\n$err"] + unlock_index + return + } + + $ui_diff conf -state normal + $ui_diff delete $s_lno $e_lno + $ui_diff conf -state disabled + + if {[$ui_diff get 1.0 end] eq "\n"} { + set o _ + } else { + set o ? + } + + if {$current_diff_side eq $ui_index} { + set mi ${o}M + } elseif {[string index $mi 0] eq {_}} { + set mi M$o + } else { + set mi ?$o + } + unlock_index + display_file $current_diff_path $mi + # This should trigger shift to the next changed file + if {$o eq {_}} { + reshow_diff + } +} + +proc apply_line {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set apply_cmd {apply --cached --whitespace=nowarn} + set mi [lindex $file_states($current_diff_path) 0] + if {$current_diff_side eq $ui_index} { + set failed_msg [mc "Failed to unstage selected line."] + set to_context {+} + lappend apply_cmd --reverse + if {[string index $mi 0] ne {M}} { + unlock_index + return + } + } else { + set failed_msg [mc "Failed to stage selected line."] + set to_context {-} + if {[string index $mi 1] ne {M}} { + unlock_index + return + } + } + + set the_l [$ui_diff index @$x,$y] + + # operate only on change lines + set c1 [$ui_diff get "$the_l linestart"] + if {$c1 ne {+} && $c1 ne {-}} { + unlock_index + return + } + set sign $c1 + + set i_l [$ui_diff search -backwards -regexp ^@@ $the_l 0.0] + if {$i_l eq {}} { + unlock_index + return + } + # $i_l is now at the beginning of a line + + # pick start line number from hunk header + set hh [$ui_diff get $i_l "$i_l + 1 lines"] + set hh [lindex [split $hh ,] 0] + set hln [lindex [split $hh -] 1] + + # There is a special situation to take care of. Consider this hunk: + # + # @@ -10,4 +10,4 @@ + # context before + # -old 1 + # -old 2 + # +new 1 + # +new 2 + # context after + # + # We used to keep the context lines in the order they appear in the + # hunk. But then it is not possible to correctly stage only + # "-old 1" and "+new 1" - it would result in this staged text: + # + # context before + # old 2 + # new 1 + # context after + # + # (By symmetry it is not possible to *un*stage "old 2" and "new 2".) + # + # We resolve the problem by introducing an asymmetry, namely, when + # a "+" line is *staged*, it is moved in front of the context lines + # that are generated from the "-" lines that are immediately before + # the "+" block. That is, we construct this patch: + # + # @@ -10,4 +10,5 @@ + # context before + # +new 1 + # old 1 + # old 2 + # context after + # + # But we do *not* treat "-" lines that are *un*staged in a special + # way. + # + # With this asymmetry it is possible to stage the change + # "old 1" -> "new 1" directly, and to stage the change + # "old 2" -> "new 2" by first staging the entire hunk and + # then unstaging the change "old 1" -> "new 1". + + # This is non-empty if and only if we are _staging_ changes; + # then it accumulates the consecutive "-" lines (after converting + # them to context lines) in order to be moved after the "+" change + # line. + set pre_context {} + + set n 0 + set i_l [$ui_diff index "$i_l + 1 lines"] + set patch {} + while {[$ui_diff compare $i_l < "end - 1 chars"] && + [$ui_diff get $i_l "$i_l + 2 chars"] ne {@@}} { + set next_l [$ui_diff index "$i_l + 1 lines"] + set c1 [$ui_diff get $i_l] + if {[$ui_diff compare $i_l <= $the_l] && + [$ui_diff compare $the_l < $next_l]} { + # the line to stage/unstage + set ln [$ui_diff get $i_l $next_l] + if {$c1 eq {-}} { + set n [expr $n+1] + set patch "$patch$pre_context$ln" + } else { + set patch "$patch$ln$pre_context" + } + set pre_context {} + } elseif {$c1 ne {-} && $c1 ne {+}} { + # context line + set ln [$ui_diff get $i_l $next_l] + set patch "$patch$pre_context$ln" + set n [expr $n+1] + set pre_context {} + } elseif {$c1 eq $to_context} { + # turn change line into context line + set ln [$ui_diff get "$i_l + 1 chars" $next_l] + if {$c1 eq {-}} { + set pre_context "$pre_context $ln" + } else { + set patch "$patch $ln" + } + set n [expr $n+1] + } + set i_l $next_l + } + set patch "@@ -$hln,$n +$hln,[eval expr $n $sign 1] @@\n$patch" + + if {[catch { + set enc [get_path_encoding $current_diff_path] + set p [eval git_write $apply_cmd] + fconfigure $p -translation binary -encoding $enc + puts -nonewline $p $current_diff_header + puts -nonewline $p $patch + close $p} err]} { + error_popup [append $failed_msg "\n\n$err"] + } + + unlock_index +} diff --cc git-gui/lib/option.tcl index c80c93987,000000000..1d55b49c9 mode 100644,000000..100644 --- a/git-gui/lib/option.tcl +++ b/git-gui/lib/option.tcl @@@ -1,318 -1,0 +1,318 @@@ +# git-gui options editor +# Copyright (C) 2006, 2007 Shawn Pearce + +proc config_check_encodings {} { + global repo_config_new global_config_new + + set enc $global_config_new(gui.encoding) + if {$enc eq {}} { + set global_config_new(gui.encoding) [encoding system] + } elseif {[tcl_encoding $enc] eq {}} { + error_popup [mc "Invalid global encoding '%s'" $enc] + return 0 + } + + set enc $repo_config_new(gui.encoding) + if {$enc eq {}} { + set repo_config_new(gui.encoding) [encoding system] + } elseif {[tcl_encoding $enc] eq {}} { + error_popup [mc "Invalid repo encoding '%s'" $enc] + return 0 + } + + return 1 +} + +proc save_config {} { + global default_config font_descs - global repo_config global_config ++ global repo_config global_config system_config + global repo_config_new global_config_new + global ui_comm_spell + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + font configure $font \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) + font configure ${font}bold \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) + font configure ${font}italic \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) + set global_config_new(gui.$name) [font configure $font] + unset global_config_new(gui.$font^^family) + unset global_config_new(gui.$font^^size) + } + + foreach name [array names default_config] { + set value $global_config_new($name) + if {$value ne $global_config($name)} { - if {$value eq $default_config($name)} { ++ if {$value eq $system_config($name)} { + catch {git config --global --unset $name} + } else { + regsub -all "\[{}\]" $value {"} value + git config --global $name $value + } + set global_config($name) $value + if {$value eq $repo_config($name)} { + catch {git config --unset $name} + set repo_config($name) $value + } + } + } + + foreach name [array names default_config] { + set value $repo_config_new($name) + if {$value ne $repo_config($name)} { + if {$value eq $global_config($name)} { + catch {git config --unset $name} + } else { + regsub -all "\[{}\]" $value {"} value + git config $name $value + } + set repo_config($name) $value + } + } + + if {[info exists repo_config(gui.spellingdictionary)]} { + set value $repo_config(gui.spellingdictionary) + if {$value eq {none}} { + if {[info exists ui_comm_spell]} { + $ui_comm_spell stop + } + } elseif {[info exists ui_comm_spell]} { + $ui_comm_spell lang $value + } + } +} + +proc do_options {} { + global repo_config global_config font_descs + global repo_config_new global_config_new + global ui_comm_spell + + array unset repo_config_new + array unset global_config_new + foreach name [array names repo_config] { + set repo_config_new($name) $repo_config($name) + } + load_config 1 + foreach name [array names repo_config] { + switch -- $name { + gui.diffcontext {continue} + } + set repo_config_new($name) $repo_config($name) + } + foreach name [array names global_config] { + set global_config_new($name) $global_config($name) + } + + set w .options_editor + toplevel $w + wm geometry $w "+[winfo rootx .]+[winfo rooty .]" + + frame $w.buttons + button $w.buttons.restore -text [mc "Restore Defaults"] \ + -default normal \ + -command do_restore_defaults + pack $w.buttons.restore -side left + button $w.buttons.save -text [mc Save] \ + -default active \ + -command [list do_save_config $w] + pack $w.buttons.save -side right + button $w.buttons.cancel -text [mc "Cancel"] \ + -default normal \ + -command [list destroy $w] + pack $w.buttons.cancel -side right -padx 5 + pack $w.buttons -side bottom -fill x -pady 10 -padx 10 + + labelframe $w.repo -text [mc "%s Repository" [reponame]] + labelframe $w.global -text [mc "Global (All Repositories)"] + pack $w.repo -side left -fill both -expand 1 -pady 5 -padx 5 + pack $w.global -side right -fill both -expand 1 -pady 5 -padx 5 + + set optid 0 + foreach option { + {t user.name {mc "User Name"}} + {t user.email {mc "Email Address"}} + + {b merge.summary {mc "Summarize Merge Commits"}} + {i-1..5 merge.verbosity {mc "Merge Verbosity"}} + {b merge.diffstat {mc "Show Diffstat After Merge"}} + {t merge.tool {mc "Use Merge Tool"}} + + {b gui.trustmtime {mc "Trust File Modification Timestamps"}} + {b gui.pruneduringfetch {mc "Prune Tracking Branches During Fetch"}} + {b gui.matchtrackingbranch {mc "Match Tracking Branches"}} + {b gui.fastcopyblame {mc "Blame Copy Only On Changed Files"}} + {i-20..200 gui.copyblamethreshold {mc "Minimum Letters To Blame Copy On"}} + {i-0..300 gui.blamehistoryctx {mc "Blame History Context Radius (days)"}} + {i-1..99 gui.diffcontext {mc "Number of Diff Context Lines"}} + {i-0..99 gui.commitmsgwidth {mc "Commit Message Text Width"}} + {t gui.newbranchtemplate {mc "New Branch Name Template"}} + {c gui.encoding {mc "Default File Contents Encoding"}} + } { + set type [lindex $option 0] + set name [lindex $option 1] + set text [eval [lindex $option 2]] + incr optid + foreach f {repo global} { + switch -glob -- $type { + b { + checkbutton $w.$f.$optid -text $text \ + -variable ${f}_config_new($name) \ + -onvalue true \ + -offvalue false + pack $w.$f.$optid -side top -anchor w + } + i-* { + regexp -- {-(\d+)\.\.(\d+)$} $type _junk min max + frame $w.$f.$optid + label $w.$f.$optid.l -text "$text:" + pack $w.$f.$optid.l -side left -anchor w -fill x + spinbox $w.$f.$optid.v \ + -textvariable ${f}_config_new($name) \ + -from $min \ + -to $max \ + -increment 1 \ + -width [expr {1 + [string length $max]}] + bind $w.$f.$optid.v {%W selection range 0 end} + pack $w.$f.$optid.v -side right -anchor e -padx 5 + pack $w.$f.$optid -side top -anchor w -fill x + } + c - + t { + frame $w.$f.$optid + label $w.$f.$optid.l -text "$text:" + entry $w.$f.$optid.v \ + -borderwidth 1 \ + -relief sunken \ + -width 20 \ + -textvariable ${f}_config_new($name) + pack $w.$f.$optid.l -side left -anchor w + pack $w.$f.$optid.v -side left -anchor w \ + -fill x -expand 1 \ + -padx 5 + if {$type eq {c}} { + menu $w.$f.$optid.m + build_encoding_menu $w.$f.$optid.m \ + [list set ${f}_config_new($name)] 1 + button $w.$f.$optid.b \ + -text [mc "Change"] \ + -command [list popup_btn_menu \ + $w.$f.$optid.m $w.$f.$optid.b] + pack $w.$f.$optid.b -side left -anchor w + } + pack $w.$f.$optid -side top -anchor w -fill x + } + } + } + } + + set all_dicts [linsert \ + [spellcheck::available_langs] \ + 0 \ + none] + incr optid + foreach f {repo global} { + if {![info exists ${f}_config_new(gui.spellingdictionary)]} { + if {[info exists ui_comm_spell]} { + set value [$ui_comm_spell lang] + } else { + set value none + } + set ${f}_config_new(gui.spellingdictionary) $value + } + + frame $w.$f.$optid + label $w.$f.$optid.l -text [mc "Spelling Dictionary:"] + eval tk_optionMenu $w.$f.$optid.v \ + ${f}_config_new(gui.spellingdictionary) \ + $all_dicts + pack $w.$f.$optid.l -side left -anchor w -fill x + pack $w.$f.$optid.v -side right -anchor e -padx 5 + pack $w.$f.$optid -side top -anchor w -fill x + } + unset all_dicts + + set all_fonts [lsort [font families]] + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + set text [eval [lindex $option 2]] + + set global_config_new(gui.$font^^family) \ + [font configure $font -family] + set global_config_new(gui.$font^^size) \ + [font configure $font -size] + + frame $w.global.$name + label $w.global.$name.l -text "$text:" + button $w.global.$name.b \ + -text [mc "Change Font"] \ + -command [list \ + choose_font::pick \ + $w \ + [mc "Choose %s" $text] \ + global_config_new(gui.$font^^family) \ + global_config_new(gui.$font^^size) \ + ] + label $w.global.$name.f -textvariable global_config_new(gui.$font^^family) + label $w.global.$name.s -textvariable global_config_new(gui.$font^^size) + label $w.global.$name.pt -text [mc "pt."] + pack $w.global.$name.l -side left -anchor w + pack $w.global.$name.b -side right -anchor e + pack $w.global.$name.pt -side right -anchor w + pack $w.global.$name.s -side right -anchor w + pack $w.global.$name.f -side right -anchor w + pack $w.global.$name -side top -anchor w -fill x + } + + bind $w "grab $w; focus $w.buttons.save" + bind $w "destroy $w" + bind $w [list do_save_config $w] + + if {[is_MacOSX]} { + set t [mc "Preferences"] + } else { + set t [mc "Options"] + } + wm title $w "[appname] ([reponame]): $t" + tkwait window $w +} + +proc do_restore_defaults {} { - global font_descs default_config repo_config ++ global font_descs default_config repo_config system_config + global repo_config_new global_config_new + + foreach name [array names default_config] { - set repo_config_new($name) $default_config($name) - set global_config_new($name) $default_config($name) ++ set repo_config_new($name) $system_config($name) ++ set global_config_new($name) $system_config($name) + } + + foreach option $font_descs { + set name [lindex $option 0] - set repo_config(gui.$name) $default_config(gui.$name) ++ set repo_config(gui.$name) $system_config(gui.$name) + } + apply_config + + foreach option $font_descs { + set name [lindex $option 0] + set font [lindex $option 1] + set global_config_new(gui.$font^^family) \ + [font configure $font -family] + set global_config_new(gui.$font^^size) \ + [font configure $font -size] + } +} + +proc do_save_config {w} { + if {![config_check_encodings]} return + if {[catch {save_config} err]} { + error_popup [strcat [mc "Failed to completely save options:"] "\n\n$err"] + } + reshow_diff + destroy $w +} diff --cc git-gui/lib/search.tcl index 32c8656fc,000000000..b371e9a30 mode 100644,000000..100644 --- a/git-gui/lib/search.tcl +++ b/git-gui/lib/search.tcl @@@ -1,198 -1,0 +1,198 @@@ +# incremental search panel +# based on code from gitk, Copyright (C) Paul Mackerras + +class searchbar { + +field w +field ctext + +field searchstring {} +field casesensitive 1 +field searchdirn -forwards + +field smarktop +field smarkbot + +constructor new {i_w i_text args} { + set w $i_w + set ctext $i_text + + frame $w + label $w.l -text [mc Find:] + entry $w.ent -textvariable ${__this}::searchstring -background lightgreen + button $w.bn -text [mc Next] -command [cb find_next] + button $w.bp -text [mc Prev] -command [cb find_prev] + checkbutton $w.cs -text [mc Case-Sensitive] \ + -variable ${__this}::casesensitive -command [cb _incrsearch] + pack $w.l -side left + pack $w.cs -side right + pack $w.bp -side right + pack $w.bn -side right + pack $w.ent -side left -expand 1 -fill x + + eval grid conf $w -sticky we $args + grid remove $w + + trace add variable searchstring write [cb _incrsearch_cb] + - bind $w [cb delete_this] ++ bind $w [list delete_this $this] + return $this +} + +method show {} { + if {![visible $this]} { + grid $w + } + focus -force $w.ent +} + +method hide {} { + if {[visible $this]} { + focus $ctext + grid remove $w + } +} + +method visible {} { + return [winfo ismapped $w] +} + +method editor {} { + return $w.ent +} + +method _get_new_anchor {} { + # use start of selection if it is visible, + # or the bounds of the visible area + set top [$ctext index @0,0] + set bottom [$ctext index @0,[winfo height $ctext]] + set sel [$ctext tag ranges sel] + if {$sel ne {}} { + set spos [lindex $sel 0] + if {[lindex $spos 0] >= [lindex $top 0] && + [lindex $spos 0] <= [lindex $bottom 0]} { + return $spos + } + } + if {$searchdirn eq "-forwards"} { + return $top + } else { + return $bottom + } +} + +method _get_wrap_anchor {dir} { + if {$dir eq "-forwards"} { + return 1.0 + } else { + return end + } +} + +method _do_search {start {mlenvar {}} {dir {}} {endbound {}}} { + set cmd [list $ctext search] + if {$mlenvar ne {}} { + upvar $mlenvar mlen + lappend cmd -count mlen + } + if {!$casesensitive} { + lappend cmd -nocase + } + if {$dir eq {}} { + set dir $searchdirn + } + lappend cmd $dir -- $searchstring + if {$endbound ne {}} { + set here [eval $cmd [list $start] [list $endbound]] + } else { + set here [eval $cmd [list $start]] + if {$here eq {}} { + set here [eval $cmd [_get_wrap_anchor $this $dir]] + } + } + return $here +} + +method _incrsearch_cb {name ix op} { + after idle [cb _incrsearch] +} + +method _incrsearch {} { + $ctext tag remove found 1.0 end + if {[catch {$ctext index anchor}]} { + $ctext mark set anchor [_get_new_anchor $this] + } + if {$searchstring ne {}} { + set here [_do_search $this anchor mlen] + if {$here ne {}} { + $ctext see $here + $ctext tag remove sel 1.0 end + $ctext tag add sel $here "$here + $mlen c" + $w.ent configure -background lightgreen + _set_marks $this 1 + } else { + $w.ent configure -background lightpink + } + } +} + +method find_prev {} { + find_next $this -backwards +} + +method find_next {{dir -forwards}} { + focus $w.ent + $w.ent icursor end + set searchdirn $dir + $ctext mark unset anchor + if {$searchstring ne {}} { + set start [_get_new_anchor $this] + if {$dir eq "-forwards"} { + set start "$start + 1c" + } + set match [_do_search $this $start mlen] + $ctext tag remove sel 1.0 end + if {$match ne {}} { + $ctext see $match + $ctext tag add sel $match "$match + $mlen c" + } + } +} + +method _mark_range {first last} { + set mend $first.0 + while {1} { + set match [_do_search $this $mend mlen -forwards $last.end] + if {$match eq {}} break + set mend "$match + $mlen c" + $ctext tag add found $match $mend + } +} + +method _set_marks {doall} { + set topline [lindex [split [$ctext index @0,0] .] 0] + set botline [lindex [split [$ctext index @0,[winfo height $ctext]] .] 0] + if {$doall || $botline < $smarktop || $topline > $smarkbot} { + # no overlap with previous + _mark_range $this $topline $botline + set smarktop $topline + set smarkbot $botline + } else { + if {$topline < $smarktop} { + _mark_range $this $topline [expr {$smarktop-1}] + set smarktop $topline + } + if {$botline > $smarkbot} { + _mark_range $this [expr {$smarkbot+1}] $botline + set smarkbot $botline + } + } +} + +method scrolled {} { + if {$searchstring ne {}} { + after idle [cb _set_marks 0] + } +} + +} diff --cc git-gui/lib/tools.tcl index 000000000,000000000..6ae63b6c7 new file mode 100644 --- /dev/null +++ b/git-gui/lib/tools.tcl @@@ -1,0 -1,0 +1,159 @@@ ++# git-gui Tools menu implementation ++ ++proc tools_list {} { ++ global repo_config ++ ++ set names {} ++ foreach item [array names repo_config guitool.*.cmd] { ++ lappend names [string range $item 8 end-4] ++ } ++ return [lsort $names] ++} ++ ++proc tools_populate_all {} { ++ global tools_menubar tools_menutbl ++ global tools_tailcnt ++ ++ set mbar_end [$tools_menubar index end] ++ set mbar_base [expr {$mbar_end - $tools_tailcnt}] ++ if {$mbar_base >= 0} { ++ $tools_menubar delete 0 $mbar_base ++ } ++ ++ array unset tools_menutbl ++ ++ foreach fullname [tools_list] { ++ tools_populate_one $fullname ++ } ++} ++ ++proc tools_create_item {parent args} { ++ global tools_menubar tools_tailcnt ++ if {$parent eq $tools_menubar} { ++ set pos [expr {[$parent index end]-$tools_tailcnt+1}] ++ eval [list $parent insert $pos] $args ++ } else { ++ eval [list $parent add] $args ++ } ++} ++ ++proc tools_populate_one {fullname} { ++ global tools_menubar tools_menutbl tools_id ++ ++ if {![info exists tools_id]} { ++ set tools_id 0 ++ } ++ ++ set names [split $fullname '/'] ++ set parent $tools_menubar ++ for {set i 0} {$i < [llength $names]-1} {incr i} { ++ set subname [join [lrange $names 0 $i] '/'] ++ if {[info exists tools_menutbl($subname)]} { ++ set parent $tools_menutbl($subname) ++ } else { ++ set subid $parent.t$tools_id ++ tools_create_item $parent cascade \ ++ -label [lindex $names $i] -menu $subid ++ menu $subid ++ set tools_menutbl($subname) $subid ++ set parent $subid ++ incr tools_id ++ } ++ } ++ ++ tools_create_item $parent command \ ++ -label [lindex $names end] \ ++ -command [list tools_exec $fullname] ++} ++ ++proc tools_exec {fullname} { ++ global repo_config env current_diff_path ++ global current_branch is_detached ++ ++ if {[is_config_true "guitool.$fullname.needsfile"]} { ++ if {$current_diff_path eq {}} { ++ error_popup [mc "Running %s requires a selected file." $fullname] ++ return ++ } ++ } ++ ++ catch { unset env(ARGS) } ++ catch { unset env(REVISION) } ++ ++ if {[get_config "guitool.$fullname.revprompt"] ne {} || ++ [get_config "guitool.$fullname.argprompt"] ne {}} { ++ set dlg [tools_askdlg::dialog $fullname] ++ if {![tools_askdlg::execute $dlg]} { ++ return ++ } ++ } elseif {[is_config_true "guitool.$fullname.confirm"]} { ++ if {[ask_popup [mc "Are you sure you want to run %s?" $fullname]] ne {yes}} { ++ return ++ } ++ } ++ ++ set env(GIT_GUITOOL) $fullname ++ set env(FILENAME) $current_diff_path ++ if {$is_detached} { ++ set env(CUR_BRANCH) "" ++ } else { ++ set env(CUR_BRANCH) $current_branch ++ } ++ ++ set cmdline $repo_config(guitool.$fullname.cmd) ++ if {[is_config_true "guitool.$fullname.noconsole"]} { ++ tools_run_silent [list sh -c $cmdline] \ ++ [list tools_complete $fullname {}] ++ } else { ++ regsub {/} $fullname { / } title ++ set w [console::new \ ++ [mc "Tool: %s" $title] \ ++ [mc "Running: %s" $cmdline]] ++ console::exec $w [list sh -c $cmdline] \ ++ [list tools_complete $fullname $w] ++ } ++ ++ unset env(GIT_GUITOOL) ++ unset env(FILENAME) ++ unset env(CUR_BRANCH) ++ catch { unset env(ARGS) } ++ catch { unset env(REVISION) } ++} ++ ++proc tools_run_silent {cmd after} { ++ lappend cmd 2>@1 ++ set fd [_open_stdout_stderr $cmd] ++ ++ fconfigure $fd -blocking 0 -translation binary ++ fileevent $fd readable [list tools_consume_input $fd $after] ++} ++ ++proc tools_consume_input {fd after} { ++ read $fd ++ if {[eof $fd]} { ++ fconfigure $fd -blocking 1 ++ if {[catch {close $fd}]} { ++ uplevel #0 $after 0 ++ } else { ++ uplevel #0 $after 1 ++ } ++ } ++} ++ ++proc tools_complete {fullname w {ok 1}} { ++ if {$w ne {}} { ++ console::done $w $ok ++ } ++ ++ if {$ok} { ++ set msg [mc "Tool completed succesfully: %s" $fullname] ++ } else { ++ set msg [mc "Tool failed: %s" $fullname] ++ } ++ ++ if {[is_config_true "guitool.$fullname.norescan"]} { ++ ui_status $msg ++ } else { ++ rescan [list ui_status $msg] ++ } ++} diff --cc git-gui/lib/tools_dlg.tcl index 000000000,000000000..5f7f08e23 new file mode 100644 --- /dev/null +++ b/git-gui/lib/tools_dlg.tcl @@@ -1,0 -1,0 +1,421 @@@ ++# git-gui Tools menu dialogs ++ ++class tools_add { ++ ++field w ; # widget path ++field w_name ; # new remote name widget ++field w_cmd ; # new remote location widget ++ ++field name {}; # name of the tool ++field command {}; # command to execute ++field add_global 0; # add to the --global config ++field no_console 0; # disable using the console ++field needs_file 0; # ensure filename is set ++field confirm 0; # ask for confirmation ++field ask_branch 0; # ask for a revision ++field ask_args 0; # ask for additional args ++ ++constructor dialog {} { ++ global repo_config ++ ++ make_toplevel top w ++ wm title $top [append "[appname] ([reponame]): " [mc "Add Tool"]] ++ if {$top ne {.}} { ++ wm geometry $top "+[winfo rootx .]+[winfo rooty .]" ++ wm transient $top . ++ } ++ ++ label $w.header -text [mc "Add New Tool Command"] -font font_uibold ++ pack $w.header -side top -fill x ++ ++ frame $w.buttons ++ checkbutton $w.buttons.global \ ++ -text [mc "Add globally"] \ ++ -variable @add_global ++ pack $w.buttons.global -side left -padx 5 ++ button $w.buttons.create -text [mc Add] \ ++ -default active \ ++ -command [cb _add] ++ pack $w.buttons.create -side right ++ button $w.buttons.cancel -text [mc Cancel] \ ++ -command [list destroy $w] ++ pack $w.buttons.cancel -side right -padx 5 ++ pack $w.buttons -side bottom -fill x -pady 10 -padx 10 ++ ++ labelframe $w.desc -text [mc "Tool Details"] ++ ++ label $w.desc.name_cmnt -anchor w\ ++ -text [mc "Use '/' separators to create a submenu tree:"] ++ grid x $w.desc.name_cmnt -sticky we -padx {0 5} -pady {0 2} ++ label $w.desc.name_l -text [mc "Name:"] ++ set w_name $w.desc.name_t ++ entry $w_name \ ++ -borderwidth 1 \ ++ -relief sunken \ ++ -width 40 \ ++ -textvariable @name \ ++ -validate key \ ++ -validatecommand [cb _validate_name %d %S] ++ grid $w.desc.name_l $w_name -sticky we -padx {0 5} ++ ++ label $w.desc.cmd_l -text [mc "Command:"] ++ set w_cmd $w.desc.cmd_t ++ entry $w_cmd \ ++ -borderwidth 1 \ ++ -relief sunken \ ++ -width 40 \ ++ -textvariable @command ++ grid $w.desc.cmd_l $w_cmd -sticky we -padx {0 5} -pady {0 3} ++ ++ grid columnconfigure $w.desc 1 -weight 1 ++ pack $w.desc -anchor nw -fill x -pady 5 -padx 5 ++ ++ checkbutton $w.confirm \ ++ -text [mc "Show a dialog before running"] \ ++ -variable @confirm -command [cb _check_enable_dlg] ++ ++ labelframe $w.dlg -labelwidget $w.confirm ++ ++ checkbutton $w.dlg.askbranch \ ++ -text [mc "Ask the user to select a revision (sets \$REVISION)"] \ ++ -variable @ask_branch -state disabled ++ pack $w.dlg.askbranch -anchor w -padx 15 ++ ++ checkbutton $w.dlg.askargs \ ++ -text [mc "Ask the user for additional arguments (sets \$ARGS)"] \ ++ -variable @ask_args -state disabled ++ pack $w.dlg.askargs -anchor w -padx 15 ++ ++ pack $w.dlg -anchor nw -fill x -pady {0 8} -padx 5 ++ ++ checkbutton $w.noconsole \ ++ -text [mc "Don't show the command output window"] \ ++ -variable @no_console ++ pack $w.noconsole -anchor w -padx 5 ++ ++ checkbutton $w.needsfile \ ++ -text [mc "Run only if a diff is selected (\$FILENAME not empty)"] \ ++ -variable @needs_file ++ pack $w.needsfile -anchor w -padx 5 ++ ++ bind $w [cb _visible] ++ bind $w [list destroy $w] ++ bind $w [cb _add]\;break ++ tkwait window $w ++} ++ ++method _check_enable_dlg {} { ++ if {$confirm} { ++ $w.dlg.askbranch configure -state normal ++ $w.dlg.askargs configure -state normal ++ } else { ++ $w.dlg.askbranch configure -state disabled ++ $w.dlg.askargs configure -state disabled ++ } ++} ++ ++method _add {} { ++ global repo_config ++ ++ if {$name eq {}} { ++ error_popup [mc "Please supply a name for the tool."] ++ focus $w_name ++ return ++ } ++ ++ set item "guitool.$name.cmd" ++ ++ if {[info exists repo_config($item)]} { ++ error_popup [mc "Tool '%s' already exists." $name] ++ focus $w_name ++ return ++ } ++ ++ set cmd [list git config] ++ if {$add_global} { lappend cmd --global } ++ set items {} ++ if {$no_console} { lappend items "guitool.$name.noconsole" } ++ if {$needs_file} { lappend items "guitool.$name.needsfile" } ++ if {$confirm} { ++ if {$ask_args} { lappend items "guitool.$name.argprompt" } ++ if {$ask_branch} { lappend items "guitool.$name.revprompt" } ++ if {!$ask_args && !$ask_branch} { ++ lappend items "guitool.$name.confirm" ++ } ++ } ++ ++ if {[catch { ++ eval $cmd [list $item $command] ++ foreach citem $items { eval $cmd [list $citem yes] } ++ } err]} { ++ error_popup [mc "Could not add tool:\n%s" $err] ++ } else { ++ set repo_config($item) $command ++ foreach citem $items { set repo_config($citem) yes } ++ ++ tools_populate_all ++ } ++ ++ destroy $w ++} ++ ++method _validate_name {d S} { ++ if {$d == 1} { ++ if {[regexp {[~?*&\[\0\"\\\{]} $S]} { ++ return 0 ++ } ++ } ++ return 1 ++} ++ ++method _visible {} { ++ grab $w ++ $w_name icursor end ++ focus $w_name ++} ++ ++} ++ ++class tools_remove { ++ ++field w ; # widget path ++field w_names ; # name list ++ ++constructor dialog {} { ++ global repo_config global_config system_config ++ ++ load_config 1 ++ ++ make_toplevel top w ++ wm title $top [append "[appname] ([reponame]): " [mc "Remove Tool"]] ++ if {$top ne {.}} { ++ wm geometry $top "+[winfo rootx .]+[winfo rooty .]" ++ wm transient $top . ++ } ++ ++ label $w.header -text [mc "Remove Tool Commands"] -font font_uibold ++ pack $w.header -side top -fill x ++ ++ frame $w.buttons ++ button $w.buttons.create -text [mc Remove] \ ++ -default active \ ++ -command [cb _remove] ++ pack $w.buttons.create -side right ++ button $w.buttons.cancel -text [mc Cancel] \ ++ -command [list destroy $w] ++ pack $w.buttons.cancel -side right -padx 5 ++ pack $w.buttons -side bottom -fill x -pady 10 -padx 10 ++ ++ frame $w.list ++ set w_names $w.list.l ++ listbox $w_names \ ++ -height 10 \ ++ -width 30 \ ++ -selectmode extended \ ++ -exportselection false \ ++ -yscrollcommand [list $w.list.sby set] ++ scrollbar $w.list.sby -command [list $w.list.l yview] ++ pack $w.list.sby -side right -fill y ++ pack $w.list.l -side left -fill both -expand 1 ++ pack $w.list -fill both -expand 1 -pady 5 -padx 5 ++ ++ set local_cnt 0 ++ foreach fullname [tools_list] { ++ # Cannot delete system tools ++ if {[info exists system_config(guitool.$fullname.cmd)]} continue ++ ++ $w_names insert end $fullname ++ if {![info exists global_config(guitool.$fullname.cmd)]} { ++ $w_names itemconfigure end -foreground blue ++ incr local_cnt ++ } ++ } ++ ++ if {$local_cnt > 0} { ++ label $w.colorlbl -foreground blue \ ++ -text [mc "(Blue denotes repository-local tools)"] ++ pack $w.colorlbl -fill x -pady 5 -padx 5 ++ } ++ ++ bind $w [cb _visible] ++ bind $w [list destroy $w] ++ bind $w [cb _remove]\;break ++ tkwait window $w ++} ++ ++method _remove {} { ++ foreach i [$w_names curselection] { ++ set name [$w_names get $i] ++ ++ catch { git config --remove-section guitool.$name } ++ catch { git config --global --remove-section guitool.$name } ++ } ++ ++ load_config 0 ++ tools_populate_all ++ ++ destroy $w ++} ++ ++method _visible {} { ++ grab $w ++ focus $w_names ++} ++ ++} ++ ++class tools_askdlg { ++ ++field w ; # widget path ++field w_rev {}; # revision browser ++field w_args {}; # arguments ++ ++field is_ask_args 0; # has arguments field ++field is_ask_revs 0; # has revision browser ++ ++field is_ok 0; # ok to start ++field argstr {}; # arguments ++ ++constructor dialog {fullname} { ++ global M1B ++ ++ set title [get_config "guitool.$fullname.title"] ++ if {$title eq {}} { ++ regsub {/} $fullname { / } title ++ } ++ ++ make_toplevel top w -autodelete 0 ++ wm title $top [append "[appname] ([reponame]): " $title] ++ if {$top ne {.}} { ++ wm geometry $top "+[winfo rootx .]+[winfo rooty .]" ++ wm transient $top . ++ } ++ ++ set prompt [get_config "guitool.$fullname.prompt"] ++ if {$prompt eq {}} { ++ set command [get_config "guitool.$fullname.cmd"] ++ set prompt [mc "Run Command: %s" $command] ++ } ++ ++ label $w.header -text $prompt -font font_uibold ++ pack $w.header -side top -fill x ++ ++ set argprompt [get_config "guitool.$fullname.argprompt"] ++ set revprompt [get_config "guitool.$fullname.revprompt"] ++ ++ set is_ask_args [expr {$argprompt ne {}}] ++ set is_ask_revs [expr {$revprompt ne {}}] ++ ++ if {$is_ask_args} { ++ if {$argprompt eq {yes} || $argprompt eq {true} || $argprompt eq {1}} { ++ set argprompt [mc "Arguments"] ++ } ++ ++ labelframe $w.arg -text $argprompt ++ ++ set w_args $w.arg.txt ++ entry $w_args \ ++ -borderwidth 1 \ ++ -relief sunken \ ++ -width 40 \ ++ -textvariable @argstr ++ pack $w_args -padx 5 -pady 5 -fill both ++ pack $w.arg -anchor nw -fill both -pady 5 -padx 5 ++ } ++ ++ if {$is_ask_revs} { ++ if {$revprompt eq {yes} || $revprompt eq {true} || $revprompt eq {1}} { ++ set revprompt [mc "Revision"] ++ } ++ ++ if {[is_config_true "guitool.$fullname.revunmerged"]} { ++ set w_rev [::choose_rev::new_unmerged $w.rev $revprompt] ++ } else { ++ set w_rev [::choose_rev::new $w.rev $revprompt] ++ } ++ ++ pack $w.rev -anchor nw -fill both -expand 1 -pady 5 -padx 5 ++ } ++ ++ frame $w.buttons ++ if {$is_ask_revs} { ++ button $w.buttons.visualize \ ++ -text [mc Visualize] \ ++ -command [cb _visualize] ++ pack $w.buttons.visualize -side left ++ } ++ button $w.buttons.ok \ ++ -text [mc OK] \ ++ -command [cb _start] ++ pack $w.buttons.ok -side right ++ button $w.buttons.cancel \ ++ -text [mc "Cancel"] \ ++ -command [cb _cancel] ++ pack $w.buttons.cancel -side right -padx 5 ++ pack $w.buttons -side bottom -fill x -pady 10 -padx 10 ++ ++ bind $w <$M1B-Key-Return> [cb _start] ++ bind $w [cb _start] ++ bind $w [cb _cancel] ++ wm protocol $w WM_DELETE_WINDOW [cb _cancel] ++ ++ bind $w [cb _visible] ++ return $this ++} ++ ++method execute {} { ++ tkwait window $w ++ set rv $is_ok ++ delete_this ++ return $rv ++} ++ ++method _visible {} { ++ grab $w ++ if {$is_ask_args} { ++ focus $w_args ++ } elseif {$is_ask_revs} { ++ $w_rev focus_filter ++ } ++} ++ ++method _cancel {} { ++ wm protocol $w WM_DELETE_WINDOW {} ++ destroy $w ++} ++ ++method _rev {} { ++ if {[catch {$w_rev commit_or_die}]} { ++ return {} ++ } ++ return [$w_rev get] ++} ++ ++method _visualize {} { ++ global current_branch ++ set rev [_rev $this] ++ if {$rev ne {}} { ++ do_gitk [list --left-right "$current_branch...$rev"] ++ } ++} ++ ++method _start {} { ++ global env ++ ++ if {$is_ask_revs} { ++ set name [_rev $this] ++ if {$name eq {}} { ++ return ++ } ++ set env(REVISION) $name ++ } ++ ++ if {$is_ask_args} { ++ set env(ARGS) $argstr ++ } ++ ++ set is_ok 1 ++ _cancel $this ++} ++ ++} diff --cc git-gui/po/git-gui.pot index e295000e7,000000000..58db67c21 mode 100644,000000..100644 --- a/git-gui/po/git-gui.pot +++ b/git-gui/po/git-gui.pot @@@ -1,1864 -1,0 +1,2370 @@@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" - "POT-Creation-Date: 2008-08-02 14:45-0700\n" ++"POT-Creation-Date: 2008-11-16 13:56-0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + - #: git-gui.sh:41 git-gui.sh:688 git-gui.sh:702 git-gui.sh:715 git-gui.sh:798 - #: git-gui.sh:817 ++#: git-gui.sh:41 git-gui.sh:737 git-gui.sh:751 git-gui.sh:764 git-gui.sh:847 ++#: git-gui.sh:866 +msgid "git-gui: fatal error" +msgstr "" + - #: git-gui.sh:644 ++#: git-gui.sh:689 +#, tcl-format +msgid "Invalid font specified in %s:" +msgstr "" + - #: git-gui.sh:674 ++#: git-gui.sh:723 +msgid "Main Font" +msgstr "" + - #: git-gui.sh:675 ++#: git-gui.sh:724 +msgid "Diff/Console Font" +msgstr "" + - #: git-gui.sh:689 ++#: git-gui.sh:738 +msgid "Cannot find git in PATH." +msgstr "" + - #: git-gui.sh:716 ++#: git-gui.sh:765 +msgid "Cannot parse Git version string:" +msgstr "" + - #: git-gui.sh:734 ++#: git-gui.sh:783 +#, tcl-format +msgid "" +"Git version cannot be determined.\n" +"\n" +"%s claims it is version '%s'.\n" +"\n" +"%s requires at least Git 1.5.0 or later.\n" +"\n" +"Assume '%s' is version 1.5.0?\n" +msgstr "" + - #: git-gui.sh:972 ++#: git-gui.sh:1062 +msgid "Git directory not found:" +msgstr "" + - #: git-gui.sh:979 ++#: git-gui.sh:1069 +msgid "Cannot move to top of working directory:" +msgstr "" + - #: git-gui.sh:986 ++#: git-gui.sh:1076 +msgid "Cannot use funny .git directory:" +msgstr "" + - #: git-gui.sh:991 ++#: git-gui.sh:1081 +msgid "No working directory" +msgstr "" + - #: git-gui.sh:1138 lib/checkout_op.tcl:305 ++#: git-gui.sh:1247 lib/checkout_op.tcl:305 +msgid "Refreshing file status..." +msgstr "" + - #: git-gui.sh:1194 ++#: git-gui.sh:1303 +msgid "Scanning for modified files ..." +msgstr "" + - #: git-gui.sh:1369 lib/browser.tcl:246 ++#: git-gui.sh:1367 ++msgid "Calling prepare-commit-msg hook..." ++msgstr "" ++ ++#: git-gui.sh:1384 ++msgid "Commit declined by prepare-commit-msg hook." ++msgstr "" ++ ++#: git-gui.sh:1542 lib/browser.tcl:246 +msgid "Ready." +msgstr "" + - #: git-gui.sh:1635 ++#: git-gui.sh:1819 +msgid "Unmodified" +msgstr "" + - #: git-gui.sh:1637 ++#: git-gui.sh:1821 +msgid "Modified, not staged" +msgstr "" + - #: git-gui.sh:1638 git-gui.sh:1643 ++#: git-gui.sh:1822 git-gui.sh:1830 +msgid "Staged for commit" +msgstr "" + - #: git-gui.sh:1639 git-gui.sh:1644 ++#: git-gui.sh:1823 git-gui.sh:1831 +msgid "Portions staged for commit" +msgstr "" + - #: git-gui.sh:1640 git-gui.sh:1645 ++#: git-gui.sh:1824 git-gui.sh:1832 +msgid "Staged for commit, missing" +msgstr "" + - #: git-gui.sh:1642 ++#: git-gui.sh:1826 ++msgid "File type changed, not staged" ++msgstr "" ++ ++#: git-gui.sh:1827 ++msgid "File type changed, staged" ++msgstr "" ++ ++#: git-gui.sh:1829 +msgid "Untracked, not staged" +msgstr "" + - #: git-gui.sh:1647 ++#: git-gui.sh:1834 +msgid "Missing" +msgstr "" + - #: git-gui.sh:1648 ++#: git-gui.sh:1835 +msgid "Staged for removal" +msgstr "" + - #: git-gui.sh:1649 ++#: git-gui.sh:1836 +msgid "Staged for removal, still present" +msgstr "" + - #: git-gui.sh:1651 git-gui.sh:1652 git-gui.sh:1653 git-gui.sh:1654 ++#: git-gui.sh:1838 git-gui.sh:1839 git-gui.sh:1840 git-gui.sh:1841 ++#: git-gui.sh:1842 git-gui.sh:1843 +msgid "Requires merge resolution" +msgstr "" + - #: git-gui.sh:1689 ++#: git-gui.sh:1878 +msgid "Starting gitk... please wait..." +msgstr "" + - #: git-gui.sh:1698 ++#: git-gui.sh:1887 +msgid "Couldn't find gitk in PATH" +msgstr "" + - #: git-gui.sh:1948 lib/choose_repository.tcl:36 ++#: git-gui.sh:2280 lib/choose_repository.tcl:36 +msgid "Repository" +msgstr "" + - #: git-gui.sh:1949 ++#: git-gui.sh:2281 +msgid "Edit" +msgstr "" + - #: git-gui.sh:1951 lib/choose_rev.tcl:561 ++#: git-gui.sh:2283 lib/choose_rev.tcl:561 +msgid "Branch" +msgstr "" + - #: git-gui.sh:1954 lib/choose_rev.tcl:548 ++#: git-gui.sh:2286 lib/choose_rev.tcl:548 +msgid "Commit@@noun" +msgstr "" + - #: git-gui.sh:1957 lib/merge.tcl:120 lib/merge.tcl:149 lib/merge.tcl:167 ++#: git-gui.sh:2289 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168 +msgid "Merge" +msgstr "" + - #: git-gui.sh:1958 lib/choose_rev.tcl:557 ++#: git-gui.sh:2290 lib/choose_rev.tcl:557 +msgid "Remote" +msgstr "" + - #: git-gui.sh:1967 ++#: git-gui.sh:2293 ++msgid "Tools" ++msgstr "" ++ ++#: git-gui.sh:2302 ++msgid "Explore Working Copy" ++msgstr "" ++ ++#: git-gui.sh:2307 +msgid "Browse Current Branch's Files" +msgstr "" + - #: git-gui.sh:1971 ++#: git-gui.sh:2311 +msgid "Browse Branch Files..." +msgstr "" + - #: git-gui.sh:1976 ++#: git-gui.sh:2316 +msgid "Visualize Current Branch's History" +msgstr "" + - #: git-gui.sh:1980 ++#: git-gui.sh:2320 +msgid "Visualize All Branch History" +msgstr "" + - #: git-gui.sh:1987 ++#: git-gui.sh:2327 +#, tcl-format +msgid "Browse %s's Files" +msgstr "" + - #: git-gui.sh:1989 ++#: git-gui.sh:2329 +#, tcl-format +msgid "Visualize %s's History" +msgstr "" + - #: git-gui.sh:1994 lib/database.tcl:27 lib/database.tcl:67 ++#: git-gui.sh:2334 lib/database.tcl:27 lib/database.tcl:67 +msgid "Database Statistics" +msgstr "" + - #: git-gui.sh:1997 lib/database.tcl:34 ++#: git-gui.sh:2337 lib/database.tcl:34 +msgid "Compress Database" +msgstr "" + - #: git-gui.sh:2000 ++#: git-gui.sh:2340 +msgid "Verify Database" +msgstr "" + - #: git-gui.sh:2007 git-gui.sh:2011 git-gui.sh:2015 lib/shortcut.tcl:7 ++#: git-gui.sh:2347 git-gui.sh:2351 git-gui.sh:2355 lib/shortcut.tcl:7 +#: lib/shortcut.tcl:39 lib/shortcut.tcl:71 +msgid "Create Desktop Icon" +msgstr "" + - #: git-gui.sh:2023 lib/choose_repository.tcl:177 lib/choose_repository.tcl:185 ++#: git-gui.sh:2363 lib/choose_repository.tcl:183 lib/choose_repository.tcl:191 +msgid "Quit" +msgstr "" + - #: git-gui.sh:2031 ++#: git-gui.sh:2371 +msgid "Undo" +msgstr "" + - #: git-gui.sh:2034 ++#: git-gui.sh:2374 +msgid "Redo" +msgstr "" + - #: git-gui.sh:2038 git-gui.sh:2545 ++#: git-gui.sh:2378 git-gui.sh:2923 +msgid "Cut" +msgstr "" + - #: git-gui.sh:2041 git-gui.sh:2548 git-gui.sh:2622 git-gui.sh:2715 ++#: git-gui.sh:2381 git-gui.sh:2926 git-gui.sh:3000 git-gui.sh:3082 +#: lib/console.tcl:69 +msgid "Copy" +msgstr "" + - #: git-gui.sh:2044 git-gui.sh:2551 ++#: git-gui.sh:2384 git-gui.sh:2929 +msgid "Paste" +msgstr "" + - #: git-gui.sh:2047 git-gui.sh:2554 lib/branch_delete.tcl:26 ++#: git-gui.sh:2387 git-gui.sh:2932 lib/branch_delete.tcl:26 +#: lib/remote_branch_delete.tcl:38 +msgid "Delete" +msgstr "" + - #: git-gui.sh:2051 git-gui.sh:2558 git-gui.sh:2719 lib/console.tcl:71 ++#: git-gui.sh:2391 git-gui.sh:2936 git-gui.sh:3086 lib/console.tcl:71 +msgid "Select All" +msgstr "" + - #: git-gui.sh:2060 ++#: git-gui.sh:2400 +msgid "Create..." +msgstr "" + - #: git-gui.sh:2066 ++#: git-gui.sh:2406 +msgid "Checkout..." +msgstr "" + - #: git-gui.sh:2072 ++#: git-gui.sh:2412 +msgid "Rename..." +msgstr "" + - #: git-gui.sh:2077 git-gui.sh:2187 ++#: git-gui.sh:2417 +msgid "Delete..." +msgstr "" + - #: git-gui.sh:2082 ++#: git-gui.sh:2422 +msgid "Reset..." +msgstr "" + - #: git-gui.sh:2094 git-gui.sh:2491 ++#: git-gui.sh:2432 ++msgid "Done" ++msgstr "" ++ ++#: git-gui.sh:2434 ++msgid "Commit@@verb" ++msgstr "" ++ ++#: git-gui.sh:2443 git-gui.sh:2864 +msgid "New Commit" +msgstr "" + - #: git-gui.sh:2102 git-gui.sh:2498 ++#: git-gui.sh:2451 git-gui.sh:2871 +msgid "Amend Last Commit" +msgstr "" + - #: git-gui.sh:2111 git-gui.sh:2458 lib/remote_branch_delete.tcl:99 ++#: git-gui.sh:2461 git-gui.sh:2825 lib/remote_branch_delete.tcl:99 +msgid "Rescan" +msgstr "" + - #: git-gui.sh:2117 ++#: git-gui.sh:2467 +msgid "Stage To Commit" +msgstr "" + - #: git-gui.sh:2123 ++#: git-gui.sh:2473 +msgid "Stage Changed Files To Commit" +msgstr "" + - #: git-gui.sh:2129 ++#: git-gui.sh:2479 +msgid "Unstage From Commit" +msgstr "" + - #: git-gui.sh:2134 lib/index.tcl:395 ++#: git-gui.sh:2484 lib/index.tcl:410 +msgid "Revert Changes" +msgstr "" + - #: git-gui.sh:2141 git-gui.sh:2702 ++#: git-gui.sh:2491 git-gui.sh:3069 +msgid "Show Less Context" +msgstr "" + - #: git-gui.sh:2145 git-gui.sh:2706 ++#: git-gui.sh:2495 git-gui.sh:3073 +msgid "Show More Context" +msgstr "" + - #: git-gui.sh:2151 git-gui.sh:2470 git-gui.sh:2569 ++#: git-gui.sh:2502 git-gui.sh:2838 git-gui.sh:2947 +msgid "Sign Off" +msgstr "" + - #: git-gui.sh:2155 git-gui.sh:2474 - msgid "Commit@@verb" - msgstr "" - - #: git-gui.sh:2166 ++#: git-gui.sh:2518 +msgid "Local Merge..." +msgstr "" + - #: git-gui.sh:2171 ++#: git-gui.sh:2523 +msgid "Abort Merge..." +msgstr "" + - #: git-gui.sh:2183 ++#: git-gui.sh:2535 git-gui.sh:2575 ++msgid "Add..." ++msgstr "" ++ ++#: git-gui.sh:2539 +msgid "Push..." +msgstr "" + - #: git-gui.sh:2197 git-gui.sh:2219 lib/about.tcl:14 - #: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50 ++#: git-gui.sh:2543 ++msgid "Delete Branch..." ++msgstr "" ++ ++#: git-gui.sh:2553 git-gui.sh:2589 lib/about.tcl:14 ++#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:53 +#, tcl-format +msgid "About %s" +msgstr "" + - #: git-gui.sh:2201 ++#: git-gui.sh:2557 +msgid "Preferences..." +msgstr "" + - #: git-gui.sh:2209 git-gui.sh:2740 ++#: git-gui.sh:2565 git-gui.sh:3115 +msgid "Options..." +msgstr "" + - #: git-gui.sh:2215 lib/choose_repository.tcl:47 ++#: git-gui.sh:2576 ++msgid "Remove..." ++msgstr "" ++ ++#: git-gui.sh:2585 lib/choose_repository.tcl:50 +msgid "Help" +msgstr "" + - #: git-gui.sh:2256 ++#: git-gui.sh:2611 +msgid "Online Documentation" +msgstr "" + - #: git-gui.sh:2340 ++#: git-gui.sh:2614 lib/choose_repository.tcl:47 lib/choose_repository.tcl:56 ++msgid "Show SSH Key" ++msgstr "" ++ ++#: git-gui.sh:2707 +#, tcl-format +msgid "fatal: cannot stat path %s: No such file or directory" +msgstr "" + - #: git-gui.sh:2373 ++#: git-gui.sh:2740 +msgid "Current Branch:" +msgstr "" + - #: git-gui.sh:2394 ++#: git-gui.sh:2761 +msgid "Staged Changes (Will Commit)" +msgstr "" + - #: git-gui.sh:2414 ++#: git-gui.sh:2781 +msgid "Unstaged Changes" +msgstr "" + - #: git-gui.sh:2464 ++#: git-gui.sh:2831 +msgid "Stage Changed" +msgstr "" + - #: git-gui.sh:2480 lib/transport.tcl:93 lib/transport.tcl:182 ++#: git-gui.sh:2850 lib/transport.tcl:93 lib/transport.tcl:182 +msgid "Push" +msgstr "" + - #: git-gui.sh:2510 ++#: git-gui.sh:2885 +msgid "Initial Commit Message:" +msgstr "" + - #: git-gui.sh:2511 ++#: git-gui.sh:2886 +msgid "Amended Commit Message:" +msgstr "" + - #: git-gui.sh:2512 ++#: git-gui.sh:2887 +msgid "Amended Initial Commit Message:" +msgstr "" + - #: git-gui.sh:2513 ++#: git-gui.sh:2888 +msgid "Amended Merge Commit Message:" +msgstr "" + - #: git-gui.sh:2514 ++#: git-gui.sh:2889 +msgid "Merge Commit Message:" +msgstr "" + - #: git-gui.sh:2515 ++#: git-gui.sh:2890 +msgid "Commit Message:" +msgstr "" + - #: git-gui.sh:2561 git-gui.sh:2723 lib/console.tcl:73 ++#: git-gui.sh:2939 git-gui.sh:3090 lib/console.tcl:73 +msgid "Copy All" +msgstr "" + - #: git-gui.sh:2585 lib/blame.tcl:100 ++#: git-gui.sh:2963 lib/blame.tcl:104 +msgid "File:" +msgstr "" + - #: git-gui.sh:2691 ++#: git-gui.sh:3078 ++msgid "Refresh" ++msgstr "" ++ ++#: git-gui.sh:3099 ++msgid "Decrease Font Size" ++msgstr "" ++ ++#: git-gui.sh:3103 ++msgid "Increase Font Size" ++msgstr "" ++ ++#: git-gui.sh:3111 lib/blame.tcl:281 ++msgid "Encoding" ++msgstr "" ++ ++#: git-gui.sh:3122 +msgid "Apply/Reverse Hunk" +msgstr "" + - #: git-gui.sh:2696 ++#: git-gui.sh:3127 +msgid "Apply/Reverse Line" +msgstr "" + - #: git-gui.sh:2711 - msgid "Refresh" ++#: git-gui.sh:3137 ++msgid "Run Merge Tool" +msgstr "" + - #: git-gui.sh:2732 - msgid "Decrease Font Size" ++#: git-gui.sh:3142 ++msgid "Use Remote Version" +msgstr "" + - #: git-gui.sh:2736 - msgid "Increase Font Size" ++#: git-gui.sh:3146 ++msgid "Use Local Version" ++msgstr "" ++ ++#: git-gui.sh:3150 ++msgid "Revert To Base" +msgstr "" + - #: git-gui.sh:2747 ++#: git-gui.sh:3169 +msgid "Unstage Hunk From Commit" +msgstr "" + - #: git-gui.sh:2748 ++#: git-gui.sh:3170 +msgid "Unstage Line From Commit" +msgstr "" + - #: git-gui.sh:2750 ++#: git-gui.sh:3172 +msgid "Stage Hunk For Commit" +msgstr "" + - #: git-gui.sh:2751 ++#: git-gui.sh:3173 +msgid "Stage Line For Commit" +msgstr "" + - #: git-gui.sh:2771 ++#: git-gui.sh:3196 +msgid "Initializing..." +msgstr "" + - #: git-gui.sh:2876 ++#: git-gui.sh:3301 +#, tcl-format +msgid "" +"Possible environment issues exist.\n" +"\n" +"The following environment variables are probably\n" +"going to be ignored by any Git subprocess run\n" +"by %s:\n" +"\n" +msgstr "" + - #: git-gui.sh:2906 ++#: git-gui.sh:3331 +msgid "" +"\n" +"This is due to a known issue with the\n" +"Tcl binary distributed by Cygwin." +msgstr "" + - #: git-gui.sh:2911 ++#: git-gui.sh:3336 +#, tcl-format +msgid "" +"\n" +"\n" +"A good replacement for %s\n" +"is placing values for the user.name and\n" +"user.email settings into your personal\n" +"~/.gitconfig file.\n" +msgstr "" + +#: lib/about.tcl:26 +msgid "git-gui - a graphical user interface for Git." +msgstr "" + - #: lib/blame.tcl:70 ++#: lib/blame.tcl:72 +msgid "File Viewer" +msgstr "" + - #: lib/blame.tcl:74 ++#: lib/blame.tcl:78 +msgid "Commit:" +msgstr "" + - #: lib/blame.tcl:257 ++#: lib/blame.tcl:271 +msgid "Copy Commit" +msgstr "" + - #: lib/blame.tcl:260 ++#: lib/blame.tcl:275 ++msgid "Find Text..." ++msgstr "" ++ ++#: lib/blame.tcl:284 +msgid "Do Full Copy Detection" +msgstr "" + - #: lib/blame.tcl:388 ++#: lib/blame.tcl:288 ++msgid "Show History Context" ++msgstr "" ++ ++#: lib/blame.tcl:291 ++msgid "Blame Parent Commit" ++msgstr "" ++ ++#: lib/blame.tcl:450 +#, tcl-format +msgid "Reading %s..." +msgstr "" + - #: lib/blame.tcl:492 ++#: lib/blame.tcl:557 +msgid "Loading copy/move tracking annotations..." +msgstr "" + - #: lib/blame.tcl:512 ++#: lib/blame.tcl:577 +msgid "lines annotated" +msgstr "" + - #: lib/blame.tcl:704 ++#: lib/blame.tcl:769 +msgid "Loading original location annotations..." +msgstr "" + - #: lib/blame.tcl:707 ++#: lib/blame.tcl:772 +msgid "Annotation complete." +msgstr "" + - #: lib/blame.tcl:737 ++#: lib/blame.tcl:802 +msgid "Busy" +msgstr "" + - #: lib/blame.tcl:738 ++#: lib/blame.tcl:803 +msgid "Annotation process is already running." +msgstr "" + - #: lib/blame.tcl:777 ++#: lib/blame.tcl:842 +msgid "Running thorough copy detection..." +msgstr "" + - #: lib/blame.tcl:827 ++#: lib/blame.tcl:910 +msgid "Loading annotation..." +msgstr "" + - #: lib/blame.tcl:883 ++#: lib/blame.tcl:964 +msgid "Author:" +msgstr "" + - #: lib/blame.tcl:887 ++#: lib/blame.tcl:968 +msgid "Committer:" +msgstr "" + - #: lib/blame.tcl:892 ++#: lib/blame.tcl:973 +msgid "Original File:" +msgstr "" + - #: lib/blame.tcl:1006 ++#: lib/blame.tcl:1021 ++msgid "Cannot find HEAD commit:" ++msgstr "" ++ ++#: lib/blame.tcl:1076 ++msgid "Cannot find parent commit:" ++msgstr "" ++ ++#: lib/blame.tcl:1091 ++msgid "Unable to display parent" ++msgstr "" ++ ++#: lib/blame.tcl:1092 lib/diff.tcl:297 ++msgid "Error loading diff:" ++msgstr "" ++ ++#: lib/blame.tcl:1232 +msgid "Originally By:" +msgstr "" + - #: lib/blame.tcl:1012 ++#: lib/blame.tcl:1238 +msgid "In File:" +msgstr "" + - #: lib/blame.tcl:1017 ++#: lib/blame.tcl:1243 +msgid "Copied Or Moved Here By:" +msgstr "" + +#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19 +msgid "Checkout Branch" +msgstr "" + +#: lib/branch_checkout.tcl:23 +msgid "Checkout" +msgstr "" + +#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35 +#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:282 - #: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:171 - #: lib/option.tcl:103 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97 ++#: lib/checkout_op.tcl:544 lib/choose_font.tcl:43 lib/merge.tcl:172 ++#: lib/option.tcl:125 lib/remote_add.tcl:32 lib/remote_branch_delete.tcl:42 ++#: lib/tools_dlg.tcl:40 lib/tools_dlg.tcl:204 lib/tools_dlg.tcl:352 ++#: lib/transport.tcl:97 +msgid "Cancel" +msgstr "" + - #: lib/branch_checkout.tcl:32 lib/browser.tcl:287 ++#: lib/branch_checkout.tcl:32 lib/browser.tcl:287 lib/tools_dlg.tcl:328 +msgid "Revision" +msgstr "" + - #: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:244 ++#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:280 +msgid "Options" +msgstr "" + +#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92 +msgid "Fetch Tracking Branch" +msgstr "" + +#: lib/branch_checkout.tcl:44 +msgid "Detach From Local Branch" +msgstr "" + +#: lib/branch_create.tcl:22 +msgid "Create Branch" +msgstr "" + +#: lib/branch_create.tcl:27 +msgid "Create New Branch" +msgstr "" + - #: lib/branch_create.tcl:31 lib/choose_repository.tcl:371 ++#: lib/branch_create.tcl:31 lib/choose_repository.tcl:377 +msgid "Create" +msgstr "" + +#: lib/branch_create.tcl:40 +msgid "Branch Name" +msgstr "" + - #: lib/branch_create.tcl:43 ++#: lib/branch_create.tcl:43 lib/remote_add.tcl:39 lib/tools_dlg.tcl:50 +msgid "Name:" +msgstr "" + +#: lib/branch_create.tcl:58 +msgid "Match Tracking Branch Name" +msgstr "" + +#: lib/branch_create.tcl:66 +msgid "Starting Revision" +msgstr "" + +#: lib/branch_create.tcl:72 +msgid "Update Existing Branch:" +msgstr "" + +#: lib/branch_create.tcl:75 +msgid "No" +msgstr "" + +#: lib/branch_create.tcl:80 +msgid "Fast Forward Only" +msgstr "" + +#: lib/branch_create.tcl:85 lib/checkout_op.tcl:536 +msgid "Reset" +msgstr "" + +#: lib/branch_create.tcl:97 +msgid "Checkout After Creation" +msgstr "" + +#: lib/branch_create.tcl:131 +msgid "Please select a tracking branch." +msgstr "" + +#: lib/branch_create.tcl:140 +#, tcl-format +msgid "Tracking branch %s is not a branch in the remote repository." +msgstr "" + +#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86 +msgid "Please supply a branch name." +msgstr "" + +#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106 +#, tcl-format +msgid "'%s' is not an acceptable branch name." +msgstr "" + +#: lib/branch_delete.tcl:15 +msgid "Delete Branch" +msgstr "" + +#: lib/branch_delete.tcl:20 +msgid "Delete Local Branch" +msgstr "" + +#: lib/branch_delete.tcl:37 +msgid "Local Branches" +msgstr "" + +#: lib/branch_delete.tcl:52 +msgid "Delete Only If Merged Into" +msgstr "" + +#: lib/branch_delete.tcl:54 +msgid "Always (Do not perform merge test.)" +msgstr "" + +#: lib/branch_delete.tcl:103 +#, tcl-format +msgid "The following branches are not completely merged into %s:" +msgstr "" + +#: lib/branch_delete.tcl:115 +msgid "" +"Recovering deleted branches is difficult. \n" +"\n" +" Delete the selected branches?" +msgstr "" + +#: lib/branch_delete.tcl:141 +#, tcl-format +msgid "" +"Failed to delete branches:\n" +"%s" +msgstr "" + +#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22 +msgid "Rename Branch" +msgstr "" + +#: lib/branch_rename.tcl:26 +msgid "Rename" +msgstr "" + +#: lib/branch_rename.tcl:36 +msgid "Branch:" +msgstr "" + +#: lib/branch_rename.tcl:39 +msgid "New Name:" +msgstr "" + +#: lib/branch_rename.tcl:75 +msgid "Please select a branch to rename." +msgstr "" + +#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:201 +#, tcl-format +msgid "Branch '%s' already exists." +msgstr "" + +#: lib/branch_rename.tcl:117 +#, tcl-format +msgid "Failed to rename '%s'." +msgstr "" + +#: lib/browser.tcl:17 +msgid "Starting..." +msgstr "" + +#: lib/browser.tcl:26 +msgid "File Browser" +msgstr "" + +#: lib/browser.tcl:126 lib/browser.tcl:143 +#, tcl-format +msgid "Loading %s..." +msgstr "" + +#: lib/browser.tcl:187 +msgid "[Up To Parent]" +msgstr "" + +#: lib/browser.tcl:267 lib/browser.tcl:273 +msgid "Browse Branch Files" +msgstr "" + - #: lib/browser.tcl:278 lib/choose_repository.tcl:387 - #: lib/choose_repository.tcl:472 lib/choose_repository.tcl:482 - #: lib/choose_repository.tcl:985 ++#: lib/browser.tcl:278 lib/choose_repository.tcl:394 ++#: lib/choose_repository.tcl:480 lib/choose_repository.tcl:491 ++#: lib/choose_repository.tcl:995 +msgid "Browse" +msgstr "" + +#: lib/checkout_op.tcl:84 +#, tcl-format +msgid "Fetching %s from %s" +msgstr "" + +#: lib/checkout_op.tcl:132 +#, tcl-format +msgid "fatal: Cannot resolve %s" +msgstr "" + +#: lib/checkout_op.tcl:145 lib/console.tcl:81 lib/database.tcl:31 ++#: lib/sshkey.tcl:53 +msgid "Close" +msgstr "" + +#: lib/checkout_op.tcl:174 +#, tcl-format +msgid "Branch '%s' does not exist." +msgstr "" + +#: lib/checkout_op.tcl:193 +#, tcl-format +msgid "Failed to configure simplified git-pull for '%s'." +msgstr "" + +#: lib/checkout_op.tcl:228 +#, tcl-format +msgid "" +"Branch '%s' already exists.\n" +"\n" +"It cannot fast-forward to %s.\n" +"A merge is required." +msgstr "" + +#: lib/checkout_op.tcl:242 +#, tcl-format +msgid "Merge strategy '%s' not supported." +msgstr "" + +#: lib/checkout_op.tcl:261 +#, tcl-format +msgid "Failed to update '%s'." +msgstr "" + +#: lib/checkout_op.tcl:273 +msgid "Staging area (index) is already locked." +msgstr "" + +#: lib/checkout_op.tcl:288 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before the current branch can be changed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" + +#: lib/checkout_op.tcl:344 +#, tcl-format +msgid "Updating working directory to '%s'..." +msgstr "" + +#: lib/checkout_op.tcl:345 +msgid "files checked out" +msgstr "" + +#: lib/checkout_op.tcl:375 +#, tcl-format +msgid "Aborted checkout of '%s' (file level merging is required)." +msgstr "" + +#: lib/checkout_op.tcl:376 +msgid "File level merge required." +msgstr "" + +#: lib/checkout_op.tcl:380 +#, tcl-format +msgid "Staying on branch '%s'." +msgstr "" + +#: lib/checkout_op.tcl:451 +msgid "" +"You are no longer on a local branch.\n" +"\n" +"If you wanted to be on a branch, create one now starting from 'This Detached " +"Checkout'." +msgstr "" + +#: lib/checkout_op.tcl:468 lib/checkout_op.tcl:472 +#, tcl-format +msgid "Checked out '%s'." +msgstr "" + +#: lib/checkout_op.tcl:500 +#, tcl-format +msgid "Resetting '%s' to '%s' will lose the following commits:" +msgstr "" + +#: lib/checkout_op.tcl:522 +msgid "Recovering lost commits may not be easy." +msgstr "" + +#: lib/checkout_op.tcl:527 +#, tcl-format +msgid "Reset '%s'?" +msgstr "" + - #: lib/checkout_op.tcl:532 lib/merge.tcl:163 ++#: lib/checkout_op.tcl:532 lib/merge.tcl:164 lib/tools_dlg.tcl:343 +msgid "Visualize" +msgstr "" + +#: lib/checkout_op.tcl:600 +#, tcl-format +msgid "" +"Failed to set current branch.\n" +"\n" +"This working directory is only partially switched. We successfully updated " +"your files, but failed to update an internal Git file.\n" +"\n" +"This should not have occurred. %s will now close and give up." +msgstr "" + +#: lib/choose_font.tcl:39 +msgid "Select" +msgstr "" + +#: lib/choose_font.tcl:53 +msgid "Font Family" +msgstr "" + +#: lib/choose_font.tcl:74 +msgid "Font Size" +msgstr "" + +#: lib/choose_font.tcl:91 +msgid "Font Example" +msgstr "" + +#: lib/choose_font.tcl:103 +msgid "" +"This is example text.\n" +"If you like this text, it can be your font." +msgstr "" + +#: lib/choose_repository.tcl:28 +msgid "Git Gui" +msgstr "" + - #: lib/choose_repository.tcl:81 lib/choose_repository.tcl:376 ++#: lib/choose_repository.tcl:87 lib/choose_repository.tcl:382 +msgid "Create New Repository" +msgstr "" + - #: lib/choose_repository.tcl:87 ++#: lib/choose_repository.tcl:93 +msgid "New..." +msgstr "" + - #: lib/choose_repository.tcl:94 lib/choose_repository.tcl:458 ++#: lib/choose_repository.tcl:100 lib/choose_repository.tcl:465 +msgid "Clone Existing Repository" +msgstr "" + - #: lib/choose_repository.tcl:100 ++#: lib/choose_repository.tcl:106 +msgid "Clone..." +msgstr "" + - #: lib/choose_repository.tcl:107 lib/choose_repository.tcl:974 ++#: lib/choose_repository.tcl:113 lib/choose_repository.tcl:983 +msgid "Open Existing Repository" +msgstr "" + - #: lib/choose_repository.tcl:113 ++#: lib/choose_repository.tcl:119 +msgid "Open..." +msgstr "" + - #: lib/choose_repository.tcl:126 ++#: lib/choose_repository.tcl:132 +msgid "Recent Repositories" +msgstr "" + - #: lib/choose_repository.tcl:132 ++#: lib/choose_repository.tcl:138 +msgid "Open Recent Repository:" +msgstr "" + - #: lib/choose_repository.tcl:296 lib/choose_repository.tcl:303 - #: lib/choose_repository.tcl:310 ++#: lib/choose_repository.tcl:302 lib/choose_repository.tcl:309 ++#: lib/choose_repository.tcl:316 +#, tcl-format +msgid "Failed to create repository %s:" +msgstr "" + - #: lib/choose_repository.tcl:381 lib/choose_repository.tcl:476 ++#: lib/choose_repository.tcl:387 +msgid "Directory:" +msgstr "" + - #: lib/choose_repository.tcl:410 lib/choose_repository.tcl:535 - #: lib/choose_repository.tcl:1007 ++#: lib/choose_repository.tcl:417 lib/choose_repository.tcl:544 ++#: lib/choose_repository.tcl:1017 +msgid "Git Repository" +msgstr "" + - #: lib/choose_repository.tcl:435 ++#: lib/choose_repository.tcl:442 +#, tcl-format +msgid "Directory %s already exists." +msgstr "" + - #: lib/choose_repository.tcl:439 ++#: lib/choose_repository.tcl:446 +#, tcl-format +msgid "File %s already exists." +msgstr "" + - #: lib/choose_repository.tcl:453 ++#: lib/choose_repository.tcl:460 +msgid "Clone" +msgstr "" + - #: lib/choose_repository.tcl:466 - msgid "URL:" ++#: lib/choose_repository.tcl:473 ++msgid "Source Location:" +msgstr "" + - #: lib/choose_repository.tcl:487 ++#: lib/choose_repository.tcl:484 ++msgid "Target Directory:" ++msgstr "" ++ ++#: lib/choose_repository.tcl:496 +msgid "Clone Type:" +msgstr "" + - #: lib/choose_repository.tcl:493 ++#: lib/choose_repository.tcl:502 +msgid "Standard (Fast, Semi-Redundant, Hardlinks)" +msgstr "" + - #: lib/choose_repository.tcl:499 ++#: lib/choose_repository.tcl:508 +msgid "Full Copy (Slower, Redundant Backup)" +msgstr "" + - #: lib/choose_repository.tcl:505 ++#: lib/choose_repository.tcl:514 +msgid "Shared (Fastest, Not Recommended, No Backup)" +msgstr "" + - #: lib/choose_repository.tcl:541 lib/choose_repository.tcl:588 - #: lib/choose_repository.tcl:734 lib/choose_repository.tcl:804 - #: lib/choose_repository.tcl:1013 lib/choose_repository.tcl:1021 ++#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597 ++#: lib/choose_repository.tcl:743 lib/choose_repository.tcl:813 ++#: lib/choose_repository.tcl:1023 lib/choose_repository.tcl:1031 +#, tcl-format +msgid "Not a Git repository: %s" +msgstr "" + - #: lib/choose_repository.tcl:577 ++#: lib/choose_repository.tcl:586 +msgid "Standard only available for local repository." +msgstr "" + - #: lib/choose_repository.tcl:581 ++#: lib/choose_repository.tcl:590 +msgid "Shared only available for local repository." +msgstr "" + - #: lib/choose_repository.tcl:602 ++#: lib/choose_repository.tcl:611 +#, tcl-format +msgid "Location %s already exists." +msgstr "" + - #: lib/choose_repository.tcl:613 ++#: lib/choose_repository.tcl:622 +msgid "Failed to configure origin" +msgstr "" + - #: lib/choose_repository.tcl:625 ++#: lib/choose_repository.tcl:634 +msgid "Counting objects" +msgstr "" + - #: lib/choose_repository.tcl:626 ++#: lib/choose_repository.tcl:635 +msgid "buckets" +msgstr "" + - #: lib/choose_repository.tcl:650 ++#: lib/choose_repository.tcl:659 +#, tcl-format +msgid "Unable to copy objects/info/alternates: %s" +msgstr "" + - #: lib/choose_repository.tcl:686 ++#: lib/choose_repository.tcl:695 +#, tcl-format +msgid "Nothing to clone from %s." +msgstr "" + - #: lib/choose_repository.tcl:688 lib/choose_repository.tcl:902 - #: lib/choose_repository.tcl:914 ++#: lib/choose_repository.tcl:697 lib/choose_repository.tcl:911 ++#: lib/choose_repository.tcl:923 +msgid "The 'master' branch has not been initialized." +msgstr "" + - #: lib/choose_repository.tcl:701 ++#: lib/choose_repository.tcl:710 +msgid "Hardlinks are unavailable. Falling back to copying." +msgstr "" + - #: lib/choose_repository.tcl:713 ++#: lib/choose_repository.tcl:722 +#, tcl-format +msgid "Cloning from %s" +msgstr "" + - #: lib/choose_repository.tcl:744 ++#: lib/choose_repository.tcl:753 +msgid "Copying objects" +msgstr "" + - #: lib/choose_repository.tcl:745 ++#: lib/choose_repository.tcl:754 +msgid "KiB" +msgstr "" + - #: lib/choose_repository.tcl:769 ++#: lib/choose_repository.tcl:778 +#, tcl-format +msgid "Unable to copy object: %s" +msgstr "" + - #: lib/choose_repository.tcl:779 ++#: lib/choose_repository.tcl:788 +msgid "Linking objects" +msgstr "" + - #: lib/choose_repository.tcl:780 ++#: lib/choose_repository.tcl:789 +msgid "objects" +msgstr "" + - #: lib/choose_repository.tcl:788 ++#: lib/choose_repository.tcl:797 +#, tcl-format +msgid "Unable to hardlink object: %s" +msgstr "" + - #: lib/choose_repository.tcl:843 ++#: lib/choose_repository.tcl:852 +msgid "Cannot fetch branches and objects. See console output for details." +msgstr "" + - #: lib/choose_repository.tcl:854 ++#: lib/choose_repository.tcl:863 +msgid "Cannot fetch tags. See console output for details." +msgstr "" + - #: lib/choose_repository.tcl:878 ++#: lib/choose_repository.tcl:887 +msgid "Cannot determine HEAD. See console output for details." +msgstr "" + - #: lib/choose_repository.tcl:887 ++#: lib/choose_repository.tcl:896 +#, tcl-format +msgid "Unable to cleanup %s" +msgstr "" + - #: lib/choose_repository.tcl:893 ++#: lib/choose_repository.tcl:902 +msgid "Clone failed." +msgstr "" + - #: lib/choose_repository.tcl:900 ++#: lib/choose_repository.tcl:909 +msgid "No default branch obtained." +msgstr "" + - #: lib/choose_repository.tcl:911 ++#: lib/choose_repository.tcl:920 +#, tcl-format +msgid "Cannot resolve %s as a commit." +msgstr "" + - #: lib/choose_repository.tcl:923 ++#: lib/choose_repository.tcl:932 +msgid "Creating working directory" +msgstr "" + - #: lib/choose_repository.tcl:924 lib/index.tcl:65 lib/index.tcl:127 - #: lib/index.tcl:193 ++#: lib/choose_repository.tcl:933 lib/index.tcl:65 lib/index.tcl:128 ++#: lib/index.tcl:196 +msgid "files" +msgstr "" + - #: lib/choose_repository.tcl:953 ++#: lib/choose_repository.tcl:962 +msgid "Initial file checkout failed." +msgstr "" + - #: lib/choose_repository.tcl:969 ++#: lib/choose_repository.tcl:978 +msgid "Open" +msgstr "" + - #: lib/choose_repository.tcl:979 ++#: lib/choose_repository.tcl:988 +msgid "Repository:" +msgstr "" + - #: lib/choose_repository.tcl:1027 ++#: lib/choose_repository.tcl:1037 +#, tcl-format +msgid "Failed to open repository %s:" +msgstr "" + +#: lib/choose_rev.tcl:53 +msgid "This Detached Checkout" +msgstr "" + +#: lib/choose_rev.tcl:60 +msgid "Revision Expression:" +msgstr "" + +#: lib/choose_rev.tcl:74 +msgid "Local Branch" +msgstr "" + +#: lib/choose_rev.tcl:79 +msgid "Tracking Branch" +msgstr "" + +#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:538 +msgid "Tag" +msgstr "" + +#: lib/choose_rev.tcl:317 +#, tcl-format +msgid "Invalid revision: %s" +msgstr "" + +#: lib/choose_rev.tcl:338 +msgid "No revision selected." +msgstr "" + +#: lib/choose_rev.tcl:346 +msgid "Revision expression is empty." +msgstr "" + +#: lib/choose_rev.tcl:531 +msgid "Updated" +msgstr "" + +#: lib/choose_rev.tcl:559 +msgid "URL" +msgstr "" + +#: lib/commit.tcl:9 +msgid "" +"There is nothing to amend.\n" +"\n" +"You are about to create the initial commit. There is no commit before this " +"to amend.\n" +msgstr "" + +#: lib/commit.tcl:18 +msgid "" +"Cannot amend while merging.\n" +"\n" +"You are currently in the middle of a merge that has not been fully " +"completed. You cannot amend the prior commit unless you first abort the " +"current merge activity.\n" +msgstr "" + +#: lib/commit.tcl:49 +msgid "Error loading commit data for amend:" +msgstr "" + +#: lib/commit.tcl:76 +msgid "Unable to obtain your identity:" +msgstr "" + +#: lib/commit.tcl:81 +msgid "Invalid GIT_COMMITTER_IDENT:" +msgstr "" + +#: lib/commit.tcl:133 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before another commit can be created.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" + - #: lib/commit.tcl:154 ++#: lib/commit.tcl:156 +#, tcl-format +msgid "" +"Unmerged files cannot be committed.\n" +"\n" +"File %s has merge conflicts. You must resolve them and stage the file " +"before committing.\n" +msgstr "" + - #: lib/commit.tcl:162 ++#: lib/commit.tcl:164 +#, tcl-format +msgid "" +"Unknown file state %s detected.\n" +"\n" +"File %s cannot be committed by this program.\n" +msgstr "" + - #: lib/commit.tcl:170 ++#: lib/commit.tcl:172 +msgid "" +"No changes to commit.\n" +"\n" +"You must stage at least 1 file before you can commit.\n" +msgstr "" + - #: lib/commit.tcl:183 ++#: lib/commit.tcl:187 +msgid "" +"Please supply a commit message.\n" +"\n" +"A good commit message has the following format:\n" +"\n" +"- First line: Describe in one sentence what you did.\n" +"- Second line: Blank\n" +"- Remaining lines: Describe why this change is good.\n" +msgstr "" + - #: lib/commit.tcl:207 ++#: lib/commit.tcl:211 +#, tcl-format +msgid "warning: Tcl does not support encoding '%s'." +msgstr "" + - #: lib/commit.tcl:221 ++#: lib/commit.tcl:227 +msgid "Calling pre-commit hook..." +msgstr "" + - #: lib/commit.tcl:236 ++#: lib/commit.tcl:242 +msgid "Commit declined by pre-commit hook." +msgstr "" + - #: lib/commit.tcl:259 ++#: lib/commit.tcl:265 +msgid "Calling commit-msg hook..." +msgstr "" + - #: lib/commit.tcl:274 ++#: lib/commit.tcl:280 +msgid "Commit declined by commit-msg hook." +msgstr "" + - #: lib/commit.tcl:287 ++#: lib/commit.tcl:293 +msgid "Committing changes..." +msgstr "" + - #: lib/commit.tcl:303 ++#: lib/commit.tcl:309 +msgid "write-tree failed:" +msgstr "" + - #: lib/commit.tcl:304 lib/commit.tcl:348 lib/commit.tcl:368 ++#: lib/commit.tcl:310 lib/commit.tcl:354 lib/commit.tcl:374 +msgid "Commit failed." +msgstr "" + - #: lib/commit.tcl:321 ++#: lib/commit.tcl:327 +#, tcl-format +msgid "Commit %s appears to be corrupt" +msgstr "" + - #: lib/commit.tcl:326 ++#: lib/commit.tcl:332 +msgid "" +"No changes to commit.\n" +"\n" +"No files were modified by this commit and it was not a merge commit.\n" +"\n" +"A rescan will be automatically started now.\n" +msgstr "" + - #: lib/commit.tcl:333 ++#: lib/commit.tcl:339 +msgid "No changes to commit." +msgstr "" + - #: lib/commit.tcl:347 ++#: lib/commit.tcl:353 +msgid "commit-tree failed:" +msgstr "" + - #: lib/commit.tcl:367 ++#: lib/commit.tcl:373 +msgid "update-ref failed:" +msgstr "" + - #: lib/commit.tcl:454 ++#: lib/commit.tcl:461 +#, tcl-format +msgid "Created commit %s: %s" +msgstr "" + +#: lib/console.tcl:59 +msgid "Working... please wait..." +msgstr "" + +#: lib/console.tcl:186 +msgid "Success" +msgstr "" + +#: lib/console.tcl:200 +msgid "Error: Command Failed" +msgstr "" + +#: lib/database.tcl:43 +msgid "Number of loose objects" +msgstr "" + +#: lib/database.tcl:44 +msgid "Disk space used by loose objects" +msgstr "" + +#: lib/database.tcl:45 +msgid "Number of packed objects" +msgstr "" + +#: lib/database.tcl:46 +msgid "Number of packs" +msgstr "" + +#: lib/database.tcl:47 +msgid "Disk space used by packed objects" +msgstr "" + +#: lib/database.tcl:48 +msgid "Packed objects waiting for pruning" +msgstr "" + +#: lib/database.tcl:49 +msgid "Garbage files" +msgstr "" + +#: lib/database.tcl:72 +msgid "Compressing the object database" +msgstr "" + +#: lib/database.tcl:83 +msgid "Verifying the object database with fsck-objects" +msgstr "" + +#: lib/database.tcl:108 +#, tcl-format +msgid "" +"This repository currently has approximately %i loose objects.\n" +"\n" +"To maintain optimal performance it is strongly recommended that you compress " +"the database when more than %i loose objects exist.\n" +"\n" +"Compress the database now?" +msgstr "" + +#: lib/date.tcl:25 +#, tcl-format +msgid "Invalid date from Git: %s" +msgstr "" + - #: lib/diff.tcl:44 ++#: lib/diff.tcl:59 +#, tcl-format +msgid "" +"No differences detected.\n" +"\n" +"%s has no changes.\n" +"\n" +"The modification date of this file was updated by another application, but " +"the content within the file was not changed.\n" +"\n" +"A rescan will be automatically started to find other files which may have " +"the same state." +msgstr "" + - #: lib/diff.tcl:83 ++#: lib/diff.tcl:99 +#, tcl-format +msgid "Loading diff of %s..." +msgstr "" + - #: lib/diff.tcl:116 lib/diff.tcl:190 ++#: lib/diff.tcl:120 ++msgid "" ++"LOCAL: deleted\n" ++"REMOTE:\n" ++msgstr "" ++ ++#: lib/diff.tcl:125 ++msgid "" ++"REMOTE: deleted\n" ++"LOCAL:\n" ++msgstr "" ++ ++#: lib/diff.tcl:132 ++msgid "LOCAL:\n" ++msgstr "" ++ ++#: lib/diff.tcl:135 ++msgid "REMOTE:\n" ++msgstr "" ++ ++#: lib/diff.tcl:197 lib/diff.tcl:296 +#, tcl-format +msgid "Unable to display %s" +msgstr "" + - #: lib/diff.tcl:117 ++#: lib/diff.tcl:198 +msgid "Error loading file:" +msgstr "" + - #: lib/diff.tcl:124 ++#: lib/diff.tcl:205 +msgid "Git Repository (subproject)" +msgstr "" + - #: lib/diff.tcl:136 ++#: lib/diff.tcl:217 +msgid "* Binary file (not showing content)." +msgstr "" + - #: lib/diff.tcl:191 - msgid "Error loading diff:" ++#: lib/diff.tcl:222 ++#, tcl-format ++msgid "" ++"* Untracked file is %d bytes.\n" ++"* Showing only first %d bytes.\n" ++msgstr "" ++ ++#: lib/diff.tcl:228 ++#, tcl-format ++msgid "" ++"\n" ++"* Untracked file clipped here by %s.\n" ++"* To see the entire file, use an external editor.\n" +msgstr "" + - #: lib/diff.tcl:313 ++#: lib/diff.tcl:436 +msgid "Failed to unstage selected hunk." +msgstr "" + - #: lib/diff.tcl:320 ++#: lib/diff.tcl:443 +msgid "Failed to stage selected hunk." +msgstr "" + - #: lib/diff.tcl:386 ++#: lib/diff.tcl:509 +msgid "Failed to unstage selected line." +msgstr "" + - #: lib/diff.tcl:394 ++#: lib/diff.tcl:517 +msgid "Failed to stage selected line." +msgstr "" + ++#: lib/encoding.tcl:443 ++msgid "Default" ++msgstr "" ++ ++#: lib/encoding.tcl:448 ++#, tcl-format ++msgid "System (%s)" ++msgstr "" ++ ++#: lib/encoding.tcl:459 lib/encoding.tcl:465 ++msgid "Other" ++msgstr "" ++ +#: lib/error.tcl:20 lib/error.tcl:114 +msgid "error" +msgstr "" + +#: lib/error.tcl:36 +msgid "warning" +msgstr "" + +#: lib/error.tcl:94 +msgid "You must correct the above errors before committing." +msgstr "" + +#: lib/index.tcl:6 +msgid "Unable to unlock the index." +msgstr "" + +#: lib/index.tcl:15 +msgid "Index Error" +msgstr "" + +#: lib/index.tcl:21 +msgid "" +"Updating the Git index failed. A rescan will be automatically started to " +"resynchronize git-gui." +msgstr "" + +#: lib/index.tcl:27 +msgid "Continue" +msgstr "" + +#: lib/index.tcl:31 +msgid "Unlock Index" +msgstr "" + - #: lib/index.tcl:282 ++#: lib/index.tcl:287 +#, tcl-format +msgid "Unstaging %s from commit" +msgstr "" + - #: lib/index.tcl:313 ++#: lib/index.tcl:326 +msgid "Ready to commit." +msgstr "" + - #: lib/index.tcl:326 ++#: lib/index.tcl:339 +#, tcl-format +msgid "Adding %s" +msgstr "" + - #: lib/index.tcl:381 ++#: lib/index.tcl:396 +#, tcl-format +msgid "Revert changes in file %s?" +msgstr "" + - #: lib/index.tcl:383 ++#: lib/index.tcl:398 +#, tcl-format +msgid "Revert changes in these %i files?" +msgstr "" + - #: lib/index.tcl:391 ++#: lib/index.tcl:406 +msgid "Any unstaged changes will be permanently lost by the revert." +msgstr "" + - #: lib/index.tcl:394 ++#: lib/index.tcl:409 +msgid "Do Nothing" +msgstr "" + ++#: lib/index.tcl:427 ++msgid "Reverting selected files" ++msgstr "" ++ ++#: lib/index.tcl:431 ++#, tcl-format ++msgid "Reverting %s" ++msgstr "" ++ +#: lib/merge.tcl:13 +msgid "" +"Cannot merge while amending.\n" +"\n" +"You must finish amending this commit before starting any type of merge.\n" +msgstr "" + +#: lib/merge.tcl:27 +msgid "" +"Last scanned state does not match repository state.\n" +"\n" +"Another Git program has modified this repository since the last scan. A " +"rescan must be performed before a merge can be performed.\n" +"\n" +"The rescan will be automatically started now.\n" +msgstr "" + - #: lib/merge.tcl:44 ++#: lib/merge.tcl:45 +#, tcl-format +msgid "" +"You are in the middle of a conflicted merge.\n" +"\n" +"File %s has merge conflicts.\n" +"\n" +"You must resolve them, stage the file, and commit to complete the current " +"merge. Only then can you begin another merge.\n" +msgstr "" + - #: lib/merge.tcl:54 ++#: lib/merge.tcl:55 +#, tcl-format +msgid "" +"You are in the middle of a change.\n" +"\n" +"File %s is modified.\n" +"\n" +"You should complete the current commit before starting a merge. Doing so " +"will help you abort a failed merge, should the need arise.\n" +msgstr "" + - #: lib/merge.tcl:106 ++#: lib/merge.tcl:107 +#, tcl-format +msgid "%s of %s" +msgstr "" + - #: lib/merge.tcl:119 ++#: lib/merge.tcl:120 +#, tcl-format +msgid "Merging %s and %s..." +msgstr "" + - #: lib/merge.tcl:130 ++#: lib/merge.tcl:131 +msgid "Merge completed successfully." +msgstr "" + - #: lib/merge.tcl:132 ++#: lib/merge.tcl:133 +msgid "Merge failed. Conflict resolution is required." +msgstr "" + - #: lib/merge.tcl:157 ++#: lib/merge.tcl:158 +#, tcl-format +msgid "Merge Into %s" +msgstr "" + - #: lib/merge.tcl:176 ++#: lib/merge.tcl:177 +msgid "Revision To Merge" +msgstr "" + - #: lib/merge.tcl:211 ++#: lib/merge.tcl:212 +msgid "" +"Cannot abort while amending.\n" +"\n" +"You must finish amending this commit.\n" +msgstr "" + - #: lib/merge.tcl:221 ++#: lib/merge.tcl:222 +msgid "" +"Abort merge?\n" +"\n" +"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with aborting the current merge?" +msgstr "" + - #: lib/merge.tcl:227 ++#: lib/merge.tcl:228 +msgid "" +"Reset changes?\n" +"\n" +"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n" +"\n" +"Continue with resetting the current changes?" +msgstr "" + - #: lib/merge.tcl:238 ++#: lib/merge.tcl:239 +msgid "Aborting" +msgstr "" + - #: lib/merge.tcl:238 ++#: lib/merge.tcl:239 +msgid "files reset" +msgstr "" + - #: lib/merge.tcl:266 ++#: lib/merge.tcl:267 +msgid "Abort failed." +msgstr "" + - #: lib/merge.tcl:268 ++#: lib/merge.tcl:269 +msgid "Abort completed. Ready." +msgstr "" + - #: lib/option.tcl:95 ++#: lib/mergetool.tcl:8 ++msgid "Force resolution to the base version?" ++msgstr "" ++ ++#: lib/mergetool.tcl:9 ++msgid "Force resolution to this branch?" ++msgstr "" ++ ++#: lib/mergetool.tcl:10 ++msgid "Force resolution to the other branch?" ++msgstr "" ++ ++#: lib/mergetool.tcl:14 ++#, tcl-format ++msgid "" ++"Note that the diff shows only conflicting changes.\n" ++"\n" ++"%s will be overwritten.\n" ++"\n" ++"This operation can be undone only by restarting the merge." ++msgstr "" ++ ++#: lib/mergetool.tcl:45 ++#, tcl-format ++msgid "File %s seems to have unresolved conflicts, still stage?" ++msgstr "" ++ ++#: lib/mergetool.tcl:60 ++#, tcl-format ++msgid "Adding resolution for %s" ++msgstr "" ++ ++#: lib/mergetool.tcl:141 ++msgid "Cannot resolve deletion or link conflicts using a tool" ++msgstr "" ++ ++#: lib/mergetool.tcl:146 ++msgid "Conflict file does not exist" ++msgstr "" ++ ++#: lib/mergetool.tcl:264 ++#, tcl-format ++msgid "Not a GUI merge tool: '%s'" ++msgstr "" ++ ++#: lib/mergetool.tcl:268 ++#, tcl-format ++msgid "Unsupported merge tool '%s'" ++msgstr "" ++ ++#: lib/mergetool.tcl:303 ++msgid "Merge tool is already running, terminate it?" ++msgstr "" ++ ++#: lib/mergetool.tcl:323 ++#, tcl-format ++msgid "" ++"Error retrieving versions:\n" ++"%s" ++msgstr "" ++ ++#: lib/mergetool.tcl:343 ++#, tcl-format ++msgid "" ++"Could not start the merge tool:\n" ++"\n" ++"%s" ++msgstr "" ++ ++#: lib/mergetool.tcl:347 ++msgid "Running merge tool..." ++msgstr "" ++ ++#: lib/mergetool.tcl:375 lib/mergetool.tcl:383 ++msgid "Merge tool failed." ++msgstr "" ++ ++#: lib/option.tcl:11 ++#, tcl-format ++msgid "Invalid global encoding '%s'" ++msgstr "" ++ ++#: lib/option.tcl:19 ++#, tcl-format ++msgid "Invalid repo encoding '%s'" ++msgstr "" ++ ++#: lib/option.tcl:117 +msgid "Restore Defaults" +msgstr "" + - #: lib/option.tcl:99 ++#: lib/option.tcl:121 +msgid "Save" +msgstr "" + - #: lib/option.tcl:109 ++#: lib/option.tcl:131 +#, tcl-format +msgid "%s Repository" +msgstr "" + - #: lib/option.tcl:110 ++#: lib/option.tcl:132 +msgid "Global (All Repositories)" +msgstr "" + - #: lib/option.tcl:116 ++#: lib/option.tcl:138 +msgid "User Name" +msgstr "" + - #: lib/option.tcl:117 ++#: lib/option.tcl:139 +msgid "Email Address" +msgstr "" + - #: lib/option.tcl:119 ++#: lib/option.tcl:141 +msgid "Summarize Merge Commits" +msgstr "" + - #: lib/option.tcl:120 ++#: lib/option.tcl:142 +msgid "Merge Verbosity" +msgstr "" + - #: lib/option.tcl:121 ++#: lib/option.tcl:143 +msgid "Show Diffstat After Merge" +msgstr "" + - #: lib/option.tcl:123 ++#: lib/option.tcl:144 ++msgid "Use Merge Tool" ++msgstr "" ++ ++#: lib/option.tcl:146 +msgid "Trust File Modification Timestamps" +msgstr "" + - #: lib/option.tcl:124 ++#: lib/option.tcl:147 +msgid "Prune Tracking Branches During Fetch" +msgstr "" + - #: lib/option.tcl:125 ++#: lib/option.tcl:148 +msgid "Match Tracking Branches" +msgstr "" + - #: lib/option.tcl:126 ++#: lib/option.tcl:149 +msgid "Blame Copy Only On Changed Files" +msgstr "" + - #: lib/option.tcl:127 ++#: lib/option.tcl:150 +msgid "Minimum Letters To Blame Copy On" +msgstr "" + - #: lib/option.tcl:128 ++#: lib/option.tcl:151 ++msgid "Blame History Context Radius (days)" ++msgstr "" ++ ++#: lib/option.tcl:152 +msgid "Number of Diff Context Lines" +msgstr "" + - #: lib/option.tcl:129 ++#: lib/option.tcl:153 +msgid "Commit Message Text Width" +msgstr "" + - #: lib/option.tcl:130 ++#: lib/option.tcl:154 +msgid "New Branch Name Template" +msgstr "" + - #: lib/option.tcl:194 ++#: lib/option.tcl:155 ++msgid "Default File Contents Encoding" ++msgstr "" ++ ++#: lib/option.tcl:203 ++msgid "Change" ++msgstr "" ++ ++#: lib/option.tcl:230 +msgid "Spelling Dictionary:" +msgstr "" + - #: lib/option.tcl:218 ++#: lib/option.tcl:254 +msgid "Change Font" +msgstr "" + - #: lib/option.tcl:222 ++#: lib/option.tcl:258 +#, tcl-format +msgid "Choose %s" +msgstr "" + - #: lib/option.tcl:228 ++#: lib/option.tcl:264 +msgid "pt." +msgstr "" + - #: lib/option.tcl:242 ++#: lib/option.tcl:278 +msgid "Preferences" +msgstr "" + - #: lib/option.tcl:277 ++#: lib/option.tcl:314 +msgid "Failed to completely save options:" +msgstr "" + - #: lib/remote.tcl:165 ++#: lib/remote.tcl:163 ++msgid "Remove Remote" ++msgstr "" ++ ++#: lib/remote.tcl:168 +msgid "Prune from" +msgstr "" + - #: lib/remote.tcl:170 ++#: lib/remote.tcl:173 +msgid "Fetch from" +msgstr "" + - #: lib/remote.tcl:213 ++#: lib/remote.tcl:215 +msgid "Push to" +msgstr "" + ++#: lib/remote_add.tcl:19 ++msgid "Add Remote" ++msgstr "" ++ ++#: lib/remote_add.tcl:24 ++msgid "Add New Remote" ++msgstr "" ++ ++#: lib/remote_add.tcl:28 lib/tools_dlg.tcl:36 ++msgid "Add" ++msgstr "" ++ ++#: lib/remote_add.tcl:37 ++msgid "Remote Details" ++msgstr "" ++ ++#: lib/remote_add.tcl:50 ++msgid "Location:" ++msgstr "" ++ ++#: lib/remote_add.tcl:62 ++msgid "Further Action" ++msgstr "" ++ ++#: lib/remote_add.tcl:65 ++msgid "Fetch Immediately" ++msgstr "" ++ ++#: lib/remote_add.tcl:71 ++msgid "Initialize Remote Repository and Push" ++msgstr "" ++ ++#: lib/remote_add.tcl:77 ++msgid "Do Nothing Else Now" ++msgstr "" ++ ++#: lib/remote_add.tcl:101 ++msgid "Please supply a remote name." ++msgstr "" ++ ++#: lib/remote_add.tcl:114 ++#, tcl-format ++msgid "'%s' is not an acceptable remote name." ++msgstr "" ++ ++#: lib/remote_add.tcl:125 ++#, tcl-format ++msgid "Failed to add remote '%s' of location '%s'." ++msgstr "" ++ ++#: lib/remote_add.tcl:133 lib/transport.tcl:6 ++#, tcl-format ++msgid "fetch %s" ++msgstr "" ++ ++#: lib/remote_add.tcl:134 ++#, tcl-format ++msgid "Fetching the %s" ++msgstr "" ++ ++#: lib/remote_add.tcl:157 ++#, tcl-format ++msgid "Do not know how to initialize repository at location '%s'." ++msgstr "" ++ ++#: lib/remote_add.tcl:163 lib/transport.tcl:25 lib/transport.tcl:71 ++#, tcl-format ++msgid "push %s" ++msgstr "" ++ ++#: lib/remote_add.tcl:164 ++#, tcl-format ++msgid "Setting up the %s (at %s)" ++msgstr "" ++ +#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34 - msgid "Delete Remote Branch" ++msgid "Delete Branch Remotely" +msgstr "" + +#: lib/remote_branch_delete.tcl:47 +msgid "From Repository" +msgstr "" + +#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123 +msgid "Remote:" +msgstr "" + +#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138 - msgid "Arbitrary URL:" ++msgid "Arbitrary Location:" +msgstr "" + +#: lib/remote_branch_delete.tcl:84 +msgid "Branches" +msgstr "" + +#: lib/remote_branch_delete.tcl:109 +msgid "Delete Only If" +msgstr "" + +#: lib/remote_branch_delete.tcl:111 +msgid "Merged Into:" +msgstr "" + +#: lib/remote_branch_delete.tcl:119 +msgid "Always (Do not perform merge checks)" +msgstr "" + +#: lib/remote_branch_delete.tcl:152 +msgid "A branch is required for 'Merged Into'." +msgstr "" + +#: lib/remote_branch_delete.tcl:184 +#, tcl-format +msgid "" +"The following branches are not completely merged into %s:\n" +"\n" +" - %s" +msgstr "" + +#: lib/remote_branch_delete.tcl:189 +#, tcl-format +msgid "" +"One or more of the merge tests failed because you have not fetched the " +"necessary commits. Try fetching from %s first." +msgstr "" + +#: lib/remote_branch_delete.tcl:207 +msgid "Please select one or more branches to delete." +msgstr "" + +#: lib/remote_branch_delete.tcl:216 +msgid "" +"Recovering deleted branches is difficult.\n" +"\n" +"Delete the selected branches?" +msgstr "" + +#: lib/remote_branch_delete.tcl:226 +#, tcl-format +msgid "Deleting branches from %s" +msgstr "" + +#: lib/remote_branch_delete.tcl:286 +msgid "No repository selected." +msgstr "" + +#: lib/remote_branch_delete.tcl:291 +#, tcl-format +msgid "Scanning %s..." +msgstr "" + ++#: lib/search.tcl:21 ++msgid "Find:" ++msgstr "" ++ ++#: lib/search.tcl:23 ++msgid "Next" ++msgstr "" ++ ++#: lib/search.tcl:24 ++msgid "Prev" ++msgstr "" ++ ++#: lib/search.tcl:25 ++msgid "Case-Sensitive" ++msgstr "" ++ +#: lib/shortcut.tcl:20 lib/shortcut.tcl:61 +msgid "Cannot write shortcut:" +msgstr "" + +#: lib/shortcut.tcl:136 +msgid "Cannot write icon:" +msgstr "" + +#: lib/spellcheck.tcl:57 +msgid "Unsupported spell checker" +msgstr "" + +#: lib/spellcheck.tcl:65 +msgid "Spell checking is unavailable" +msgstr "" + +#: lib/spellcheck.tcl:68 +msgid "Invalid spell checking configuration" +msgstr "" + +#: lib/spellcheck.tcl:70 +#, tcl-format +msgid "Reverting dictionary to %s." +msgstr "" + +#: lib/spellcheck.tcl:73 +msgid "Spell checker silently failed on startup" +msgstr "" + +#: lib/spellcheck.tcl:80 +msgid "Unrecognized spell checker" +msgstr "" + +#: lib/spellcheck.tcl:186 +msgid "No Suggestions" +msgstr "" + - #: lib/spellcheck.tcl:387 ++#: lib/spellcheck.tcl:388 +msgid "Unexpected EOF from spell checker" +msgstr "" + - #: lib/spellcheck.tcl:391 ++#: lib/spellcheck.tcl:392 +msgid "Spell Checker Failed" +msgstr "" + ++#: lib/sshkey.tcl:31 ++msgid "No keys found." ++msgstr "" ++ ++#: lib/sshkey.tcl:34 ++#, tcl-format ++msgid "Found a public key in: %s" ++msgstr "" ++ ++#: lib/sshkey.tcl:40 ++msgid "Generate Key" ++msgstr "" ++ ++#: lib/sshkey.tcl:56 ++msgid "Copy To Clipboard" ++msgstr "" ++ ++#: lib/sshkey.tcl:70 ++msgid "Your OpenSSH Public Key" ++msgstr "" ++ ++#: lib/sshkey.tcl:78 ++msgid "Generating..." ++msgstr "" ++ ++#: lib/sshkey.tcl:84 ++#, tcl-format ++msgid "" ++"Could not start ssh-keygen:\n" ++"\n" ++"%s" ++msgstr "" ++ ++#: lib/sshkey.tcl:111 ++msgid "Generation failed." ++msgstr "" ++ ++#: lib/sshkey.tcl:118 ++msgid "Generation succeded, but no keys found." ++msgstr "" ++ ++#: lib/sshkey.tcl:121 ++#, tcl-format ++msgid "Your key is in: %s" ++msgstr "" ++ +#: lib/status_bar.tcl:83 +#, tcl-format +msgid "%s ... %*i of %*i %s (%3i%%)" +msgstr "" + - #: lib/transport.tcl:6 ++#: lib/tools.tcl:75 +#, tcl-format - msgid "fetch %s" ++msgid "Running %s requires a selected file." ++msgstr "" ++ ++#: lib/tools.tcl:90 ++#, tcl-format ++msgid "Are you sure you want to run %s?" ++msgstr "" ++ ++#: lib/tools.tcl:110 ++#, tcl-format ++msgid "Tool: %s" ++msgstr "" ++ ++#: lib/tools.tcl:111 ++#, tcl-format ++msgid "Running: %s" ++msgstr "" ++ ++#: lib/tools.tcl:149 ++#, tcl-format ++msgid "Tool completed succesfully: %s" ++msgstr "" ++ ++#: lib/tools.tcl:151 ++#, tcl-format ++msgid "Tool failed: %s" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:22 ++msgid "Add Tool" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:28 ++msgid "Add New Tool Command" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:33 ++msgid "Add globally" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:45 ++msgid "Tool Details" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:48 ++msgid "Use '/' separators to create a submenu tree:" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:61 ++msgid "Command:" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:74 ++msgid "Show a dialog before running" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:80 ++msgid "Ask the user to select a revision (sets $REVISION)" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:85 ++msgid "Ask the user for additional arguments (sets $ARGS)" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:92 ++msgid "Don't show the command output window" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:97 ++msgid "Run only if a diff is selected ($FILENAME not empty)" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:121 ++msgid "Please supply a name for the tool." ++msgstr "" ++ ++#: lib/tools_dlg.tcl:129 ++#, tcl-format ++msgid "Tool '%s' already exists." ++msgstr "" ++ ++#: lib/tools_dlg.tcl:151 ++#, tcl-format ++msgid "" ++"Could not add tool:\n" ++"%s" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:190 ++msgid "Remove Tool" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:196 ++msgid "Remove Tool Commands" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:200 ++msgid "Remove" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:236 ++msgid "(Blue denotes repository-local tools)" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:297 ++#, tcl-format ++msgid "Run Command: %s" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:311 ++msgid "Arguments" ++msgstr "" ++ ++#: lib/tools_dlg.tcl:348 ++msgid "OK" +msgstr "" + +#: lib/transport.tcl:7 +#, tcl-format +msgid "Fetching new changes from %s" +msgstr "" + +#: lib/transport.tcl:18 +#, tcl-format +msgid "remote prune %s" +msgstr "" + +#: lib/transport.tcl:19 +#, tcl-format +msgid "Pruning tracking branches deleted from %s" +msgstr "" + - #: lib/transport.tcl:25 lib/transport.tcl:71 - #, tcl-format - msgid "push %s" - msgstr "" - +#: lib/transport.tcl:26 +#, tcl-format +msgid "Pushing changes to %s" +msgstr "" + +#: lib/transport.tcl:72 +#, tcl-format +msgid "Pushing %s %s to %s" +msgstr "" + +#: lib/transport.tcl:89 +msgid "Push Branches" +msgstr "" + +#: lib/transport.tcl:103 +msgid "Source Branches" +msgstr "" + +#: lib/transport.tcl:120 +msgid "Destination Repository" +msgstr "" + +#: lib/transport.tcl:158 +msgid "Transfer Options" +msgstr "" + +#: lib/transport.tcl:160 +msgid "Force overwrite existing branch (may discard changes)" +msgstr "" + +#: lib/transport.tcl:164 +msgid "Use thin pack (for slow network connections)" +msgstr "" + +#: lib/transport.tcl:168 +msgid "Include tags" +msgstr ""