@@ -1088,6 +1088,8 @@ proc makewindow {} {
10881088 -command {flist_hl 0}
10891089 $flist_menu add command -label [mc " Highlight this only" ] \
10901090 -command {flist_hl 1}
1091+ $flist_menu add command -label [mc " External diff" ] \
1092+ -command {external_diff}
10911093}
10921094
10931095# Windows sends all mouse wheel events to the current focused window, not
@@ -1192,7 +1194,7 @@ proc savestuff {w} {
11921194 global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
11931195 global cmitmode wrapcomment datetimeformat limitdiffs
11941196 global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
1195- global autoselect
1197+ global autoselect extdifftool
11961198
11971199 if {$stuffsaved } return
11981200 if {![winfo viewable .]} return
@@ -1218,6 +1220,7 @@ proc savestuff {w} {
12181220 puts $f [list set diffcolors $diffcolors ]
12191221 puts $f [list set diffcontext $diffcontext ]
12201222 puts $f [list set selectbgcolor $selectbgcolor ]
1223+ puts $f [list set extdifftool $extdifftool ]
12211224
12221225 puts $f " set geometry(main) [ wm geometry .] "
12231226 puts $f " set geometry(topwidth) [ winfo width .tf] "
@@ -1768,6 +1771,12 @@ proc pop_flist_menu {w X Y x y} {
17681771 set e [lindex $treediffs($diffids) [expr {$l -2}]]
17691772 }
17701773 set flist_menu_file $e
1774+ set xdiffstate " normal"
1775+ if {$cmitmode eq " tree" } {
1776+ set xdiffstate " disabled"
1777+ }
1778+ # Disable "External diff" item in tree mode
1779+ $flist_menu entryconf 2 -state $xdiffstate
17711780 tk_popup $flist_menu $X $Y
17721781}
17731782
@@ -1783,6 +1792,113 @@ proc flist_hl {only} {
17831792 set gdttype [mc " touching paths:" ]
17841793}
17851794
1795+ proc save_file_from_commit {filename output what} {
1796+ global nullfile
1797+
1798+ if {[catch {exec git show $filename -- > $output } err]} {
1799+ if {[string match " fatal: bad revision *" $err ]} {
1800+ return $nullfile
1801+ }
1802+ error_popup " Error getting \" $filename \" from $what : $err "
1803+ return {}
1804+ }
1805+ return $output
1806+ }
1807+
1808+ proc external_diff_get_one_file {diffid filename diffdir} {
1809+ global nullid nullid2 nullfile
1810+ global gitdir
1811+
1812+ if {$diffid == $nullid } {
1813+ set difffile [file join [file dirname $gitdir ] $filename ]
1814+ if {[file exists $difffile ]} {
1815+ return $difffile
1816+ }
1817+ return $nullfile
1818+ }
1819+ if {$diffid == $nullid2 } {
1820+ set difffile [file join $diffdir " \[ index\] [ file tail $filename ] " ]
1821+ return [save_file_from_commit :$filename $difffile index]
1822+ }
1823+ set difffile [file join $diffdir " \[ $diffid \] [ file tail $filename ] " ]
1824+ return [save_file_from_commit $diffid :$filename $difffile \
1825+ " revision $diffid " ]
1826+ }
1827+
1828+ proc external_diff {} {
1829+ global gitktmpdir nullid nullid2
1830+ global flist_menu_file
1831+ global diffids
1832+ global diffnum
1833+ global gitdir extdifftool
1834+
1835+ if {[llength $diffids ] == 1} {
1836+ # no reference commit given
1837+ set diffidto [lindex $diffids 0]
1838+ if {$diffidto eq $nullid } {
1839+ # diffing working copy with index
1840+ set diffidfrom $nullid2
1841+ } elseif {$diffidto eq $nullid2 } {
1842+ # diffing index with HEAD
1843+ set diffidfrom " HEAD"
1844+ } else {
1845+ # use first parent commit
1846+ global parentlist selectedline
1847+ set diffidfrom [lindex $parentlist $selectedline 0]
1848+ }
1849+ } else {
1850+ set diffidfrom [lindex $diffids 0]
1851+ set diffidto [lindex $diffids 1]
1852+ }
1853+
1854+ # make sure that several diffs wont collide
1855+ if {![info exists gitktmpdir]} {
1856+ set gitktmpdir [file join [file dirname $gitdir ] \
1857+ [format " .gitk-tmp.%s" [pid ]]]
1858+ if {[catch {file mkdir $gitktmpdir } err]} {
1859+ error_popup " Error creating temporary directory $gitktmpdir : $err "
1860+ unset gitktmpdir
1861+ return
1862+ }
1863+ set diffnum 0
1864+ }
1865+ incr diffnum
1866+ set diffdir [file join $gitktmpdir $diffnum ]
1867+ if {[catch {file mkdir $diffdir } err]} {
1868+ error_popup " Error creating temporary directory $diffdir : $err "
1869+ return
1870+ }
1871+
1872+ # gather files to diff
1873+ set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file $diffdir ]
1874+ set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir ]
1875+
1876+ if {$difffromfile ne {} && $difftofile ne {}} {
1877+ set cmd [concat | [shellsplit $extdifftool ] \
1878+ [list $difffromfile $difftofile ]]
1879+ if {[catch {set fl [open $cmd r]} err]} {
1880+ file delete -force $diffdir
1881+ error_popup [mc " $extdifftool : command failed: $err " ]
1882+ } else {
1883+ fconfigure $fl -blocking 0
1884+ filerun $fl [list delete_at_eof $fl $diffdir ]
1885+ }
1886+ }
1887+ }
1888+
1889+ # delete $dir when we see eof on $f (presumably because the child has exited)
1890+ proc delete_at_eof {f dir} {
1891+ while {[gets $f line] >= 0} {}
1892+ if {[eof $f ]} {
1893+ if {[catch {close $f } err]} {
1894+ error_popup " External diff viewer failed: $err "
1895+ }
1896+ file delete -force $dir
1897+ return 0
1898+ }
1899+ return 1
1900+ }
1901+
17861902# Functions for adding and removing shell-type quoting
17871903
17881904proc shellquote {str} {
@@ -7881,9 +7997,15 @@ proc showtag {tag isnew} {
78817997
78827998proc doquit {} {
78837999 global stopped
8000+ global gitktmpdir
8001+
78848002 set stopped 100
78858003 savestuff .
78868004 destroy .
8005+
8006+ if {[info exists gitktmpdir]} {
8007+ catch {file delete -force $gitktmpdir }
8008+ }
78878009}
78888010
78898011proc mkfontdisp {font top which} {
@@ -8012,7 +8134,7 @@ proc doprefs {} {
80128134 global maxwidth maxgraphpct
80138135 global oldprefs prefstop showneartags showlocalchanges
80148136 global bgcolor fgcolor ctext diffcolors selectbgcolor
8015- global tabstop limitdiffs autoselect
8137+ global tabstop limitdiffs autoselect extdifftool
80168138
80178139 set top .gitkprefs
80188140 set prefstop $top
@@ -8064,6 +8186,15 @@ proc doprefs {} {
80648186 pack $top .ldiff.b $top .ldiff.l -side left
80658187 grid x $top .ldiff -sticky w
80668188
8189+ entry $top .extdifft -textvariable extdifftool
8190+ frame $top .extdifff
8191+ label $top .extdifff.l -text [mc " External diff tool" ] -font optionfont \
8192+ -padx 10
8193+ button $top .extdifff.b -text [mc " Choose..." ] -font optionfont \
8194+ -command choose_extdiff
8195+ pack $top .extdifff.l $top .extdifff.b -side left
8196+ grid x $top .extdifff $top .extdifft -sticky w
8197+
80678198 label $top .cdisp -text [mc " Colors: press to choose" ]
80688199 grid $top .cdisp - -sticky w -pady 10
80698200 label $top .bg -padx 40 -relief sunk -background $bgcolor
@@ -8111,6 +8242,15 @@ proc doprefs {} {
81118242 bind $top <Visibility> " focus $top .buts.ok"
81128243}
81138244
8245+ proc choose_extdiff {} {
8246+ global extdifftool
8247+
8248+ set prog [tk_getOpenFile -title " External diff tool" -multiple false]
8249+ if {$prog ne {}} {
8250+ set extdifftool $prog
8251+ }
8252+ }
8253+
81148254proc choosecolor {v vi w x cmd} {
81158255 global $v
81168256
@@ -8539,6 +8679,8 @@ set limitdiffs 1
85398679set datetimeformat " %Y-%m-%d %H:%M:%S"
85408680set autoselect 1
85418681
8682+ set extdifftool " meld"
8683+
85428684set colors {green red blue magenta darkgrey brown orange}
85438685set bgcolor white
85448686set fgcolor black
@@ -8685,6 +8827,7 @@ if {$mergeonly} {
86858827
86868828set nullid " 0000000000000000000000000000000000000000"
86878829set nullid2 " 0000000000000000000000000000000000000001"
8830+ set nullfile " /dev/null"
86888831
86898832set have_tk85 [expr {[package vcompare $tk_version " 8.5" ] >= 0}]
86908833
0 commit comments