Skip to content

Commit 9396cd3

Browse files
committed
gitk: Improve handling of whitespace and special chars in filenames
The main thing here is better parsing of the diff --git lines in the output of git diff-tree -p. We now cope with filenames in quotes with special chars escaped. If the filenames contain spaces they aren't quoted, however, which can create difficulties in parsing. We get around the difficulties by detecting the case when the filename hasn't changed (chop the part after "diff --git " in two and see if the halves match apart from a/ in one and b/ in the other), and if it hasn't changed, we just use one half. If the filename has changed we wait for the "rename from" and "rename to" lines, which give the old and new filenames unambiguously. This also improves the parsing of the output of git diff-tree. Instead of using lindex to extract the filename, we take the part from the first tab on, and if it starts with a quote, we use [lindex $str 0] to remove the quotes and convert the escapes. This also gets rid of some unused tagging of the diff text, uses [string compare] instead of [regexp] in some places, and fixes the regexp for detecting the @@ hunk-separator lines (the regexp wasn't accepting a single number, as in "-0,0 +1" for example). Signed-off-by: Paul Mackerras <[email protected]>
1 parent f3326b6 commit 9396cd3

File tree

1 file changed

+84
-51
lines changed

1 file changed

+84
-51
lines changed

gitk

Lines changed: 84 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4400,7 +4400,6 @@ proc selectline {l isnew} {
44004400
}
44014401
appendwithlinks $comment {comment}
44024402

