Browse Source

gitk: Allow users to view diffs in external diff viewer

This allows gitk to run an external diff viewer such as meld.

Right-click on a file in the file list view gives "External diff"
popup menu entry, which launches the selected external diff tool.
The menu entry is only active in "Patch" mode, not in "Tree" mode.

The program to run to display the diff is configurable through
Edit/Preference/External diff tool.  The program is run with two
arguments, being the names of files containing the two versions to
diff.  Gitk will create temporary directories called
.gitk-tmp.<pid>/<n> to place these files in, and remove them when
it's finished.

If the file doesn't exist in one or other revision, gitk will supply
/dev/null as the name of the file on that side of the diff.  This may
need to be adjusted for Windows or MacOS.

[paulus@samba.org - cleaned up and rewrote some parts of the patch.]

Signed-off-by: Thomas Arcila <thomas.arcila@gmail.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
maint
Thomas Arcila 17 years ago committed by Paul Mackerras
parent
commit
314f5de1a0
  1. 147
      gitk

147
gitk

@ -1088,6 +1088,8 @@ proc makewindow {} { @@ -1088,6 +1088,8 @@ proc makewindow {} {
-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}
}

# Windows sends all mouse wheel events to the current focused window, not
@ -1192,7 +1194,7 @@ proc savestuff {w} { @@ -1192,7 +1194,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
global autoselect extdifftool

if {$stuffsaved} return
if {![winfo viewable .]} return
@ -1218,6 +1220,7 @@ proc savestuff {w} { @@ -1218,6 +1220,7 @@ proc savestuff {w} {
puts $f [list set diffcolors $diffcolors]
puts $f [list set diffcontext $diffcontext]
puts $f [list set selectbgcolor $selectbgcolor]
puts $f [list set extdifftool $extdifftool]

puts $f "set geometry(main) [wm geometry .]"
puts $f "set geometry(topwidth) [winfo width .tf]"
@ -1768,6 +1771,12 @@ proc pop_flist_menu {w X Y x y} { @@ -1768,6 +1771,12 @@ proc pop_flist_menu {w X Y x y} {
set e [lindex $treediffs($diffids) [expr {$l-2}]]
}
set flist_menu_file $e
set xdiffstate "normal"
if {$cmitmode eq "tree"} {
set xdiffstate "disabled"
}
# Disable "External diff" item in tree mode
$flist_menu entryconf 2 -state $xdiffstate
tk_popup $flist_menu $X $Y
}

@ -1783,6 +1792,113 @@ proc flist_hl {only} { @@ -1783,6 +1792,113 @@ proc flist_hl {only} {
set gdttype [mc "touching paths:"]
}

proc save_file_from_commit {filename output what} {
global nullfile

if {[catch {exec git show $filename -- > $output} err]} {
if {[string match "fatal: bad revision *" $err]} {
return $nullfile
}
error_popup "Error getting \"$filename\" from $what: $err"
return {}
}
return $output
}

proc external_diff_get_one_file {diffid filename diffdir} {
global nullid nullid2 nullfile
global gitdir

if {$diffid == $nullid} {
set difffile [file join [file dirname $gitdir] $filename]
if {[file exists $difffile]} {
return $difffile
}
return $nullfile
}
if {$diffid == $nullid2} {
set difffile [file join $diffdir "\[index\] [file tail $filename]"]
return [save_file_from_commit :$filename $difffile index]
}
set difffile [file join $diffdir "\[$diffid\] [file tail $filename]"]
return [save_file_from_commit $diffid:$filename $difffile \
"revision $diffid"]
}

proc external_diff {} {
global gitktmpdir nullid nullid2
global flist_menu_file
global diffids
global diffnum
global gitdir extdifftool

if {[llength $diffids] == 1} {
# no reference commit given
set diffidto [lindex $diffids 0]
if {$diffidto eq $nullid} {
# diffing working copy with index
set diffidfrom $nullid2
} elseif {$diffidto eq $nullid2} {
# diffing index with HEAD
set diffidfrom "HEAD"
} else {
# use first parent commit
global parentlist selectedline
set diffidfrom [lindex $parentlist $selectedline 0]
}
} else {
set diffidfrom [lindex $diffids 0]
set diffidto [lindex $diffids 1]
}

# make sure that several diffs wont collide
if {![info exists gitktmpdir]} {
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"
unset gitktmpdir
return
}
set diffnum 0
}
incr diffnum
set diffdir [file join $gitktmpdir $diffnum]
if {[catch {file mkdir $diffdir} err]} {
error_popup "Error creating temporary directory $diffdir: $err"
return
}

# gather files to diff
set difffromfile [external_diff_get_one_file $diffidfrom $flist_menu_file $diffdir]
set difftofile [external_diff_get_one_file $diffidto $flist_menu_file $diffdir]

if {$difffromfile ne {} && $difftofile ne {}} {
set cmd [concat | [shellsplit $extdifftool] \
[list $difffromfile $difftofile]]
if {[catch {set fl [open $cmd r]} err]} {
file delete -force $diffdir
error_popup [mc "$extdifftool: command failed: $err"]
} else {
fconfigure $fl -blocking 0
filerun $fl [list delete_at_eof $fl $diffdir]
}
}
}

# 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"
}
file delete -force $dir
return 0
}
return 1
}

