@matheusbsbs / matheus-bagliano / commits / 8b07dca18a
Fork 0

gitk: Unify handling of merge diffs with normal 2-way diffs

This adds code to getblobdiffline to make it able to recognize and display merge diffs (i.e. N-way diffs for N >= 3) as well as normal two-way diffs. This means that it can also correctly display the 3-way diff of the local changes when the git repository is in the middle of a merge with conflicts. This also removes getmergediffline and changes mergediff to invoke getblobdiffline rather than getmergediffline. Signed-off-by: Paul Mackerras <paulus@samba.org>

Paul Mackerras committed Nov 2, 2008 at 22:34 UTC 8b07dca18a498c5900edc717d216e841d6c15dc9
1 file changed +99 -171
gitk
+99 -171
@@ -2098,7 +2098,7 @@ proc makewindow {} {
2098 $ctext tag conf filesep -font textfontbold -back "#aaaaaa"
2099 $ctext tag conf hunksep -fore [lindex $diffcolors 2]
2100 $ctext tag conf d0 -fore [lindex $diffcolors 0]
2101 - $ctext tag conf d1 -fore [lindex $diffcolors 1]
2101 + $ctext tag conf dresult -fore [lindex $diffcolors 1]
2102 $ctext tag conf m0 -fore red
2103 $ctext tag conf m1 -fore blue
2104 $ctext tag conf m2 -fore green
@@ -3217,7 +3217,7 @@ proc find_hunk_blamespec {base line} {
3217 }
3218
3219 proc external_blame_diff {} {
3220 - global currentid diffmergeid cmitmode
3220 + global currentid cmitmode
3221 global diff_menu_txtpos diff_menu_line
3222 global diff_menu_filebase flist_menu_file
3223
@@ -6668,130 +6668,16 @@ proc mark_ctext_line {lnum} {
6668 }
6669
6670 proc mergediff {id} {
6671 - global diffmergeid mdifffd
6671 + global diffmergeid
6672 global diffids treediffs
6673 - global parents
6674 - global diffcontext
6675 - global diffencoding
6676 - global limitdiffs vfilelimit curview
6677 - global targetline
6673 + global parents curview
6674
6675 set diffmergeid $id
6676 set diffids $id
6677 set treediffs($id) {}
6682 - set targetline {}
6683 - # this doesn't seem to actually affect anything...
6684 - set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id]
6685 - if {$limitdiffs && $vfilelimit($curview) ne {}} {
6686 - set cmd [concat $cmd -- $vfilelimit($curview)]
6687 - }
6688 - if {[catch {set mdf [open $cmd r]} err]} {
6689 - error_popup "[mc "Error getting merge diffs:"] $err"
6690 - return
6691 - }
6692 - fconfigure $mdf -blocking 0 -encoding binary
6693 - set mdifffd($id) $mdf
6678 set np [llength $parents($curview,$id)]
6695 - set diffencoding [get_path_encoding {}]
6679 settabs $np
6697 - filerun $mdf [list getmergediffline $mdf $id $np]
6698 -}
6699 -
6700 -proc getmergediffline {mdf id np} {
6701 - global diffmergeid ctext cflist mergemax
6702 - global difffilestart mdifffd treediffs
6703 - global ctext_file_names ctext_file_lines
6704 - global diffencoding jump_to_here targetline diffline
6705 -
6706 - $ctext conf -state normal
6707 - set nr 0
6708 - while {[incr nr] <= 1000 && [gets $mdf line] >= 0} {
6709 - if {![info exists diffmergeid] || $id != $diffmergeid
6710 - || $mdf != $mdifffd($id)} {
6711 - close $mdf
6712 - return 0
6713 - }
6714 - if {[regexp {^diff --cc (.*)} $line match fname]} {
6715 - # start of a new file
6716 - set fname [encoding convertfrom $fname]
6717 - $ctext insert end "\n"
6718 - set here [$ctext index "end - 1c"]
6719 - lappend difffilestart $here
6720 - lappend treediffs($id) $fname
6721 - add_flist [list $fname]
6722 - lappend ctext_file_names $fname
6723 - lappend ctext_file_lines [lindex [split $here "."] 0]
6724 - set diffencoding [get_path_encoding $fname]
6725 - set l [expr {(78 - [string length $fname]) / 2}]
6726 - set pad [string range "----------------------------------------" 1 $l]
6727 - $ctext insert end "$pad $fname $pad\n" filesep
6728 - set targetline {}
6729 - if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname} {
6730 - set targetline [lindex $jump_to_here 1]
6731 - }
6732 - set diffline 0
6733 - } elseif {[regexp {^@@} $line]} {
6734 - set line [encoding convertfrom $diffencoding $line]
6735 - $ctext insert end "$line\n" hunksep
6736 - if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
6737 - set diffline $nl
6738 - }
6739 - } elseif {[regexp {^[0-9a-f]{40}$} $line] || [regexp {^index} $line]} {
6740 - # do nothing
6741 - } else {
6742 - set line [encoding convertfrom $diffencoding $line]
6743 - # parse the prefix - one ' ', '-' or '+' for each parent
6744 - set spaces {}
6745 - set minuses {}
6746 - set pluses {}
6747 - set isbad 0
6748 - for {set j 0} {$j < $np} {incr j} {
6749 - set c [string range $line $j $j]
6750 - if {$c == " "} {
6751 - lappend spaces $j
6752 - } elseif {$c == "-"} {
6753 - lappend minuses $j
6754 - } elseif {$c == "+"} {
6755 - lappend pluses $j
6756 - } else {
6757 - set isbad 1
6758 - break
6759 - }
6760 - }
6761 - set tags {}
6762 - set num {}
6763 - if {!$isbad && $minuses ne {} && $pluses eq {}} {
6764 - # line doesn't appear in result, parents in $minuses have the line
6765 - set num [lindex $minuses 0]
6766 - } elseif {!$isbad && $pluses ne {} && $minuses eq {}} {
6767 - # line appears in result, parents in $pluses don't have the line
6768 - lappend tags mresult
6769 - set num [lindex $spaces 0]
6770 - }
6771 - if {$num ne {}} {
6772 - if {$num >= $mergemax} {
6773 - set num "max"
6774 - }
6775 - lappend tags m$num
6776 - }
6777 - $ctext insert end "$line\n" $tags
6778 - if {$targetline ne {} && $minuses eq {}} {
6779 - if {$diffline == $targetline} {
6780 - set here [$ctext index "end - 1 line"]
6781 - mark_ctext_line [lindex [split $here .] 0]
6782 - set targetline {}
6783 - } else {
6784 - incr diffline
6785 - }
6786 - }
6787 - }
6788 - }
6789 - $ctext conf -state disabled
6790 - if {[eof $mdf]} {
6791 - close $mdf
6792 - return 0
6793 - }
6794 - return [expr {$nr >= 1000? 2: 1}]
6680 + getblobdiffs $id
6681 }
6682
6683 proc startdiff {ids} {
@@ -6971,9 +6857,9 @@ proc getblobdiffs {ids} {
6857 global diffcontext
6858 global ignorespace
6859 global limitdiffs vfilelimit curview
6974 - global diffencoding targetline
6860 + global diffencoding targetline diffnparents
6861
6976 - set cmd [diffcmd $ids "-p -C --no-commit-id -U$diffcontext"]
6862 + set cmd [diffcmd $ids "-p -C --cc --no-commit-id -U$diffcontext"]
6863 if {$ignorespace} {
6864 append cmd " -w"
6865 }
@@ -6981,10 +6867,11 @@ proc getblobdiffs {ids} {
6867 set cmd [concat $cmd -- $vfilelimit($curview)]
6868 }
6869 if {[catch {set bdf [open $cmd r]} err]} {
6984 - puts "error getting diffs: $err"
6870 + error_popup [mc "Error getting diffs: %s" $err]
6871 return
6872 }
6873 set targetline {}
6874 + set diffnparents 0
6875 set diffinhdr 0
6876 set diffencoding [get_path_encoding {}]
6877 fconfigure $bdf -blocking 0 -encoding binary
@@ -7006,9 +6893,11 @@ proc setinlist {var i val} {
6893 }
6894
6895 proc makediffhdr {fname ids} {
7009 - global ctext curdiffstart treediffs
6896 + global ctext curdiffstart treediffs diffencoding
6897 global ctext_file_names jump_to_here targetline diffline
6898
6899 + set fname [encoding convertfrom $fname]
6900 + set diffencoding [get_path_encoding $fname]
6901 set i [lsearch -exact $treediffs($ids) $fname]
6902 if {$i >= 0} {
6903 setinlist difffilestart $i $curdiffstart
@@ -7028,7 +6917,7 @@ proc getblobdiffline {bdf ids} {
6917 global diffids blobdifffd ctext curdiffstart
6918 global diffnexthead diffnextnote difffilestart
6919 global ctext_file_names ctext_file_lines
7031 - global diffinhdr treediffs
6920 + global diffinhdr treediffs mergemax diffnparents
6921 global diffencoding jump_to_here targetline diffline
6922
6923 set nr 0
@@ -7038,47 +6927,63 @@ proc getblobdiffline {bdf ids} {
6927 close $bdf
6928 return 0
6929 }
7041 - if {![string compare -length 11 "diff --git " $line]} {
7042 - # trim off "diff --git "
7043 - set line [string range $line 11 end]
7044 - set diffinhdr 1
6930 + if {![string compare -length 5 "diff " $line]} {
6931 + if {![regexp {^diff (--cc|--git) } $line m type]} {
6932 + set line [encoding convertfrom $line]
6933 + $ctext insert end "$line\n" hunksep
6934 + continue
6935 + }
6936 # start of a new file
6937 + set diffinhdr 1
6938 $ctext insert end "\n"
6939 set curdiffstart [$ctext index "end - 1c"]
6940 lappend ctext_file_names ""
6941 lappend ctext_file_lines [lindex [split $curdiffstart "."] 0]
6942 $ctext insert end "\n" filesep
7051 - # If the name hasn't changed the length will be odd,
7052 - # the middle char will be a space, and the two bits either
7053 - # side will be a/name and b/name, or "a/name" and "b/name".
7054 - # If the name has changed we'll get "rename from" and
7055 - # "rename to" or "copy from" and "copy to" lines following this,
7056 - # and we'll use them to get the filenames.
7057 - # This complexity is necessary because spaces in the filename(s)
7058 - # don't get escaped.
7059 - set l [string length $line]
7060 - set i [expr {$l / 2}]
7061 - if {!(($l & 1) && [string index $line $i] eq " " &&
7062 - [string range $line 2 [expr {$i - 1}]] eq \
7063 - [string range $line [expr {$i + 3}] end])} {
7064 - continue
7065 - }
7066 - # unescape if quoted and chop off the a/ from the front
7067 - if {[string index $line 0] eq "\""} {
7068 - set fname [string range [lindex $line 0] 2 end]
6943 +
6944 + if {$type eq "--cc"} {
6945 + # start of a new file in a merge diff
6946 + set fname [string range $line 10 end]
6947 + if {[lsearch -exact $treediffs($ids) $fname] < 0} {
6948 + lappend treediffs($ids) $fname
6949 + add_flist [list $fname]
6950 + }
6951 +
6952 } else {
7070 - set fname [string range $line 2 [expr {$i - 1}]]
6953 + set line [string range $line 11 end]
6954 + # If the name hasn't changed the length will be odd,
6955 + # the middle char will be a space, and the two bits either
6956 + # side will be a/name and b/name, or "a/name" and "b/name".
6957 + # If the name has changed we'll get "rename from" and
6958 + # "rename to" or "copy from" and "copy to" lines following
6959 + # this, and we'll use them to get the filenames.
6960 + # This complexity is necessary because spaces in the
6961 + # filename(s) don't get escaped.
6962 + set l [string length $line]
6963 + set i [expr {$l / 2}]
6964 + if {!(($l & 1) && [string index $line $i] eq " " &&
6965 + [string range $line 2 [expr {$i - 1}]] eq \
6966 + [string range $line [expr {$i + 3}] end])} {
6967 + continue
6968 + }
6969 + # unescape if quoted and chop off the a/ from the front
6970 + if {[string index $line 0] eq "\""} {
6971 + set fname [string range [lindex $line 0] 2 end]
6972 + } else {
6973 + set fname [string range $line 2 [expr {$i - 1}]]
6974 + }
6975 }
7072 - set fname [encoding convertfrom $fname]
7073 - set diffencoding [get_path_encoding $fname]
6976 makediffhdr $fname $ids
6977
7076 - } elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
7077 - $line match f1l f1c f2l f2c rest]} {
6978 + } elseif {![string compare -length 2 "@@" $line]} {
6979 + regexp {^@@+} $line ats
6980 set line [encoding convertfrom $diffencoding $line]
6981 $ctext insert end "$line\n" hunksep
6982 + if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
6983 + set diffline $nl
6984 + }
6985 + set diffnparents [expr {[string length $ats] - 1}]
6986 set diffinhdr 0
7081 - set diffline $f2l
6987
6988 } elseif {$diffinhdr} {
6989 if {![string compare -length 12 "rename from " $line]} {
@@ -7097,8 +7002,6 @@ proc getblobdiffline {bdf ids} {
7002 if {[string index $fname 0] eq "\""} {
7003 set fname [lindex $fname 0]
7004 }
7100 - set fname [encoding convertfrom $fname]
7101 - set diffencoding [get_path_encoding $fname]
7005 makediffhdr $fname $ids
7006 } elseif {[string compare -length 3 $line "---"] == 0} {
7007 # do nothing
@@ -7111,28 +7014,53 @@ proc getblobdiffline {bdf ids} {
7014
7015 } else {
7016 set line [encoding convertfrom $diffencoding $line]
7114 - set x [string range $line 0 0]
7115 - set here [$ctext index "end - 1 chars"]
7116 - if {$x == "-" || $x == "+"} {
7117 - set tag [expr {$x == "+"}]
7118 - $ctext insert end "$line\n" d$tag
7119 - } elseif {$x == " "} {
7120 - $ctext insert end "$line\n"
7017 + # parse the prefix - one ' ', '-' or '+' for each parent
7018 + set prefix [string range $line 0 [expr {$diffnparents - 1}]]
7019 + set tag [expr {$diffnparents > 1? "m": "d"}]
7020 + if {[string trim $prefix " -+"] eq {}} {
7021 + # prefix only has " ", "-" and "+" in it: normal diff line
7022 + set num [string first "-" $prefix]
7023 + if {$num >= 0} {
7024 + # removed line, first parent with line is $num
7025 + if {$num >= $mergemax} {
7026 + set num "max"
7027 + }
7028 + $ctext insert end "$line\n" $tag$num
7029 + } else {
7030 + set tags {}
7031 + if {[string first "+" $prefix] >= 0} {
7032 + # added line
7033 + lappend tags ${tag}result
7034 + if {$diffnparents > 1} {
7035 + set num [string first " " $prefix]
7036 + if {$num >= 0} {
7037 + if {$num >= $mergemax} {
7038 + set num "max"
7039 + }
7040 + lappend tags m$num
7041 + }
7042 + }
7043 + }
7044 + if {$targetline ne {}} {
7045 + if {$diffline == $targetline} {
7046 + set seehere [$ctext index "end - 1 chars"]
7047 + set targetline {}
7048 + } else {
7049 + incr diffline
7050 + }
7051 + }
7052 + $ctext insert end "$line\n" $tags
7053 + }
7054 } else {
7055 # "\ No newline at end of file",
7056 # or something else we don't recognize
7057 $ctext insert end "$line\n" hunksep
7058 }
7126 - if {$targetline ne {} && ($x eq " " || $x eq "+")} {
7127 - if {$diffline == $targetline} {
7128 - mark_ctext_line [lindex [split $here .] 0]
7129 - set targetline {}
7130 - } else {
7131 - incr diffline
7132 - }
7133 - }
7059 }
7060 }
7061 + if {[info exists seehere]} {
7062 + mark_ctext_line [lindex [split $seehere .] 0]
7063 + }
7064 $ctext conf -state disabled
7065 if {[eof $bdf]} {
7066 close $bdf
@@ -7145,7 +7073,7 @@ proc changediffdisp {} {
7073 global ctext diffelide
7074
7075 $ctext tag conf d0 -elide [lindex $diffelide 0]
7148 - $ctext tag conf d1 -elide [lindex $diffelide 1]
7076 + $ctext tag conf dresult -elide [lindex $diffelide 1]
7077 }
7078
7079 proc highlightfile {loc cline} {
@@ -9817,7 +9745,7 @@ proc doprefs {} {
9745 label $top.diffnew -padx 40 -relief sunk -background [lindex $diffcolors 1]
9746 button $top.diffnewbut -text [mc "Diff: new lines"] -font optionfont \
9747 -command [list choosecolor diffcolors 1 $top.diffnew "diff new lines" \
9820 - [list $ctext tag conf d1 -foreground]]
9748 + [list $ctext tag conf dresult -foreground]]
9749 grid x $top.diffnewbut $top.diffnew -sticky w
9750 label $top.hunksep -padx 40 -relief sunk -background [lindex $diffcolors 2]
9751 button $top.hunksepbut -text [mc "Diff: hunk header"] -font optionfont \