Skip to content

Commit 39ee47e

Browse files
committed
gitk: Clean up file encoding code and add enable/disable option
This adds an option allowing the user to select whether gitk should look up per-file encoding settings using git check-attr or not. If not, gitk uses the global encoding set in the git config (as reported by git config --get gui.encoding) for all files, or if that is not set, then the system encoding. The option is controlled by a checkbox in the Edit->Preferences window, and defaults to off for now because git check-attr is so slow. When the user turns it on we discard any cached diff file lists in treediffs, because we may not have encodings cached for the files listed in those lists, meaning that getblobdiffline will do it for each file, which will be really really slow. This adjusts the limit of how many paths cache_gitattr passes to each instance of git check-attr depending on whether we're running under windows or not. Passing only 30 doesn't effectively amortize the startup costs of git check-attr, but it's all we can do under windows because of the 32k limit on arguments to a command. Under other OSes we pass up to 1000. Similarly we adjust how many lines gettreediffline processes depending on whether we are doing per-file encodings so that we don't run for too long. When we are, 500 seems to be a reasonable limit, leading to gettreediffline taking about 60-70ms under Linux (almost all of which is in cache_gitattr, unfortunately). This means that we can take out the update call in cache_gitattr. This adds a simple cache on [tclencoding]. Now that we get repeated calls to translate the same encoding, this is useful. This reindents the new code added in the last couple of commits to conform to the gitk 4-space indent and makes various other improvements: use regexp in gitattr and cache_gitattr instead of split + join + regsub, make gui_encoding be the value from [tclencoding] to avoid having to do [tcl_encoding $gui_encoding] in each call to get_path_encoding, and print a warning message at startup if $gui_encoding isn't supported by Tcl. Signed-off-by: Paul Mackerras <[email protected]>
1 parent 4db0930 commit 39ee47e

File tree

1 file changed

+92
-59
lines changed

1 file changed

+92
-59
lines changed

gitk