# Functions for adding and removing shell-type quoting

proc shellquote {str} {
@ -7881,9 +7997,15 @@ proc showtag {tag isnew} { @@ -7881,9 +7997,15 @@ proc showtag {tag isnew} {

proc doquit {} {
global stopped
global gitktmpdir

set stopped 100
savestuff .
destroy .

if {[info exists gitktmpdir]} {
catch {file delete -force $gitktmpdir}
}
}

proc mkfontdisp {font top which} {
@ -8012,7 +8134,7 @@ proc doprefs {} { @@ -8012,7 +8134,7 @@ proc doprefs {} {
global maxwidth maxgraphpct
global oldprefs prefstop showneartags showlocalchanges
global bgcolor fgcolor ctext diffcolors selectbgcolor
global tabstop limitdiffs autoselect
global tabstop limitdiffs autoselect extdifftool

set top .gitkprefs
set prefstop $top
@ -8064,6 +8186,15 @@ proc doprefs {} { @@ -8064,6 +8186,15 @@ proc doprefs {} {
pack $top.ldiff.b $top.ldiff.l -side left
grid x $top.ldiff -sticky w

entry $top.extdifft -textvariable extdifftool
frame $top.extdifff
label $top.extdifff.l -text [mc "External diff tool" ] -font optionfont \
-padx 10
button $top.extdifff.b -text [mc "Choose..."] -font optionfont \
-command choose_extdiff
pack $top.extdifff.l $top.extdifff.b -side left
grid x $top.extdifff $top.extdifft -sticky w

label $top.cdisp -text [mc "Colors: press to choose"]
grid $top.cdisp - -sticky w -pady 10
label $top.bg -padx 40 -relief sunk -background $bgcolor
@ -8111,6 +8242,15 @@ proc doprefs {} { @@ -8111,6 +8242,15 @@ proc doprefs {} {
bind $top <Visibility> "focus $top.buts.ok"
}

proc choose_extdiff {} {
global extdifftool

set prog [tk_getOpenFile -title "External diff tool" -multiple false]
if {$prog ne {}} {
set extdifftool $prog
}
}

proc choosecolor {v vi w x cmd} {
global $v

@ -8539,6 +8679,8 @@ set limitdiffs 1 @@ -8539,6 +8679,8 @@ set limitdiffs 1
set datetimeformat "%Y-%m-%d %H:%M:%S"
set autoselect 1

set extdifftool "meld"

set colors {green red blue magenta darkgrey brown orange}
set bgcolor white
set fgcolor black
@ -8685,6 +8827,7 @@ if {$mergeonly} { @@ -8685,6 +8827,7 @@ if {$mergeonly} {

set nullid "0000000000000000000000000000000000000000"
set nullid2 "0000000000000000000000000000000000000001"
set nullfile "/dev/null"

set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]


Loading…
Cancel
Save