From: Alexander Gavrilov Date: Sat, 23 Aug 2008 08:31:35 +0000 (+0400) Subject: git-gui: Better positioning in Blame Parent Commit X-Git-Tag: v1.6.1-rc1~3^2~70 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=823f7cf81dbed741c3a645913d7461e9bc04e0d2;p=git.git git-gui: Better positioning in Blame Parent Commit Invoke diff-tree between the commit and its parent, and use the hunks to fix the target line number, accounting for addition and removal of lines. Signed-off-by: Alexander Gavrilov Signed-off-by: Shawn O. Pearce --- diff --git a/lib/blame.tcl b/lib/blame.tcl index ef4223179..110697577 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -984,19 +984,76 @@ method _blameparent {} { set dat [_get_click_amov_info $this] if {$dat ne {}} { set cmit [lindex $dat 0] + set new_path [lindex $dat 1] if {[catch {set cparent [git rev-parse --verify "$cmit^"]}]} { error_popup [strcat [mc "Cannot find parent commit:"] "\n\n$err"] return; } - _load_new_commit $this \ - $cparent \ - [lindex $dat 1] \ - [list [lindex $dat 2]] + _kill $this + + # Generate a diff between the commit and its parent, + # and use the hunks to update the line number. + # Request zero context to simplify calculations. + if {[catch {set fd [eval git_read diff-tree \ + --unified=0 $cparent $cmit $new_path]} err]} { + $status stop [mc "Unable to display parent"] + error_popup [strcat [mc "Error loading diff:"] "\n\n$err"] + return + } + + set r_orig_line [lindex $dat 2] + + fconfigure $fd \ + -blocking 0 \ + -encoding binary \ + -translation binary + fileevent $fd readable [cb _read_diff_load_commit \ + $fd $cparent $new_path $r_orig_line] + set current_fd $fd } } +method _read_diff_load_commit {fd cparent new_path tline} { + if {$fd ne $current_fd} { + catch {close $fd} + return + } + + while {[gets $fd line] >= 0} { + if {[regexp {^@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@} $line line \ + old_line osz old_size new_line nsz new_size]} { + + if {$osz eq {}} { set old_size 1 } + if {$nsz eq {}} { set new_size 1 } + + if {$new_line <= $tline} { + if {[expr {$new_line + $new_size}] > $tline} { + # Target line within the hunk + set line_shift [expr { + ($new_size-$old_size)*($tline-$new_line)/$new_size + }] + } else { + set line_shift [expr {$new_size-$old_size}] + } + + set r_orig_line [expr {$r_orig_line - $line_shift}] + } + } + } + + if {[eof $fd]} { + close $fd; + set current_fd {} + + _load_new_commit $this \ + $cparent \ + $new_path \ + [list $r_orig_line] + } +} ifdeleted { catch {close $fd} } + method _show_tooltip {cur_w pos} { if {$tooltip_wm ne {}} { _open_tooltip $this $cur_w