diff options
Diffstat (limited to 'gitk-git/gitk')
-rw-r--r-- | gitk-git/gitk | 530 |
1 files changed, 392 insertions, 138 deletions
diff --git a/gitk-git/gitk b/gitk-git/gitk index 087c4ac73..bcebc87f7 100644 --- a/gitk-git/gitk +++ b/gitk-git/gitk @@ -269,7 +269,7 @@ proc parseviewrevs {view revs} { lappend badrev $line } } - error_popup "Error parsing revisions: $err" + error_popup "[mc "Error parsing revisions:"] $err" return {} } set ret {} @@ -307,7 +307,7 @@ proc start_rev_list {view} { global startmsecs commitidx viewcomplete curview global tclencoding global viewargs viewargscmd viewfiles vfilelimit - global showlocalchanges commitinterest + global showlocalchanges global viewactive viewinstances vmergeonly global mainheadid global vcanopt vflags vrevs vorigargs @@ -324,7 +324,7 @@ proc start_rev_list {view} { if {[catch { set str [exec sh -c $viewargscmd($view)] } err]} { - error_popup "Error executing --argscmd command: $err" + error_popup "[mc "Error executing --argscmd command:"] $err" return 0 } set args [concat $args [split $str "\n"]] @@ -368,7 +368,7 @@ proc start_rev_list {view} { set i [reg_instance $fd] set viewinstances($view) [list $i] if {$showlocalchanges && $mainheadid ne {}} { - lappend commitinterest($mainheadid) {dodiffindex} + interestedin $mainheadid dodiffindex } fconfigure $fd -blocking 0 -translation lf -eofchar {} if {$tclencoding != {}} { @@ -418,10 +418,12 @@ proc stop_rev_list {view} { } proc reset_pending_select {selid} { - global pending_select mainheadid + global pending_select mainheadid selectheadid if {$selid ne {}} { set pending_select $selid + } elseif {$selectheadid ne {}} { + set pending_select $selectheadid } else { set pending_select $mainheadid } @@ -498,7 +500,7 @@ proc updatecommits {} { set fd [open [concat | git log --no-color -z --pretty=raw --parents \ --boundary $args "--" $vfilelimit($view)] r] } err]} { - error_popup "Error executing git log: $err" + error_popup "[mc "Error executing git log:"] $err" return } if {$viewactive($view) == 0} { @@ -1229,7 +1231,7 @@ proc commitonrow {row} { proc closevarcs {v} { global varctok varccommits varcid parents children - global cmitlisted commitidx commitinterest vtokmod + global cmitlisted commitidx vtokmod set missing_parents 0 set scripts {} @@ -1254,12 +1256,7 @@ proc closevarcs {v} { } lappend varccommits($v,$b) $p incr commitidx($v) - if {[info exists commitinterest($p)]} { - foreach script $commitinterest($p) { - lappend scripts [string map [list "%I" $p] $script] - } - unset commitinterest($id) - } + set scripts [check_interest $p $scripts] } } if {$missing_parents > 0} { @@ -1295,8 +1292,41 @@ proc rewrite_commit {v id rwid} { } } +# Mechanism for registering a command to be executed when we come +# across a particular commit. To handle the case when only the +# prefix of the commit is known, the commitinterest array is now +# indexed by the first 4 characters of the ID. Each element is a +# list of id, cmd pairs. +proc interestedin {id cmd} { + global commitinterest + + lappend commitinterest([string range $id 0 3]) $id $cmd +} + +proc check_interest {id scripts} { + global commitinterest + + set prefix [string range $id 0 3] + if {[info exists commitinterest($prefix)]} { + set newlist {} + foreach {i script} $commitinterest($prefix) { + if {[string match "$i*" $id]} { + lappend scripts [string map [list "%I" $id "%P" $i] $script] + } else { + lappend newlist $i $script + } + } + if {$newlist ne {}} { + set commitinterest($prefix) $newlist + } else { + unset commitinterest($prefix) + } + } + return $scripts +} + proc getcommitlines {fd inst view updating} { - global cmitlisted commitinterest leftover + global cmitlisted leftover global commitidx commitdata vdatemode global parents children curview hlview global idpending ordertok @@ -1472,12 +1502,7 @@ proc getcommitlines {fd inst view updating} { incr i } - if {[info exists commitinterest($id)]} { - foreach script $commitinterest($id) { - lappend scripts [string map [list "%I" $id] $script] - } - unset commitinterest($id) - } + set scripts [check_interest $id $scripts] set gotsome 1 } if {$gotsome} { @@ -1606,9 +1631,23 @@ proc getcommit {id} { return 1 } +# Expand an abbreviated commit ID to a list of full 40-char IDs that match +# and are present in the current view. +# This is fairly slow... +proc longid {prefix} { + global varcid curview + + set ids {} + foreach match [array names varcid "$curview,$prefix*"] { + lappend ids [lindex [split $match ","] 1] + } + return $ids +} + proc readrefs {} { global tagids idtags headids idheads tagobjid global otherrefids idotherrefs mainhead mainheadid + global selecthead selectheadid foreach v {tagids idtags headids idheads otherrefids idotherrefs} { catch {unset $v} @@ -1655,6 +1694,12 @@ proc readrefs {} { set mainhead [string range $thehead 11 end] } } + set selectheadid {} + if {$selecthead ne {}} { + catch { + set selectheadid [exec git rev-parse --verify $selecthead] + } + } } # skip over fake commits @@ -1741,6 +1786,53 @@ proc setoptions {} { option add *Entry.font uifont startupFile } +# Make a menu and submenus. +# m is the window name for the menu, items is the list of menu items to add. +# Each item is a list {mc label type description options...} +# mc is ignored; it's so we can put mc there to alert xgettext +# label is the string that appears in the menu +# type is cascade, command or radiobutton (should add checkbutton) +# description depends on type; it's the sublist for cascade, the +# command to invoke for command, or {variable value} for radiobutton +proc makemenu {m items} { + menu $m + foreach i $items { + set name [mc [lindex $i 1]] + set type [lindex $i 2] + set thing [lindex $i 3] + set params [list $type] + if {$name ne {}} { + set u [string first "&" [string map {&& x} $name]] + lappend params -label [string map {&& & & {}} $name] + if {$u >= 0} { + lappend params -underline $u + } + } + switch -- $type { + "cascade" { + set submenu [string tolower [string map {& ""} [lindex $i 1]]] + lappend params -menu $m.$submenu + } + "command" { + lappend params -command $thing + } + "radiobutton" { + lappend params -variable [lindex $thing 0] \ + -value [lindex $thing 1] + } + } + eval $m add $params [lrange $i 4 end] + if {$type eq "cascade"} { + makemenu $m.$submenu $thing + } + } +} + +# translate string and remove ampersands +proc mca {str} { + return [string map {&& & & {}} [mc $str]] +} + proc makewindow {} { global canv canv2 canv3 linespc charspc ctext cflist cscroll global tabstop @@ -1758,33 +1850,31 @@ proc makewindow {} { global rprogitem rprogcoord rownumsel numcommits global have_tk85 - menu .bar - .bar add cascade -label [mc "File"] -menu .bar.file - menu .bar.file - .bar.file add command -label [mc "Update"] -command updatecommits - .bar.file add command -label [mc "Reload"] -command reloadcommits - .bar.file add command -label [mc "Reread references"] -command rereadrefs - .bar.file add command -label [mc "List references"] -command showrefs - .bar.file add command -label [mc "Quit"] -command doquit - menu .bar.edit - .bar add cascade -label [mc "Edit"] -menu .bar.edit - .bar.edit add command -label [mc "Preferences"] -command doprefs - - menu .bar.view - .bar add cascade -label [mc "View"] -menu .bar.view - .bar.view add command -label [mc "New view..."] -command {newview 0} - .bar.view add command -label [mc "Edit view..."] -command editview \ - -state disabled - .bar.view add command -label [mc "Delete view"] -command delview -state disabled - .bar.view add separator - .bar.view add radiobutton -label [mc "All files"] -command {showview 0} \ - -variable selectedview -value 0 - - menu .bar.help - .bar add cascade -label [mc "Help"] -menu .bar.help - .bar.help add command -label [mc "About gitk"] -command about - .bar.help add command -label [mc "Key bindings"] -command keys - .bar.help configure + # The "mc" arguments here are purely so that xgettext + # sees the following string as needing to be translated + makemenu .bar { + {mc "File" cascade { + {mc "Update" command updatecommits -accelerator F5} + {mc "Reload" command reloadcommits} + {mc "Reread references" command rereadrefs} + {mc "List references" command showrefs} + {mc "Quit" command doquit} + }} + {mc "Edit" cascade { + {mc "Preferences" command doprefs} + }} + {mc "View" cascade { + {mc "New view..." command {newview 0}} + {mc "Edit view..." command editview -state disabled} + {mc "Delete view" command delview -state disabled} + {xx "" separator} + {mc "All files" radiobutton {selectedview 0} -command {showview 0}} + }} + {mc "Help" cascade { + {mc "About gitk" command about} + {mc "Key bindings" command keys} + }} + } . configure -menu .bar # the gui has upper and lower half, parts of a paned window. @@ -2152,59 +2242,55 @@ proc makewindow {} { bind . <Destroy> {stop_backends} bind . <Button-1> "click %W" bind $fstring <Key-Return> {dofind 1 1} - bind $sha1entry <Key-Return> gotocommit + bind $sha1entry <Key-Return> {gotocommit; break} bind $sha1entry <<PasteSelection>> clearsha1 bind $cflist <1> {sel_flist %W %x %y; break} bind $cflist <B1-Motion> {sel_flist %W %x %y; break} bind $cflist <ButtonRelease-1> {treeclick %W %x %y} - bind $cflist <Button-3> {pop_flist_menu %W %X %Y %x %y} + global ctxbut + bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y} set maincursor [. cget -cursor] set textcursor [$ctext cget -cursor] set curtextcursor $textcursor set rowctxmenu .rowctxmenu - menu $rowctxmenu -tearoff 0 - $rowctxmenu add command -label [mc "Diff this -> selected"] \ - -command {diffvssel 0} - $rowctxmenu add command -label [mc "Diff selected -> this"] \ - -command {diffvssel 1} - $rowctxmenu add command -label [mc "Make patch"] -command mkpatch - $rowctxmenu add command -label [mc "Create tag"] -command mktag - $rowctxmenu add command -label [mc "Write commit to file"] -command writecommit - $rowctxmenu add command -label [mc "Create new branch"] -command mkbranch - $rowctxmenu add command -label [mc "Cherry-pick this commit"] \ - -command cherrypick - $rowctxmenu add command -label [mc "Reset HEAD branch to here"] \ - -command resethead + makemenu $rowctxmenu { + {mc "Diff this -> selected" command {diffvssel 0}} + {mc "Diff selected -> this" command {diffvssel 1}} + {mc "Make patch" command mkpatch} + {mc "Create tag" command mktag} + {mc "Write commit to file" command writecommit} + {mc "Create new branch" command mkbranch} + {mc "Cherry-pick this commit" command cherrypick} + {mc "Reset HEAD branch to here" command resethead} + } + $rowctxmenu configure -tearoff 0 set fakerowmenu .fakerowmenu - menu $fakerowmenu -tearoff 0 - $fakerowmenu add command -label [mc "Diff this -> selected"] \ - -command {diffvssel 0} - $fakerowmenu add command -label [mc "Diff selected -> this"] \ - -command {diffvssel 1} - $fakerowmenu add command -label [mc "Make patch"] -command mkpatch -# $fakerowmenu add command -label [mc "Commit"] -command {mkcommit 0} -# $fakerowmenu add command -label [mc "Commit all"] -command {mkcommit 1} -# $fakerowmenu add command -label [mc "Revert local changes"] -command revertlocal + makemenu $fakerowmenu { + {mc "Diff this -> selected" command {diffvssel 0}} + {mc "Diff selected -> this" command {diffvssel 1}} + {mc "Make patch" command mkpatch} + } + $fakerowmenu configure -tearoff 0 set headctxmenu .headctxmenu - menu $headctxmenu -tearoff 0 - $headctxmenu add command -label [mc "Check out this branch"] \ - -command cobranch - $headctxmenu add command -label [mc "Remove this branch"] \ - -command rmbranch + makemenu $headctxmenu { + {mc "Check out this branch" command cobranch} + {mc "Remove this branch" command rmbranch} + } + $headctxmenu configure -tearoff 0 global flist_menu set flist_menu .flistctxmenu - menu $flist_menu -tearoff 0 - $flist_menu add command -label [mc "Highlight this too"] \ - -command {flist_hl 0} - $flist_menu add command -label [mc "Highlight this only"] \ - -command {flist_hl 1} - $flist_menu add command -label [mc "External diff"] \ - -command {external_diff} + makemenu $flist_menu { + {mc "Highlight this too" command {flist_hl 0}} + {mc "Highlight this only" command {flist_hl 1}} + {mc "External diff" command {external_diff}} + {mc "Blame parent commit" command {external_blame 1}} + } + $flist_menu configure -tearoff 0 } # Windows sends all mouse wheel events to the current focused window, not @@ -2320,7 +2406,7 @@ proc savestuff {w} { global viewname viewfiles viewargs viewargscmd viewperm nextviewnum global cmitmode wrapcomment datetimeformat limitdiffs global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor - global autoselect extdifftool + global autoselect extdifftool perfile_attrs if {$stuffsaved} return if {![winfo viewable .]} return @@ -2347,6 +2433,7 @@ proc savestuff {w} { puts $f [list set diffcontext $diffcontext] puts $f [list set selectbgcolor $selectbgcolor] puts $f [list set extdifftool $extdifftool] + puts $f [list set perfile_attrs $perfile_attrs] puts $f "set geometry(main) [wm geometry .]" puts $f "set geometry(topwidth) [winfo width .tf]" @@ -2694,7 +2781,7 @@ proc treeopendir {w dir} { $w insert e:$ix $e [highlight_tag $de] } } - $w mark gravity e:$ix left + $w mark gravity e:$ix right $w conf -state disabled set treediropen($dir) 1 set top [lindex [split [$w index @0,0] .] 0] @@ -2925,7 +3012,7 @@ proc save_file_from_commit {filename output what} { if {[string match "fatal: bad revision *" $err]} { return $nullfile } - error_popup "Error getting \"$filename\" from $what: $err" + error_popup "[mc "Error getting \"%s\" from %s:" $filename $what] $err" return {} } return $output @@ -2982,7 +3069,7 @@ proc external_diff {} { set gitktmpdir [file join [file dirname $gitdir] \ [format ".gitk-tmp.%s" [pid]]] if {[catch {file mkdir $gitktmpdir} err]} { - error_popup "Error creating temporary directory $gitktmpdir: $err" + error_popup "[mc "Error creating temporary directory %s:" $gitktmpdir] $err" unset gitktmpdir return } @@ -2991,7 +3078,7 @@ proc external_diff {} { incr diffnum set diffdir [file join $gitktmpdir $diffnum] if {[catch {file mkdir $diffdir} err]} { - error_popup "Error creating temporary directory $diffdir: $err" + error_popup "[mc "Error creating temporary directory %s:" $diffdir] $err" return } @@ -3004,7 +3091,7 @@ proc external_diff {} { [list $difffromfile $difftofile]] if {[catch {set fl [open $cmd r]} err]} { file delete -force $diffdir - error_popup [mc "$extdifftool: command failed: $err"] + error_popup "$extdifftool: [mc "command failed:"] $err" } else { fconfigure $fl -blocking 0 filerun $fl [list delete_at_eof $fl $diffdir] @@ -3012,12 +3099,33 @@ proc external_diff {} { } } +proc external_blame {parent_idx} { + global flist_menu_file + global nullid nullid2 + global parentlist selectedline currentid + + if {$parent_idx > 0} { + set base_commit [lindex $parentlist $selectedline [expr {$parent_idx-1}]] + } else { + set base_commit $currentid + } + + if {$base_commit eq {} || $base_commit eq $nullid || $base_commit eq $nullid2} { + error_popup [mc "No such commit"] + return + } + + if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} { + error_popup "[mc "git gui blame: command failed:"] $err" + } +} + # delete $dir when we see eof on $f (presumably because the child has exited) proc delete_at_eof {f dir} { while {[gets $f line] >= 0} {} if {[eof $f]} { if {[catch {close $f} err]} { - error_popup "External diff viewer failed: $err" + error_popup "[mc "External diff viewer failed:"] $err" } file delete -force $dir return 0 @@ -3342,8 +3450,8 @@ proc showview {n} { set curview $n set selectedview $n - .bar.view entryconf [mc "Edit view..."] -state [expr {$n == 0? "disabled": "normal"}] - .bar.view entryconf [mc "Delete view"] -state [expr {$n == 0? "disabled": "normal"}] + .bar.view entryconf [mca "Edit view..."] -state [expr {$n == 0? "disabled": "normal"}] + .bar.view entryconf [mca "Delete view"] -state [expr {$n == 0? "disabled": "normal"}] run refill_reflist if {![info exists viewcomplete($n)]} { @@ -4047,7 +4155,7 @@ proc visiblerows {} { proc layoutmore {} { global commitidx viewcomplete curview global numcommits pending_select curview - global lastscrollset lastscrollrows commitinterest + global lastscrollset lastscrollrows if {$lastscrollrows < 100 || $viewcomplete($curview) || [clock clicks -milliseconds] - $lastscrollset > 500} { @@ -4068,7 +4176,7 @@ proc doshowlocalchanges {} { if {[commitinview $mainheadid $curview]} { dodiffindex } else { - lappend commitinterest($mainheadid) {dodiffindex} + interestedin $mainheadid dodiffindex } } @@ -4887,7 +4995,7 @@ proc drawcmittext {id row col} { global rowtextx idpos idtags idheads idotherrefs global linehtag linentag linedtag selectedline global canvxmax boldrows boldnamerows fgcolor - global mainheadid nullid nullid2 circleitem circlecolors + global mainheadid nullid nullid2 circleitem circlecolors ctxbut # listed is 0 for boundary, 1 for normal, 2 for negative, 3 for left, 4 for right set listed $cmitlisted($curview,$id) @@ -4960,7 +5068,7 @@ proc drawcmittext {id row col} { } set linehtag($row) [$canv create text $xt $y -anchor w -fill $fgcolor \ -text $headline -font $font -tags text] - $canv bind $linehtag($row) <Button-3> "rowmenu %X %Y $id" + $canv bind $linehtag($row) $ctxbut "rowmenu %X %Y $id" set linentag($row) [$canv2 create text 3 $y -anchor w -fill $fgcolor \ -text $name -font $nfont -tags text] set linedtag($row) [$canv3 create text 3 $y -anchor w -fill $fgcolor \ @@ -5302,7 +5410,7 @@ proc bindline {t id} { proc drawtags {id x xt y1} { global idtags idheads idotherrefs mainhead global linespc lthickness - global canv rowtextx curview fgcolor bgcolor + global canv rowtextx curview fgcolor bgcolor ctxbut set marks {} set ntags 0 @@ -5380,7 +5488,7 @@ proc drawtags {id x xt y1} { if {$ntags >= 0} { $canv bind $t <1> [list showtag $tag 1] } elseif {$nheads >= 0} { - $canv bind $t <Button-3> [list headmenu %X %Y $id $tag] + $canv bind $t $ctxbut [list headmenu %X %Y $id $tag] } } return $xt @@ -5723,11 +5831,11 @@ proc commit_descriptor {p} { # append some text to the ctext widget, and make any SHA1 ID # that we know about be a clickable link. proc appendwithlinks {text tags} { - global ctext linknum curview pendinglinks + global ctext linknum curview set start [$ctext index "end - 1c"] $ctext insert end $text $tags - set links [regexp -indices -all -inline {[0-9a-f]{40}} $text] + set links [regexp -indices -all -inline {\m[0-9a-f]{6,40}\M} $text] foreach l $links { set s [lindex $l 0] set e [lindex $l 1] @@ -5741,16 +5849,27 @@ proc appendwithlinks {text tags} { } proc setlink {id lk} { - global curview ctext pendinglinks commitinterest + global curview ctext pendinglinks - if {[commitinview $id $curview]} { + set known 0 + if {[string length $id] < 40} { + set matches [longid $id] + if {[llength $matches] > 0} { + if {[llength $matches] > 1} return + set known 1 + set id [lindex $matches 0] + } + } else { + set known [commitinview $id $curview] + } + if {$known} { $ctext tag conf $lk -foreground blue -underline 1 - $ctext tag bind $lk <1> [list selectline [rowofcommit $id] 1] + $ctext tag bind $lk <1> [list selbyid $id] $ctext tag bind $lk <Enter> {linkcursor %W 1} $ctext tag bind $lk <Leave> {linkcursor %W -1} } else { lappend pendinglinks($id) $lk - lappend commitinterest($id) {makelink %I} + interestedin $id {makelink %P} } } @@ -6196,7 +6315,7 @@ proc gettree {id} { set treepending $id set treefilelist($id) {} set treeidlist($id) {} - fconfigure $gtf -blocking 0 + fconfigure $gtf -blocking 0 -encoding binary filerun $gtf [list gettreeline $gtf $id] } } else { @@ -6218,11 +6337,12 @@ proc gettreeline {gtf id} { set line [string range $line 0 [expr {$i-1}]] if {$diffids ne $nullid2 && [lindex $line 1] ne "blob"} continue set sha1 [lindex $line 2] - if {[string index $fname 0] eq "\""} { - set fname [lindex $fname 0] - } lappend treeidlist($id) $sha1 } + if {[string index $fname 0] eq "\""} { + set fname [lindex $fname 0] + } + set fname [encoding convertfrom $fname] lappend treefilelist($id) $fname } if {![eof $gtf]} { @@ -6263,7 +6383,7 @@ proc showfile {f} { return } } - fconfigure $bf -blocking 0 + fconfigure $bf -blocking 0 -encoding [get_path_encoding $f] filerun $bf [list getblobline $bf $diffids] $ctext config -state normal clear_ctext $commentend @@ -6301,6 +6421,7 @@ proc mergediff {id} { global diffids global parents global diffcontext + global diffencoding global limitdiffs vfilelimit curview set diffmergeid $id @@ -6314,9 +6435,10 @@ proc mergediff {id} { error_popup "[mc "Error getting merge diffs:"] $err" return } - fconfigure $mdf -blocking 0 + fconfigure $mdf -blocking 0 -encoding binary set mdifffd($id) $mdf set np [llength $parents($curview,$id)] + set diffencoding [get_path_encoding {}] settabs $np filerun $mdf [list getmergediffline $mdf $id $np] } @@ -6324,6 +6446,7 @@ proc mergediff {id} { proc getmergediffline {mdf id np} { global diffmergeid ctext cflist mergemax global difffilestart mdifffd + global diffencoding $ctext conf -state normal set nr 0 @@ -6335,18 +6458,22 @@ proc getmergediffline {mdf id np} { } if {[regexp {^diff --cc (.*)} $line match fname]} { # start of a new file + set fname [encoding convertfrom $fname] $ctext insert end "\n" set here [$ctext index "end - 1c"] lappend difffilestart $here add_flist [list $fname] + set diffencoding [get_path_encoding $fname] set l [expr {(78 - [string length $fname]) / 2}] set pad [string range "----------------------------------------" 1 $l] $ctext insert end "$pad $fname $pad\n" filesep } elseif {[regexp {^@@} $line]} { + set line [encoding convertfrom $diffencoding $line] $ctext insert end "$line\n" hunksep } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} { # do nothing } else { + set line [encoding convertfrom $diffencoding $line] # parse the prefix - one ' ', '-' or '+' for each parent set spaces {} set minuses {} @@ -6481,27 +6608,42 @@ proc gettreediffs {ids} { set treepending $ids set treediff {} - fconfigure $gdtf -blocking 0 + fconfigure $gdtf -blocking 0 -encoding binary filerun $gdtf [list gettreediffline $gdtf $ids] } proc gettreediffline {gdtf ids} { global treediff treediffs treepending diffids diffmergeid - global cmitmode vfilelimit curview limitdiffs + global cmitmode vfilelimit curview limitdiffs perfile_attrs set nr 0 - while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} { + set sublist {} + set max 1000 + if {$perfile_attrs} { + # cache_gitattr is slow, and even slower on win32 where we + # have to invoke it for only about 30 paths at a time + set max 500 + if {[tk windowingsystem] == "win32"} { + set max 120 + } + } + while {[incr nr] <= $max && [gets $gdtf line] >= 0} { set i [string first "\t" $line] if {$i >= 0} { set file [string range $line [expr {$i+1}] end] if {[string index $file 0] eq "\""} { set file [lindex $file 0] } + set file [encoding convertfrom $file] lappend treediff $file + lappend sublist $file } } + if {$perfile_attrs} { + cache_gitattr encoding $sublist + } if {![eof $gdtf]} { - return [expr {$nr >= 1000? 2: 1}] + return [expr {$nr >= $max? 2: 1}] } close $gdtf if {$limitdiffs && $vfilelimit($curview) ne {}} { @@ -6554,6 +6696,7 @@ proc getblobdiffs {ids} { global diffcontext global ignorespace global limitdiffs vfilelimit curview + global diffencoding set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"] if {$ignorespace} { @@ -6567,7 +6710,8 @@ proc getblobdiffs {ids} { return } set diffinhdr 0 - fconfigure $bdf -blocking 0 + set diffencoding [get_path_encoding {}] + fconfigure $bdf -blocking 0 -encoding binary set blobdifffd($ids) $bdf filerun $bdf [list getblobdiffline $bdf $diffids] } @@ -6601,6 +6745,7 @@ proc getblobdiffline {bdf ids} { global diffids blobdifffd ctext curdiffstart global diffnexthead diffnextnote difffilestart global diffinhdr treediffs + global diffencoding set nr 0 $ctext conf -state normal @@ -6638,10 +6783,13 @@ proc getblobdiffline {bdf ids} { } else { set fname [string range $line 2 [expr {$i - 1}]] } + set fname [encoding convertfrom $fname] + set diffencoding [get_path_encoding $fname] makediffhdr $fname $ids } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \ $line match f1l f1c f2l f2c rest]} { + set line [encoding convertfrom $diffencoding $line] $ctext insert end "$line\n" hunksep set diffinhdr 0 @@ -6651,6 +6799,7 @@ proc getblobdiffline {bdf ids} { if {[string index $fname 0] eq "\""} { set fname [lindex $fname 0] } + set fname [encoding convertfrom $fname] set i [lsearch -exact $treediffs($ids) $fname] if {$i >= 0} { setinlist difffilestart $i $curdiffstart @@ -6661,6 +6810,8 @@ proc getblobdiffline {bdf ids} { if {[string index $fname 0] eq "\""} { set fname [lindex $fname 0] } + set fname [encoding convertfrom $fname] + set diffencoding [get_path_encoding $fname] makediffhdr $fname $ids } elseif {[string compare -length 3 $line "---"] == 0} { # do nothing @@ -6672,6 +6823,7 @@ proc getblobdiffline {bdf ids} { $ctext insert end "$line\n" filesep } else { + set line [encoding convertfrom $diffencoding $line] set x [string range $line 0 0] if {$x == "-" || $x == "+"} { set tag [expr {$x == "+"}] @@ -7033,13 +7185,13 @@ proc gotocommit {} { } else { set id [string tolower $sha1string] if {[regexp {^[0-9a-f]{4,39}$} $id]} { - set matches [array names varcid "$curview,$id*"] + set matches [longid $id] if {$matches ne {}} { if {[llength $matches] > 1} { error_popup [mc "Short SHA1 id %s is ambiguous" $id] return } - set id [lindex [split [lindex $matches 0] ","] 1] + set id [lindex $matches 0] } } } @@ -7256,9 +7408,9 @@ proc rowmenu {x y id} { } else { set menu $fakerowmenu } - $menu entryconfigure [mc "Diff this -> selected"] -state $state - $menu entryconfigure [mc "Diff selected -> this"] -state $state - $menu entryconfigure [mc "Make patch"] -state $state + $menu entryconfigure [mca "Diff this -> selected"] -state $state + $menu entryconfigure [mca "Diff selected -> this"] -state $state + $menu entryconfigure [mca "Make patch"] -state $state tk_popup $menu $x $y } @@ -7558,6 +7710,7 @@ proc mkbranch {} { grid $top.id $top.sha1 -sticky w label $top.nlab -text [mc "Name:"] entry $top.name -width 40 + bind $top.name <Key-Return> "[list mkbrgo $top]" grid $top.nlab $top.name -sticky w frame $top.buts button $top.buts.go -text [mc "Create"] -command [list mkbrgo $top] @@ -7886,7 +8039,7 @@ proc reflistfilter_change {n1 n2 op} { proc refill_reflist {} { global reflist reflistfilter showrefstop headids tagids otherrefids - global curview commitinterest + global curview if {![info exists showrefstop] || ![winfo exists $showrefstop]} return set refs {} @@ -7895,7 +8048,7 @@ proc refill_reflist {} { if {[commitinview $headids($n) $curview]} { lappend refs [list $n H] } else { - set commitinterest($headids($n)) {run refill_reflist} + interestedin $headids($n) {run refill_reflist} } } } @@ -7904,7 +8057,7 @@ proc refill_reflist {} { if {[commitinview $tagids($n) $curview]} { lappend refs [list $n T] } else { - set commitinterest($tagids($n)) {run refill_reflist} + interestedin $tagids($n) {run refill_reflist} } } } @@ -7913,7 +8066,7 @@ proc refill_reflist {} { if {[commitinview $otherrefids($n) $curview]} { lappend refs [list $n o] } else { - set commitinterest($otherrefids($n)) {run refill_reflist} + interestedin $otherrefids($n) {run refill_reflist} } } } @@ -9263,7 +9416,7 @@ proc doprefs {} { global maxwidth maxgraphpct global oldprefs prefstop showneartags showlocalchanges global bgcolor fgcolor ctext diffcolors selectbgcolor - global tabstop limitdiffs autoselect extdifftool + global tabstop limitdiffs autoselect extdifftool perfile_attrs set top .gitkprefs set prefstop $top @@ -9272,7 +9425,7 @@ proc doprefs {} { return } foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop} { + limitdiffs tabstop perfile_attrs} { set oldprefs($v) [set $v] } toplevel $top @@ -9314,6 +9467,11 @@ proc doprefs {} { checkbutton $top.ldiff.b -variable limitdiffs pack $top.ldiff.b $top.ldiff.l -side left grid x $top.ldiff -sticky w + frame $top.lattr + label $top.lattr.l -text [mc "Support per-file encodings"] -font optionfont + checkbutton $top.lattr.b -variable perfile_attrs + pack $top.lattr.b $top.lattr.l -side left + grid x $top.lattr -sticky w entry $top.extdifft -textvariable extdifftool frame $top.extdifff @@ -9423,7 +9581,7 @@ proc prefscan {} { global oldprefs prefstop foreach v {maxwidth maxgraphpct showneartags showlocalchanges \ - limitdiffs tabstop} { + limitdiffs tabstop perfile_attrs} { global $v set $v $oldprefs($v) } @@ -9436,7 +9594,7 @@ proc prefsok {} { global maxwidth maxgraphpct global oldprefs prefstop showneartags showlocalchanges global fontpref mainfont textfont uifont - global limitdiffs treediffs + global limitdiffs treediffs perfile_attrs catch {destroy $prefstop} unset prefstop @@ -9469,8 +9627,10 @@ proc prefsok {} { dohidelocalchanges } } - if {$limitdiffs != $oldprefs(limitdiffs)} { - # treediffs elements are limited by path + if {$limitdiffs != $oldprefs(limitdiffs) || + ($perfile_attrs && !$oldprefs(perfile_attrs))} { + # treediffs elements are limited by path; + # won't have encodings cached if perfile_attrs was just turned on catch {unset treediffs} } if {$fontchanged || $maxwidth != $oldprefs(maxwidth) @@ -9694,7 +9854,7 @@ set encoding_aliases { { ISO-8859-16 iso-ir-226 ISO_8859-16:2001 ISO_8859-16 latin10 l10 } { GBK CP936 MS936 windows-936 } { JIS_Encoding csJISEncoding } - { Shift_JIS MS_Kanji csShiftJIS } + { Shift_JIS MS_Kanji csShiftJIS ShiftJIS Shift-JIS } { Extended_UNIX_Code_Packed_Format_for_Japanese csEUCPkdFmtJapanese EUC-JP } { Extended_UNIX_Code_Fixed_Width_for_Japanese csEUCFixWidJapanese } @@ -9729,14 +9889,17 @@ set encoding_aliases { } proc tcl_encoding {enc} { - global encoding_aliases + global encoding_aliases tcl_encoding_cache + if {[info exists tcl_encoding_cache($enc)]} { + return $tcl_encoding_cache($enc) + } set names [encoding names] set lcnames [string tolower $names] set enc [string tolower $enc] set i [lsearch -exact $lcnames $enc] if {$i < 0} { # look for "isonnn" instead of "iso-nnn" or "iso_nnn" - if {[regsub {^iso[-_]} $enc iso encx]} { + if {[regsub {^(iso|cp|ibm|jis)[-_]} $enc {\1} encx]} { set i [lsearch -exact $lcnames $encx] } } @@ -9748,7 +9911,7 @@ proc tcl_encoding {enc} { foreach e $ll { set i [lsearch -exact $lcnames $e] if {$i < 0} { - if {[regsub {^iso[-_]} $e iso ex]} { + if {[regsub {^(iso|cp|ibm|jis)[-_]} $e {\1} ex]} { set i [lsearch -exact $lcnames $ex] } } @@ -9757,10 +9920,70 @@ proc tcl_encoding {enc} { break } } + set tclenc {} if {$i >= 0} { - return [lindex $names $i] + set tclenc [lindex $names $i] } - return {} + set tcl_encoding_cache($enc) $tclenc + return $tclenc +} + +proc gitattr {path attr default} { + global path_attr_cache + if {[info exists path_attr_cache($attr,$path)]} { + set r $path_attr_cache($attr,$path) + } else { + set r "unspecified" + if {![catch {set line [exec git check-attr $attr -- $path]}]} { + regexp "(.*): encoding: (.*)" $line m f r + } + set path_attr_cache($attr,$path) $r + } + if {$r eq "unspecified"} { + return $default + } + return $r +} + +proc cache_gitattr {attr pathlist} { + global path_attr_cache + set newlist {} + foreach path $pathlist { + if {![info exists path_attr_cache($attr,$path)]} { + lappend newlist $path + } + } + set lim 1000 + if {[tk windowingsystem] == "win32"} { + # windows has a 32k limit on the arguments to a command... + set lim 30 + } + while {$newlist ne {}} { + set head [lrange $newlist 0 [expr {$lim - 1}]] + set newlist [lrange $newlist $lim end] + if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} { + foreach row [split $rlist "\n"] { + if {[regexp "(.*): encoding: (.*)" $row m path value]} { + if {[string index $path 0] eq "\""} { + set path [encoding convertfrom [lindex $path 0]] + } + set path_attr_cache($attr,$path) $value + } + } + } + } +} + +proc get_path_encoding {path} { + global gui_encoding perfile_attrs + set tcl_enc $gui_encoding + if {$path ne {} && $perfile_attrs} { + set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]] + if {$enc2 ne {}} { + set tcl_enc $enc2 + } + } + return $tcl_enc } # First check that Tcl/Tk is recent enough @@ -9785,6 +10008,19 @@ if {$tclencoding == {}} { puts stderr "Warning: encoding $gitencoding is not supported by Tcl/Tk" } +set gui_encoding [encoding system] +catch { + set enc [exec git config --get gui.encoding] + if {$enc ne {}} { + set tclenc [tcl_encoding $enc] + if {$tclenc ne {}} { + set gui_encoding $tclenc + } else { + puts stderr "Warning: encoding $enc is not supported by Tcl/Tk" + } + } +} + set mainfont {Helvetica 9} set textfont {Courier 9} set uifont {Helvetica 9 bold} @@ -9806,6 +10042,7 @@ set showlocalchanges 1 set limitdiffs 1 set datetimeformat "%Y-%m-%d %H:%M:%S" set autoselect 1 +set perfile_attrs 0 set extdifftool "meld" @@ -9819,6 +10056,13 @@ set selectbgcolor gray85 set circlecolors {white blue gray blue blue} +# button for popping up context menus +if {[tk windowingsystem] eq "aqua"} { + set ctxbut <Button-2> +} else { + set ctxbut <Button-3> +} + ## For msgcat loading, first locate the installation location. if { [info exists ::env(GITK_MSGSDIR)] } { ## Msgsdir was manually set in the environment. @@ -9865,6 +10109,9 @@ if {![file isdirectory $gitdir]} { exit 1 } +set selecthead {} +set selectheadid {} + set revtreeargs {} set cmdline_files {} set i 0 @@ -9876,6 +10123,9 @@ foreach arg $argv { set cmdline_files [lrange $argv [expr {$i + 1}] end] break } + "--select-commit=*" { + set selecthead [string range $arg 16 end] + } "--argscmd=*" { set revtreeargscmd [string range $arg 10 end] } @@ -9886,6 +10136,10 @@ foreach arg $argv { incr i } +if {$selecthead eq "HEAD"} { + set selecthead {} +} + if {$i >= [llength $argv] && $revtreeargs ne {}} { # no -- on command line, but some arguments (other than --argscmd) if {[catch { @@ -9977,8 +10231,8 @@ if {$cmdline_files ne {} || $revtreeargs ne {} || $revtreeargscmd ne {}} { set viewperm(1) 0 set vdatemode(1) 0 addviewmenu 1 - .bar.view entryconf [mc "Edit view..."] -state normal - .bar.view entryconf [mc "Delete view"] -state normal + .bar.view entryconf [mca "Edit view..."] -state normal + .bar.view entryconf [mca "Delete view"] -state normal } if {[info exists permviews]} { |