Lines changed: 92 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2332,7 +2332,7 @@ proc savestuff {w} {
23322332
global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
23332333
global cmitmode wrapcomment datetimeformat limitdiffs
23342334
global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
2335-
global autoselect extdifftool
2335+
global autoselect extdifftool perfile_attrs
23362336

23372337
if {$stuffsaved} return
23382338
if {![winfo viewable .]} return
@@ -2359,6 +2359,7 @@ proc savestuff {w} {
23592359
puts $f [list set diffcontext $diffcontext]
23602360
puts $f [list set selectbgcolor $selectbgcolor]
23612361
puts $f [list set extdifftool $extdifftool]
2362+
puts $f [list set perfile_attrs $perfile_attrs]
23622363

23632364
puts $f "set geometry(main) [wm geometry .]"
23642365
puts $f "set geometry(topwidth) [winfo width .tf]"
@@ -6528,11 +6529,20 @@ proc gettreediffs {ids} {
65286529

65296530
proc gettreediffline {gdtf ids} {
65306531
global treediff treediffs treepending diffids diffmergeid
6531-
global cmitmode vfilelimit curview limitdiffs
6532+
global cmitmode vfilelimit curview limitdiffs perfile_attrs
65326533

65336534
set nr 0
65346535
set sublist {}
6535-
while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
6536+
set max 1000
6537+
if {$perfile_attrs} {
6538+
# cache_gitattr is slow, and even slower on win32 where we
6539+
# have to invoke it for only about 30 paths at a time
6540+
set max 500
6541+
if {[tk windowingsystem] == "win32"} {
6542+
set max 120
6543+
}
6544+
}
6545+
while {[incr nr] <= $max && [gets $gdtf line] >= 0} {
65366546
set i [string first "\t" $line]
65376547
if {$i >= 0} {
65386548
set file [string range $line [expr {$i+1}] end]
@@ -6544,9 +6554,11 @@ proc gettreediffline {gdtf ids} {
65446554
lappend sublist $file
65456555
}
65466556
}
6547-
cache_gitattr encoding $sublist
6557+
if {$perfile_attrs} {
6558+
cache_gitattr encoding $sublist
6559+
}
65486560
if {![eof $gdtf]} {
6549-
return [expr {$nr >= 1000? 2: 1}]
6561+
return [expr {$nr >= $max? 2: 1}]
65506562
}
65516563
close $gdtf
65526564
if {$limitdiffs && $vfilelimit($curview) ne {}} {
@@ -9318,7 +9330,7 @@ proc doprefs {} {
93189330
global maxwidth maxgraphpct
93199331
global oldprefs prefstop showneartags showlocalchanges
93209332
global bgcolor fgcolor ctext diffcolors selectbgcolor
9321-
global tabstop limitdiffs autoselect extdifftool
9333+
global tabstop limitdiffs autoselect extdifftool perfile_attrs
93229334

93239335
set top .gitkprefs
93249336
set prefstop $top
@@ -9327,7 +9339,7 @@ proc doprefs {} {
93279339
return
93289340
}
93299341
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
9330-
limitdiffs tabstop} {
9342+
limitdiffs tabstop perfile_attrs} {
93319343
set oldprefs($v) [set $v]
93329344
}
93339345
toplevel $top
@@ -9369,6 +9381,11 @@ proc doprefs {} {
93699381
checkbutton $top.ldiff.b -variable limitdiffs
93709382
pack $top.ldiff.b $top.ldiff.l -side left
93719383
grid x $top.ldiff -sticky w
9384+
frame $top.lattr
9385+
label $top.lattr.l -text [mc "Support per-file encodings"] -font optionfont
9386+
checkbutton $top.lattr.b -variable perfile_attrs
9387+
pack $top.lattr.b $top.lattr.l -side left
9388+
grid x $top.lattr -sticky w
93729389

93739390
entry $top.extdifft -textvariable extdifftool
93749391
frame $top.extdifff
@@ -9478,7 +9495,7 @@ proc prefscan {} {
94789495
global oldprefs prefstop
94799496

94809497
foreach v {maxwidth maxgraphpct showneartags showlocalchanges \
9481-
limitdiffs tabstop} {
9498+
limitdiffs tabstop perfile_attrs} {
94829499
global $v
94839500
set $v $oldprefs($v)
94849501
}
@@ -9491,7 +9508,7 @@ proc prefsok {} {
94919508
global maxwidth maxgraphpct
94929509
global oldprefs prefstop showneartags showlocalchanges
94939510
global fontpref mainfont textfont uifont
9494-
global limitdiffs treediffs
9511+
global limitdiffs treediffs perfile_attrs
94959512

94969513
catch {destroy $prefstop}
94979514
unset prefstop
@@ -9524,8 +9541,10 @@ proc prefsok {} {
95249541
dohidelocalchanges
95259542
}
95269543
}
9527-
if {$limitdiffs != $oldprefs(limitdiffs)} {
9528-
# treediffs elements are limited by path
9544+
if {$limitdiffs != $oldprefs(limitdiffs) ||
9545+
($perfile_attrs && !$oldprefs(perfile_attrs))} {
9546+
# treediffs elements are limited by path;
9547+
# won't have encodings cached if perfile_attrs was just turned on
95299548
catch {unset treediffs}
95309549
}
95319550
if {$fontchanged || $maxwidth != $oldprefs(maxwidth)
@@ -9784,7 +9803,10 @@ set encoding_aliases {
97849803
}
97859804

97869805
proc tcl_encoding {enc} {
9787-
global encoding_aliases
9806+
global encoding_aliases tcl_encoding_cache
9807+
if {[info exists tcl_encoding_cache($enc)]} {
9808+
return $tcl_encoding_cache($enc)
9809+
}
97889810
set names [encoding names]
97899811
set lcnames [string tolower $names]
97909812
set enc [string tolower $enc]
@@ -9812,68 +9834,70 @@ proc tcl_encoding {enc} {
98129834
break
98139835
}
98149836
}
9837+
set tclenc {}
98159838
if {$i >= 0} {
9816-
return [lindex $names $i]
9839+
set tclenc [lindex $names $i]
98179840
}
9818-
return {}
9841+
set tcl_encoding_cache($enc) $tclenc
9842+
return $tclenc
98199843
}
98209844

98219845
proc gitattr {path attr default} {
9822-
global path_attr_cache
9823-
if {[info exists path_attr_cache($attr,$path)]} {
9824-
set r $path_attr_cache($attr,$path)
9825-
} elseif {[catch {set r [exec git check-attr $attr -- $path]}]} {
9826-
set r unspecified
9827-
} else {
9828-
set r [join [lrange [split $r :] 2 end] :]
9829-
regsub {^ } $r {} r
9846+
global path_attr_cache
9847+
if {[info exists path_attr_cache($attr,$path)]} {
9848+
set r $path_attr_cache($attr,$path)
9849+
} else {
9850+
set r "unspecified"
9851+
if {![catch {set line [exec git check-attr $attr -- $path]}]} {
9852+
regexp "(.*): encoding: (.*)" $line m f r
98309853
}
98319854
set path_attr_cache($attr,$path) $r
9832-
if {$r eq {unspecified}} {
9833-
return $default
9834-
}
9835-
return $r
9855+
}
9856+
if {$r eq "unspecified"} {
9857+
return $default
9858+
}
9859+
return $r
98369860
}
98379861

98389862
proc cache_gitattr {attr pathlist} {
9839-
global path_attr_cache
9840-
set newlist {}
9841-
foreach path $pathlist {
9842-
if {[info exists path_attr_cache($attr,$path)]} continue
9843-
lappend newlist $path
9844-
}
9845-
while {$newlist ne {}} {
9846-
set head [lrange $newlist 0 29]
9847-
set newlist [lrange $newlist 30 end]
9848-
if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
9849-
foreach row [split $rlist "\n"] {
9850-
set cols [split $row :]
9851-
set path [lindex $cols 0]
9852-
set value [join [lrange $cols 2 end] :]
9853-
if {[string index $path 0] eq "\""} {
9854-
set path [encoding convertfrom [lindex $path 0]]
9855-
}
9856-
regsub {^ } $value {} value
9857-
set path_attr_cache($attr,$path) $value
9858-
}
9863+
global path_attr_cache
9864+
set newlist {}
9865+
foreach path $pathlist {
9866+
if {![info exists path_attr_cache($attr,$path)]} {
9867+
lappend newlist $path
9868+
}
9869+
}
9870+
set lim 1000
9871+
if {[tk windowingsystem] == "win32"} {
9872+
# windows has a 32k limit on the arguments to a command...
9873+
set lim 30
9874+
}
9875+
while {$newlist ne {}} {
9876+
set head [lrange $newlist 0 [expr {$lim - 1}]]
9877+
set newlist [lrange $newlist $lim end]
9878+
if {![catch {set rlist [eval exec git check-attr $attr -- $head]}]} {
9879+
foreach row [split $rlist "\n"] {
9880+
if {[regexp "(.*): encoding: (.*)" $row m path value]} {
9881+
if {[string index $path 0] eq "\""} {
9882+
set path [encoding convertfrom [lindex $path 0]]
9883+
}
9884+
set path_attr_cache($attr,$path) $value
98599885
}
9860-
update
9886+
}
98619887
}
9888+
}
98629889
}
98639890

98649891
proc get_path_encoding {path} {
9865-
global gui_encoding
9866-
set tcl_enc [tcl_encoding $gui_encoding]
9867-
if {$tcl_enc eq {}} {
9868-
set tcl_enc [encoding system]
9869-
}
9870-
if {$path ne {}} {
9871-
set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
9872-
if {$enc2 ne {}} {
9873-
set tcl_enc $enc2
9874-
}
9892+
global gui_encoding perfile_attrs
9893+
set tcl_enc $gui_encoding
9894+
if {$path ne {} && $perfile_attrs} {
9895+
set enc2 [tcl_encoding [gitattr $path encoding $tcl_enc]]
9896+
if {$enc2 ne {}} {
9897+
set tcl_enc $enc2
98759898
}
9876-
return $tcl_enc
9899+
}
9900+
return $tcl_enc
98779901
}
98789902

98799903
# First check that Tcl/Tk is recent enough
@@ -9900,7 +9924,15 @@ if {$tclencoding == {}} {
99009924

99019925
set gui_encoding [encoding system]
99029926
catch {
9903-
set gui_encoding [exec git config --get gui.encoding]
9927+
set enc [exec git config --get gui.encoding]
9928+
if {$enc ne {}} {
9929+
set tclenc [tcl_encoding $enc]
9930+
if {$tclenc ne {}} {
9931+
set gui_encoding $tclenc
9932+
} else {
9933+
puts stderr "Warning: encoding $enc is not supported by Tcl/Tk"
9934+
}
9935+
}
99049936
}
99059937

99069938
set mainfont {Helvetica 9}
@@ -9924,6 +9956,7 @@ set showlocalchanges 1
99249956
set limitdiffs 1
99259957
set datetimeformat "%Y-%m-%d %H:%M:%S"
99269958
set autoselect 1
9959+
set perfile_attrs 0
99279960

99289961
set extdifftool "meld"
99299962

0 commit comments

Comments
 (0)