4403-
$ctext tag delete Comments
44044403
$ctext tag remove found 1.0 end
44054404
$ctext conf -state disabled
44064405
set commentend [$ctext index "end - 1c"]
@@ -4566,10 +4565,11 @@ proc gettreeline {gtf id} {
45664565
set nl 0
45674566
while {[incr nl] <= 1000 && [gets $gtf line] >= 0} {
45684567
if {$diffids ne $nullid} {
4569-
set tl [split $line "\t"]
4570-
if {[lindex $tl 0 1] ne "blob"} continue
4571-
set sha1 [lindex $tl 0 2]
4572-
set fname [lindex $tl 1]
4568+
if {[lindex $line 1] ne "blob"} continue
4569+
set i [string first "\t" $line]
4570+
if {$i < 0} continue
4571+
set sha1 [lindex $line 2]
4572+
set fname [string range $line [expr {$i+1}] end]
45734573
if {[string index $fname 0] eq "\""} {
45744574
set fname [lindex $fname 0]
45754575
}
@@ -4797,8 +4797,14 @@ proc gettreediffline {gdtf ids} {
47974797

47984798
set nr 0
47994799
while {[incr nr] <= 1000 && [gets $gdtf line] >= 0} {
4800-
set file [lindex $line 5]
4801-
lappend treediff $file
4800+
set i [string first "\t" $line]
4801+
if {$i >= 0} {
4802+
set file [string range $line [expr {$i+1}] end]
4803+
if {[string index $file 0] eq "\""} {
4804+
set file [lindex $file 0]
4805+
}
4806+
lappend treediff $file
4807+
}
48024808
}
48034809
if {![eof $gdtf]} {
48044810
return [expr {$nr >= 1000? 2: 1}]
@@ -4819,7 +4825,7 @@ proc gettreediffline {gdtf ids} {
48194825
}
48204826

48214827
proc getblobdiffs {ids} {
4822-
global diffopts blobdifffd diffids env curdifftag curtagstart
4828+
global diffopts blobdifffd diffids env
48234829
global diffinhdr treediffs
48244830

48254831
set env(GIT_DIFF_OPTS) $diffopts
@@ -4830,8 +4836,6 @@ proc getblobdiffs {ids} {
48304836
set diffinhdr 0
48314837
fconfigure $bdf -blocking 0
48324838
set blobdifffd($ids) $bdf
4833-
set curdifftag Comments
4834-
set curtagstart 0.0
48354839
filerun $bdf [list getblobdiffline $bdf $diffids]
48364840
}
48374841

@@ -4848,8 +4852,20 @@ proc setinlist {var i val} {
48484852
}
48494853
}
48504854

4855+
proc makediffhdr {fname ids} {
4856+
global ctext curdiffstart treediffs
4857+
4858+
set i [lsearch -exact $treediffs($ids) $fname]
4859+
if {$i >= 0} {
4860+
setinlist difffilestart $i $curdiffstart
4861+
}
4862+
set l [expr {(78 - [string length $fname]) / 2}]
4863+
set pad [string range "----------------------------------------" 1 $l]
4864+
$ctext insert $curdiffstart "$pad $fname $pad" filesep
4865+
}
4866+
48514867
proc getblobdiffline {bdf ids} {
4852-
global diffids blobdifffd ctext curdifftag curtagstart
4868+
global diffids blobdifffd ctext curdiffstart
48534869
global diffnexthead diffnextnote difffilestart
48544870
global diffinhdr treediffs
48554871

@@ -4860,66 +4876,84 @@ proc getblobdiffline {bdf ids} {
48604876
close $bdf
48614877
return 0
48624878
}
4863-
if {[regexp {^diff --git a/(.*) b/(.*)} $line match fname newname]} {
4879+
if {![string compare -length 11 "diff --git " $line]} {
4880+
# trim off "diff --git "
4881+
set line [string range $line 11 end]
4882+
set diffinhdr 1
48644883
# start of a new file
48654884
$ctext insert end "\n"
4866-
$ctext tag add $curdifftag $curtagstart end
4867-
set here [$ctext index "end - 1c"]
4868-
set curtagstart $here
4869-
set header $newname
4870-
set i [lsearch -exact $treediffs($ids) $fname]
4871-
if {$i >= 0} {
4872-
setinlist difffilestart $i $here
4885+
set curdiffstart [$ctext index "end - 1c"]
4886+
$ctext insert end "\n" filesep
4887+
# If the name hasn't changed the length will be odd,
4888+
# the middle char will be a space, and the two bits either
4889+
# side will be a/name and b/name, or "a/name" and "b/name".
4890+
# If the name has changed we'll get "rename from" and
4891+
# "rename to" lines following this, and we'll use them
4892+
# to get the filenames.
4893+
# This complexity is necessary because spaces in the filename(s)
4894+
# don't get escaped.
4895+
set l [string length $line]
4896+
set i [expr {$l / 2}]
4897+
if {!(($l & 1) && [string index $line $i] eq " " &&
4898+
[string range $line 2 [expr {$i - 1}]] eq \
4899+
[string range $line [expr {$i + 3}] end])} {
4900+
continue
48734901
}
4874-
if {$newname ne $fname} {
4875-
set i [lsearch -exact $treediffs($ids) $newname]
4876-
if {$i >= 0} {
4877-
setinlist difffilestart $i $here
4878-
}
4902+
# unescape if quoted and chop off the a/ from the front
4903+
if {[string index $line 0] eq "\""} {
4904+
set fname [string range [lindex $line 0] 2 end]
4905+
} else {
4906+
set fname [string range $line 2 [expr {$i - 1}]]
48794907
}
4880-
set curdifftag "f:$fname"
4881-
$ctext tag delete $curdifftag
4882-
set l [expr {(78 - [string length $header]) / 2}]
4883-
set pad [string range "----------------------------------------" \
4884-
1 $l]
4885-
$ctext insert end "$pad $header $pad\n" filesep
4886-
set diffinhdr 1
4887-
} elseif {$diffinhdr && [string compare -length 3 $line "---"] == 0} {
4888-
# do nothing
4889-
} elseif {$diffinhdr && [string compare -length 3 $line "+++"] == 0} {
4890-
set diffinhdr 0
4891-
} elseif {[regexp {^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@(.*)} \
4908+
makediffhdr $fname $ids
4909+
4910+
} elseif {[regexp {^@@ -([0-9]+)(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@(.*)} \
48924911
$line match f1l f1c f2l f2c rest]} {
48934912
$ctext insert end "$line\n" hunksep
48944913
set diffinhdr 0
4914+
4915+
} elseif {$diffinhdr} {
4916+
if {![string compare -length 12 "rename from " $line]} {
4917+
set fname [string range $line 12 end]
4918+
if {[string index $fname 0] eq "\""} {
4919+
set fname [lindex $fname 0]
4920+
}
4921+
set i [lsearch -exact $treediffs($ids) $fname]
4922+
if {$i >= 0} {
4923+
setinlist difffilestart $i $curdiffstart
4924+
}
4925+
} elseif {![string compare -length 10 $line "rename to "]} {
4926+
set fname [string range $line 10 end]
4927+
if {[string index $fname 0] eq "\""} {
4928+
set fname [lindex $fname 0]
4929+
}
4930+
makediffhdr $fname $ids
4931+
} elseif {[string compare -length 3 $line "---"] == 0} {
4932+
# do nothing
4933+
continue
4934+
} elseif {[string compare -length 3 $line "+++"] == 0} {
4935+
set diffinhdr 0
4936+
continue
4937+
}
4938+
$ctext insert end "$line\n" filesep
4939+
48954940
} else {
48964941
set x [string range $line 0 0]
48974942
if {$x == "-" || $x == "+"} {
48984943
set tag [expr {$x == "+"}]
48994944
$ctext insert end "$line\n" d$tag
49004945
} elseif {$x == " "} {
49014946
$ctext insert end "$line\n"
4902-
} elseif {$diffinhdr || $x == "\\"} {
4903-
# e.g. "\ No newline at end of file"
4904-
$ctext insert end "$line\n" filesep
49054947
} else {
4906-
# Something else we don't recognize
4907-
if {$curdifftag != "Comments"} {
4908-
$ctext insert end "\n"
4909-
$ctext tag add $curdifftag $curtagstart end
4910-
set curtagstart [$ctext index "end - 1c"]
4911-
set curdifftag Comments
4912-
}
4913-
$ctext insert end "$line\n" filesep
4948+
# "\ No newline at end of file",
4949+
# or something else we don't recognize
4950+
$ctext insert end "$line\n" hunksep
49144951
}
49154952
}
49164953
}
49174954
$ctext conf -state disabled
49184955
if {[eof $bdf]} {
49194956
close $bdf
4920-
if {$ids == $diffids && $bdf == $blobdifffd($ids)} {
4921-
$ctext tag add $curdifftag $curtagstart end
4922-
}
49234957
return 0
49244958
}
49254959
return [expr {$nr >= 1000? 2: 1}]
@@ -5444,7 +5478,6 @@ proc doseldiff {oldid newid} {
54445478
$ctext insert end [lindex $commitinfo($newid) 0]
54455479
$ctext insert end "\n"
54465480
$ctext conf -state disabled
5447-
$ctext tag delete Comments
54485481
$ctext tag remove found 1.0 end
54495482
startdiff [list $oldid $newid]
54505483
}

0 commit comments

Comments
 (0)