@matheusbsbs / matheus-bagliano / commits / 314f5de1a0
Fork 0

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>

Thomas Arcila committed Mar 24, 2008 at 12:55 UTC 314f5de1a0b91d27cbbb8a400337dd41cf84d511
1 file changed +145 -2
gitk
+145 -2
@@ -1088,6 +1088,8 @@ proc makewindow {} {
1088 -command {flist_hl 0}
1089 $flist_menu add command -label [mc "Highlight this only"] \
1090 -command {flist_hl 1}
1091 + $flist_menu add command -label [mc "External diff"] \
1092 + -command {external_diff}
1093 }
1094
1095 # Windows sends all mouse wheel events to the current focused window, not
@@ -1192,7 +1194,7 @@ proc savestuff {w} {
1194 global viewname viewfiles viewargs viewargscmd viewperm nextviewnum
1195 global cmitmode wrapcomment datetimeformat limitdiffs
1196 global colors bgcolor fgcolor diffcolors diffcontext selectbgcolor
1195 - global autoselect
1197 + global autoselect extdifftool
1198
1199 if {$stuffsaved} return
1200 if {![winfo viewable .]} return
@@ -1218,6 +1220,7 @@ proc savestuff {w} {
1220 puts $f [list set diffcolors $diffcolors]
1221 puts $f [list set diffcontext $diffcontext]
1222 puts $f [list set selectbgcolor $selectbgcolor]
1223 + puts $f [list set extdifftool $extdifftool]
1224
1225 puts $f "set geometry(main) [wm geometry .]"
1226 puts $f "set geometry(topwidth) [winfo width .tf]"
@@ -1768,6 +1771,12 @@ proc pop_flist_menu {w X Y x y} {
1771 set e [lindex $treediffs($diffids) [expr {$l-2}]]
1772 }
1773 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
1780 tk_popup $flist_menu $X $Y
1781 }
1782
@@ -1783,6 +1792,113 @@ proc flist_hl {only} {
1792 set gdttype [mc "touching paths:"]
1793 }
1794
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 +
1902 # Functions for adding and removing shell-type quoting
1903
1904 proc shellquote {str} {
@@ -7881,9 +7997,15 @@ proc showtag {tag isnew} {
7997
7998 proc doquit {} {
7999 global stopped
8000 + global gitktmpdir
8001 +
8002 set stopped 100
8003 savestuff .
8004 destroy .
8005 +
8006 + if {[info exists gitktmpdir]} {
8007 + catch {file delete -force $gitktmpdir}
8008 + }
8009 }
8010
8011 proc mkfontdisp {font top which} {
@@ -8012,7 +8134,7 @@ proc doprefs {} {
8134 global maxwidth maxgraphpct
8135 global oldprefs prefstop showneartags showlocalchanges
8136 global bgcolor fgcolor ctext diffcolors selectbgcolor
8015 - global tabstop limitdiffs autoselect
8137 + global tabstop limitdiffs autoselect extdifftool
8138
8139 set top .gitkprefs
8140 set prefstop $top
@@ -8064,6 +8186,15 @@ proc doprefs {} {
8186 pack $top.ldiff.b $top.ldiff.l -side left
8187 grid x $top.ldiff -sticky w
8188
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 +
8198 label $top.cdisp -text [mc "Colors: press to choose"]
8199 grid $top.cdisp - -sticky w -pady 10
8200 label $top.bg -padx 40 -relief sunk -background $bgcolor
@@ -8111,6 +8242,15 @@ proc doprefs {} {
8242 bind $top <Visibility> "focus $top.buts.ok"
8243 }
8244
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 +
8254 proc choosecolor {v vi w x cmd} {
8255 global $v
8256
@@ -8539,6 +8679,8 @@ set limitdiffs 1
8679 set datetimeformat "%Y-%m-%d %H:%M:%S"
8680 set autoselect 1
8681
8682 +set extdifftool "meld"
8683 +
8684 set colors {green red blue magenta darkgrey brown orange}
8685 set bgcolor white
8686 set fgcolor black
@@ -8685,6 +8827,7 @@ if {$mergeonly} {
8827
8828 set nullid "0000000000000000000000000000000000000000"
8829 set nullid2 "0000000000000000000000000000000000000001"
8830 +set nullfile "/dev/null"
8831
8832 set have_tk85 [expr {[package vcompare $tk_version "8.5"] >= 0}]
8833