@@ -2110,7 +2110,7 @@ proc makewindow {} {
21102110 bindkey k " selnextline 1"
21112111 bindkey j " goback"
21122112 bindkey l " goforw"
2113- bindkey b " $ctext yview scroll -1 pages "
2113+ bindkey b prevfile
21142114 bindkey d " $ctext yview scroll 18 units"
21152115 bindkey u " $ctext yview scroll -18 units"
21162116 bindkey / {dofind 1 1}
@@ -2182,6 +2182,8 @@ proc makewindow {} {
21822182 -command {flist_hl 0}
21832183 $flist_menu add command -label [mc " Highlight this only" ] \
21842184 -command {flist_hl 1}
2185+ $flist_menu add command -label [mc " External diff" ] \
2186+ -command {external_diff}
21852187}
21862188
21872189# Windows sends all mouse wheel events to the current focused window, not
@@ -2286,7 +2288,7 @@ proc savestuff {w} {
22862288 global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
22872289 global cmitmode wrapcomment datetimeformat limitdiffs
22882290 global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
2289- global autoselect
2291+ global autoselect extdifftool
22902292
22912293 if {$stuffsaved } return
22922294 if {![winfo viewable .]} return
@@ -2312,6 +2314,7 @@ proc savestuff {w} {
23122314 puts $f [list set diffcolors $diffcolors ]
23132315 puts $f [list set diffcontext $diffcontext ]
23142316 puts $f [list set selectbgcolor $selectbgcolor ]
2317+ puts $f [list set extdifftool $extdifftool ]
23152318
23162319 puts $f " set geometry(main) [ wm geometry .] "
23172320 puts $f " set geometry(topwidth) [ winfo width .tf] "
@@ -2862,6 +2865,12 @@ proc pop_flist_menu {w X Y x y} {
28622865 set e [lindex $treediffs($diffids) [expr {$l -2}]]
28632866 }
28642867 set flist_menu_file $e
2868+ set xdiffstate " normal"
2869+ if {$cmitmode eq " tree" } {
2870+ set xdiffstate " disabled"
2871+ }
2872+ # Disable "External diff" item in tree mode
2873+ $flist_menu entryconf 2 -state $xdiffstate
28652874 tk_popup $flist_menu $X $Y
28662875}
28672876
@@ -2877,6 +2886,113 @@ proc flist_hl {only} {
28772886 set gdttype [mc " touching paths:" ]
28782887}
28792888
2889+ proc save_file_from_commit {filename output what} {
2890+ global nullfile
2891+
2892+ if {[catch {exec git show $filename -- > $output } err]} {
2893+ if {[string match " fatal: bad revision *" $err ]} {
2894+ return $nullfile
2895+ }
2896+ error_popup " Error getting \" $filename \" from $what : $err "
2897+ return {}
2898+ }
2899+ return $output
2900+ }
2901+
2902+ proc external_diff_get_one_file {diffid filename diffdir} {
2903+ global nullid nullid2 nullfile
2904+ global gitdir
2905+
2906+ if {$diffid == $nullid } {
2907+ set difffile [file join [file dirname $gitdir ] $filename ]
2908+ if {[file exists $difffile ]} {
2909+ return $difffile
2910+ }
2911+ return $nullfile
2912+ }
2913+ if {$diffid == $nullid2 } {
2914+ set difffile [file join $diffdir " \[ index\] [ file tail $filename ] " ]
2915+ return [save_file_from_commit :$filename $difffile index]
2916+ }
2917+ set difffile [file join $diffdir " \[ $diffid \] [ file tail $filename ] " ]
2918+ return [save_file_from_commit $diffid :$filename $difffile \
2919+ " revision $diffid " ]
2920+ }
2921+
2922+ proc external_diff {} {
2923+ global gitktmpdir nullid nullid2
2924+ global flist_menu_file
2925+ global diffids
2926+ global diffnum
2927+ global gitdir extdifftool
2928+
2929+ if {[llength $diffids ] == 1} {
2930+ # no reference commit given
2931+ set diffidto [lindex $diffids 0]
2932+ if {$diffidto eq $nullid } {
2933+ # diffing working copy with index
2934+ set diffidfrom $nullid2
2935+ } elseif {$diffidto eq $nullid2 } {
2936+ # diffing index with HEAD
2937+ set diffidfrom " HEAD"
2938+ } else {
2939+ # use first parent commit
2940+ global parentlist selectedline
2941+ set diffidfrom [lindex $parentlist $selectedline 0]
2942+ }
2943+ } else {
2944+ set diffidfrom [lindex $diffids 0]
2945+ set diffidto [lindex $diffids 1]
2946+ }
2947+
2948+ # make sure that several diffs wont collide
2949+ if {![info exists gitktmpdir]} {
2950+ set gitktmpdir [file join [file dirname $gitdir ] \
2951+ [format " .gitk-tmp.%s" [pid ]]]
2952+ if {[catch {file mkdir $gitktmpdir } err]} {
2953+ error_popup " Error creating temporary directory $gitktmpdir : $err "
2954+ unset gitktmpdir
2955+ return
2956+ }
2957+ set diffnum 0
2958+ }
2959+ incr diffnum
2960+ set diffdir [file join $gitktmpdir $diffnum ]
2961+ if {[catch {file mkdir $diffdir } err]} {
2962+ error_popup " Error creating temporary directory $diffdir : $err "
2963+ return
2964+ }
2965+
2966+ # gather files to diff
2967+ set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file $diffdir ]
2968+ set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir ]
2969+
2970+ if {$difffromfile ne {} && $difftofile ne {}} {
2971+ set cmd [concat | [shellsplit $extdifftool ] \
2972+ [list $difffromfile $difftofile ]]
2973+ if {[catch {set fl [open $cmd r]} err]} {
2974+ file delete -force $diffdir
2975+ error_popup [mc " $extdifftool : command failed: $err " ]
2976+ } else {
2977+ fconfigure $fl -blocking 0
2978+ filerun $fl [list delete_at_eof $fl $diffdir ]
2979+ }
2980+ }
2981+ }
2982+
2983+ # delete $dir when we see eof on $f (presumably because the child has exited)
2984+ proc delete_at_eof {f dir} {
2985+ while {[gets $f line] >= 0} {}
2986+ if {[eof $f ]} {
2987+ if {[catch {close $f } err]} {
2988+ error_popup " External diff viewer failed: $err "
2989+ }
2990+ file delete -force $dir
2991+ return 0
2992+ }
2993+ return 1
2994+ }
2995+
28802996# Functions for adding and removing shell-type quoting
28812997
28822998proc shellquote {str} {
@@ -6053,11 +6169,12 @@ proc gettreeline {gtf id} {
60536169 if {$diffids eq $nullid } {
60546170 set fname $line
60556171 } else {
6056- if {$diffids ne $nullid2 && [lindex $line 1] ne " blob" } continue
60576172 set i [string first " \t " $line ]
60586173 if {$i < 0} continue
6059- set sha1 [lindex $line 2]
60606174 set fname [string range $line [expr {$i +1}] end]
6175+ set line [string range $line 0 [expr {$i -1}]]
6176+ if {$diffids ne $nullid2 && [lindex $line 1] ne " blob" } continue
6177+ set sha1 [lindex $line 2]
60616178 if {[string index $fname 0] eq " \" " } {
60626179 set fname [lindex $fname 0]
60636180 }
@@ -6539,26 +6656,44 @@ proc changediffdisp {} {
65396656 $ctext tag conf d1 -elide [lindex $diffelide 1]
65406657}
65416658
6659+ proc highlightfile {loc cline} {
6660+ global ctext cflist cflist_top
6661+
6662+ $ctext yview $loc
6663+ $cflist tag remove highlight $cflist_top .0 " $cflist_top .0 lineend"
6664+ $cflist tag add highlight $cline .0 " $cline .0 lineend"
6665+ $cflist see $cline .0
6666+ set cflist_top $cline
6667+ }
6668+
65426669proc prevfile {} {
6543- global difffilestart ctext
6544- set prev [lindex $difffilestart 0]
6670+ global difffilestart ctext cmitmode
6671+
6672+ if {$cmitmode eq " tree" } return
6673+ set prev 0.0
6674+ set prevline 1
65456675 set here [$ctext index @0,0]
65466676 foreach loc $difffilestart {
65476677 if {[$ctext compare $loc >= $here ]} {
6548- $ctext yview $prev
6678+ highlightfile $prev $prevline
65496679 return
65506680 }
65516681 set prev $loc
6682+ incr prevline
65526683 }
6553- $ctext yview $prev
6684+ highlightfile $prev $prevline
65546685}
65556686
65566687proc nextfile {} {
6557- global difffilestart ctext
6688+ global difffilestart ctext cmitmode
6689+
6690+ if {$cmitmode eq " tree" } return
65586691 set here [$ctext index @0,0]
6692+ set line 1
65596693 foreach loc $difffilestart {
6694+ incr line
65606695 if {[$ctext compare $loc > $here ]} {
6561- $ctext yview $loc
6696+ highlightfile $loc $line
65626697 return
65636698 }
65646699 }
@@ -7070,7 +7205,11 @@ proc rowmenu {x y id} {
70707205 }
70717206 if {$id ne $nullid && $id ne $nullid2 } {
70727207 set menu $rowctxmenu
7073- $menu entryconfigure 7 -label [mc " Reset %s branch to here" $mainhead ]
7208+ if {$mainhead ne {}} {
7209+ $menu entryconfigure 7 -label [mc " Reset %s branch to here" $mainhead ]
7210+ } else {
7211+ $menu entryconfigure 7 -label [mc " Detached head: can't reset" $mainhead ] -state disabled
7212+ }
70747213 } else {
70757214 set menu $fakerowmenu
70767215 }
@@ -8917,9 +9056,15 @@ proc showtag {tag isnew} {
89179056
89189057proc doquit {} {
89199058 global stopped
9059+ global gitktmpdir
9060+
89209061 set stopped 100
89219062 savestuff .
89229063 destroy .
9064+
9065+ if {[info exists gitktmpdir]} {
9066+ catch {file delete -force $gitktmpdir }
9067+ }
89239068}
89249069
89259070proc mkfontdisp {font top which} {
@@ -9048,7 +9193,7 @@ proc doprefs {} {
90489193 global maxwidth maxgraphpct
90499194 global oldprefs prefstop showneartags showlocalchanges
90509195 global bgcolor fgcolor ctext diffcolors selectbgcolor
9051- global tabstop limitdiffs autoselect
9196+ global tabstop limitdiffs autoselect extdifftool
90529197
90539198 set top .gitkprefs
90549199 set prefstop $top
@@ -9100,15 +9245,24 @@ proc doprefs {} {
91009245 pack $top .ldiff.b $top .ldiff.l -side left
91019246 grid x $top .ldiff -sticky w
91029247
9248+ entry $top .extdifft -textvariable extdifftool
9249+ frame $top .extdifff
9250+ label $top .extdifff.l -text [mc " External diff tool" ] -font optionfont \
9251+ -padx 10
9252+ button $top .extdifff.b -text [mc " Choose..." ] -font optionfont \
9253+ -command choose_extdiff
9254+ pack $top .extdifff.l $top .extdifff.b -side left
9255+ grid x $top .extdifff $top .extdifft -sticky w
9256+
91039257 label $top .cdisp -text [mc " Colors: press to choose" ]
91049258 grid $top .cdisp - -sticky w -pady 10
91059259 label $top .bg -padx 40 -relief sunk -background $bgcolor
91069260 button $top .bgbut -text [mc " Background" ] -font optionfont \
9107- -command [list choosecolor bgcolor 0 $top .bg background setbg]
9261+ -command [list choosecolor bgcolor {} $top .bg background setbg]
91089262 grid x $top .bgbut $top .bg -sticky w
91099263 label $top .fg -padx 40 -relief sunk -background $fgcolor
91109264 button $top .fgbut -text [mc " Foreground" ] -font optionfont \
9111- -command [list choosecolor fgcolor 0 $top .fg foreground setfg]
9265+ -command [list choosecolor fgcolor {} $top .fg foreground setfg]
91129266 grid x $top .fgbut $top .fg -sticky w
91139267 label $top .diffold -padx 40 -relief sunk -background [lindex $diffcolors 0]
91149268 button $top .diffoldbut -text [mc " Diff: old lines" ] -font optionfont \
@@ -9128,7 +9282,7 @@ proc doprefs {} {
91289282 grid x $top .hunksepbut $top .hunksep -sticky w
91299283 label $top .selbgsep -padx 40 -relief sunk -background $selectbgcolor
91309284 button $top .selbgbut -text [mc " Select bg" ] -font optionfont \
9131- -command [list choosecolor selectbgcolor 0 $top .selbgsep background setselbg]
9285+ -command [list choosecolor selectbgcolor {} $top .selbgsep background setselbg]
91329286 grid x $top .selbgbut $top .selbgsep -sticky w
91339287
91349288 label $top .cfont -text [mc " Fonts: press to choose" ]
@@ -9147,6 +9301,15 @@ proc doprefs {} {
91479301 bind $top <Visibility> " focus $top .buts.ok"
91489302}
91499303
9304+ proc choose_extdiff {} {
9305+ global extdifftool
9306+
9307+ set prog [tk_getOpenFile -title " External diff tool" -multiple false]
9308+ if {$prog ne {}} {
9309+ set extdifftool $prog
9310+ }
9311+ }
9312+
91509313proc choosecolor {v vi w x cmd} {
91519314 global $v
91529315
@@ -9574,6 +9737,8 @@ set limitdiffs 1
95749737set datetimeformat " %Y-%m-%d %H:%M:%S"
95759738set autoselect 1
95769739
9740+ set extdifftool " meld"
9741+
95779742set colors {green red blue magenta darkgrey brown orange}
95789743set bgcolor white
95799744set fgcolor black
@@ -9680,6 +9845,7 @@ if {$i >= [llength $argv] && $revtreeargs ne {}} {
96809845
96819846set nullid " 0000000000000000000000000000000000000000"
96829847set nullid2 " 0000000000000000000000000000000000000001"
9848+ set nullfile " /dev/null"
96839849
96849850set have_tk85 [expr {[package vcompare $tk_version " 8.5" ] >= 0}]
96859851
0 commit comments