@@ -2296,6 +2296,7 @@ proc makewindow {} {
22962296 global diff_menu
22972297 set diff_menu .diffctxmenu
22982298 makemenu $diff_menu {
2299+ {mc " Show origin of this line" command show_line_source}
22992300 {mc " Run git gui blame on this line" command {external_blame_diff}}
23002301 }
23012302 $diff_menu configure -tearoff 0
@@ -2830,9 +2831,15 @@ proc treeclick {w x y} {
28302831}
28312832
28322833proc setfilelist {id} {
2833- global treefilelist cflist
2834+ global treefilelist cflist jump_to_here
28342835
28352836 treeview $cflist $treefilelist($id) 0
2837+ if {$jump_to_here ne {}} {
2838+ set f [lindex $jump_to_here 0]
2839+ if {[lsearch -exact $treefilelist($id) $f ] >= 0} {
2840+ showfile $f
2841+ }
2842+ }
28362843}
28372844
28382845image create bitmap tri-rt -background black -foreground blue -data {
@@ -3256,6 +3263,91 @@ proc external_blame {parent_idx {line {}}} {
32563263 }
32573264}
32583265
3266+ proc show_line_source {} {
3267+ global cmitmode currentid parents curview blamestuff blameinst
3268+ global diff_menu_line diff_menu_filebase flist_menu_file
3269+
3270+ if {$cmitmode eq " tree" } {
3271+ set id $currentid
3272+ set line [expr {$diff_menu_line - $diff_menu_filebase }]
3273+ } else {
3274+ set h [find_hunk_blamespec $diff_menu_filebase $diff_menu_line ]
3275+ if {$h eq {}} return
3276+ set pi [lindex $h 0]
3277+ if {$pi == 0} {
3278+ mark_ctext_line $diff_menu_line
3279+ return
3280+ }
3281+ set id [lindex $parents($curview,$currentid) [expr {$pi - 1}]]
3282+ set line [lindex $h 1]
3283+ }
3284+ if {[catch {
3285+ set f [open [list | git blame -p -L$line ,+1 $id -- $flist_menu_file ] r]
3286+ } err]} {
3287+ error_popup [mc " Couldn't start git blame: %s" $err ]
3288+ return
3289+ }
3290+ fconfigure $f -blocking 0
3291+ set i [reg_instance $f ]
3292+ set blamestuff($i ) {}
3293+ set blameinst $i
3294+ filerun $f [list read_line_source $f $i ]
3295+ }
3296+
3297+ proc stopblaming {} {
3298+ global blameinst
3299+
3300+ if {[info exists blameinst]} {
3301+ stop_instance $blameinst
3302+ unset blameinst
3303+ }
3304+ }
3305+
3306+ proc read_line_source {fd inst} {
3307+ global blamestuff curview commfd blameinst
3308+
3309+ while {[gets $fd line] >= 0} {
3310+ lappend blamestuff($inst ) $line
3311+ }
3312+ if {![eof $fd ]} {
3313+ return 1
3314+ }
3315+ unset commfd($inst )
3316+ unset blameinst
3317+ fconfigure $fd -blocking 1
3318+ if {[catch {close $fd } err]} {
3319+ error_popup [mc " Error running git blame: %s" $err ]
3320+ return 0
3321+ }
3322+
3323+ set fname {}
3324+ set line [split [lindex $blamestuff($inst) 0] " " ]
3325+ set id [lindex $line 0]
3326+ set lnum [lindex $line 1]
3327+ if {[string length $id ] == 40 && [string is xdigit $id ] &&
3328+ [string is digit -strict $lnum ]} {
3329+ # look for "filename" line
3330+ foreach l $blamestuff($inst) {
3331+ if {[string match " filename *" $l ]} {
3332+ set fname [string range $l 9 end]
3333+ break
3334+ }
3335+ }
3336+ }
3337+ if {$fname ne {}} {
3338+ # all looks good, select it
3339+ if {[commitinview $id $curview ]} {
3340+ selectline [rowofcommit $id ] 1 [list $fname $lnum ]
3341+ } else {
3342+ error_popup [mc " That line comes from commit %s, \
3343+ which is not in this view" [shortids $id ]]
3344+ }
3345+ } else {
3346+ puts " oops couldn't parse git blame output"
3347+ }
3348+ return 0
3349+ }
3350+
32593351# delete $dir when we see eof on $f (presumably because the child has exited)
32603352proc delete_at_eof {f dir} {
32613353 while {[gets $f line] >= 0} {}
@@ -5748,6 +5840,7 @@ proc stopfinding {} {
57485840 set fprogcoord 0
57495841 adjustprogress
57505842 }
5843+ stopblaming
57515844}
57525845
57535846proc findmore {} {
@@ -6152,15 +6245,15 @@ proc make_secsel {l} {
61526245 $canv3 lower $t
61536246}
61546247
6155- proc selectline {l isnew} {
6248+ proc selectline {l isnew {desired_loc {}} } {
61566249 global canv ctext commitinfo selectedline
61576250 global canvy0 linespc parents children curview
61586251 global currentid sha1entry
61596252 global commentend idtags linknum
61606253 global mergemax numcommits pending_select
61616254 global cmitmode showneartags allcommits
61626255 global targetrow targetid lastscrollrows
6163- global autoselect
6256+ global autoselect jump_to_here
61646257
61656258 catch {unset pending_select}
61666259 $canv delete hover
@@ -6299,6 +6392,7 @@ proc selectline {l isnew} {
62996392 $ctext conf -state disabled
63006393 set commentend [$ctext index " end - 1c" ]
63016394
6395+ set jump_to_here $desired_loc
63026396 init_flist [mc " Comments" ]
63036397 if {$cmitmode eq " tree" } {
63046398 gettree $id
@@ -6546,26 +6640,45 @@ proc getblobline {bf id} {
65466640 $ctext insert end " $line \n "
65476641 }
65486642 if {[eof $bf ]} {
6643+ global jump_to_here ctext_file_names commentend
6644+
65496645 # delete last newline
65506646 $ctext delete " end - 2c" " end - 1c"
65516647 close $bf
6648+ if {$jump_to_here ne {} &&
6649+ [lindex $jump_to_here 0] eq [lindex $ctext_file_names 0]} {
6650+ set lnum [expr {[lindex $jump_to_here 1] +
6651+ [lindex [split $commentend .] 0]}]
6652+ mark_ctext_line $lnum
6653+ }
65526654 return 0
65536655 }
65546656 $ctext config -state disabled
65556657 return [expr {$nl >= 1000? 2: 1}]
65566658}
65576659
6660+ proc mark_ctext_line {lnum} {
6661+ global ctext
6662+
6663+ $ctext tag delete omark
6664+ $ctext tag add omark $lnum .0 " $lnum .0 + 1 line"
6665+ $ctext tag conf omark -background " #e0e0ff"
6666+ $ctext see $lnum .0
6667+ }
6668+
65586669proc mergediff {id} {
65596670 global diffmergeid mdifffd
65606671 global diffids treediffs
65616672 global parents
65626673 global diffcontext
65636674 global diffencoding
65646675 global limitdiffs vfilelimit curview
6676+ global targetline
65656677
65666678 set diffmergeid $id
65676679 set diffids $id
65686680 set treediffs($id ) {}
6681+ set targetline {}
65696682 # this doesn't seem to actually affect anything...
65706683 set cmd [concat | git diff-tree --no-commit-id --cc -U$diffcontext $id ]
65716684 if {$limitdiffs && $vfilelimit($curview) ne {}} {
@@ -6587,7 +6700,7 @@ proc getmergediffline {mdf id np} {
65876700 global diffmergeid ctext cflist mergemax
65886701 global difffilestart mdifffd treediffs
65896702 global ctext_file_names ctext_file_lines
6590- global diffencoding
6703+ global diffencoding jump_to_here targetline diffline
65916704
65926705 $ctext conf -state normal
65936706 set nr 0
@@ -6611,9 +6724,17 @@ proc getmergediffline {mdf id np} {
66116724 set l [expr {(78 - [string length $fname ]) / 2}]
66126725 set pad [string range " ----------------------------------------" 1 $l ]
66136726 $ctext insert end " $pad $fname $pad \n " filesep
6727+ set targetline {}
6728+ if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname } {
6729+ set targetline [lindex $jump_to_here 1]
6730+ }
6731+ set diffline 0
66146732 } elseif {[regexp {^@@} $line ]} {
66156733 set line [encoding convertfrom $diffencoding $line ]
66166734 $ctext insert end " $line \n " hunksep
6735+ if {[regexp { \+(\d+),\d+ @@} $line m nl]} {
6736+ set diffline $nl
6737+ }
66176738 } elseif {[regexp {^[0-9a-f]{40}$} $line ] || [regexp {^index} $line ]} {
66186739 # do nothing
66196740 } else {
@@ -6653,6 +6774,15 @@ proc getmergediffline {mdf id np} {
66536774 lappend tags m$num
66546775 }
66556776 $ctext insert end " $line \n " $tags
6777+ if {$targetline ne {} && $minuses eq {}} {
6778+ if {$diffline == $targetline } {
6779+ set here [$ctext index " end - 1 line" ]
6780+ mark_ctext_line [lindex [split $here .] 0]
6781+ set targetline {}
6782+ } else {
6783+ incr diffline
6784+ }
6785+ }
66566786 }
66576787 }
66586788 $ctext conf -state disabled
@@ -6840,7 +6970,7 @@ proc getblobdiffs {ids} {
68406970 global diffcontext
68416971 global ignorespace
68426972 global limitdiffs vfilelimit curview
6843- global diffencoding
6973+ global diffencoding targetline
68446974
68456975 set cmd [diffcmd $ids " -p -C --no-commit-id -U$diffcontext " ]
68466976 if {$ignorespace } {
@@ -6853,6 +6983,7 @@ proc getblobdiffs {ids} {
68536983 puts " error getting diffs: $err "
68546984 return
68556985 }
6986+ set targetline {}
68566987 set diffinhdr 0
68576988 set diffencoding [get_path_encoding {}]
68586989 fconfigure $bdf -blocking 0 -encoding binary
@@ -6875,7 +7006,7 @@ proc setinlist {var i val} {
68757006
68767007proc makediffhdr {fname ids} {
68777008 global ctext curdiffstart treediffs
6878- global ctext_file_names
7009+ global ctext_file_names jump_to_here targetline diffline
68797010
68807011 set i [lsearch -exact $treediffs($ids) $fname ]
68817012 if {$i >= 0} {
@@ -6885,14 +7016,19 @@ proc makediffhdr {fname ids} {
68857016 set l [expr {(78 - [string length $fname ]) / 2}]
68867017 set pad [string range " ----------------------------------------" 1 $l ]
68877018 $ctext insert $curdiffstart " $pad $fname $pad " filesep
7019+ set targetline {}
7020+ if {$jump_to_here ne {} && [lindex $jump_to_here 0] eq $fname } {
7021+ set targetline [lindex $jump_to_here 1]
7022+ }
7023+ set diffline 0
68887024}
68897025
68907026proc getblobdiffline {bdf ids} {
68917027 global diffids blobdifffd ctext curdiffstart
68927028 global diffnexthead diffnextnote difffilestart
68937029 global ctext_file_names ctext_file_lines
68947030 global diffinhdr treediffs
6895- global diffencoding
7031+ global diffencoding jump_to_here targetline diffline
68967032
68977033 set nr 0
68987034 $ctext conf -state normal
@@ -6941,6 +7077,7 @@ proc getblobdiffline {bdf ids} {
69417077 set line [encoding convertfrom $diffencoding $line ]
69427078 $ctext insert end " $line \n " hunksep
69437079 set diffinhdr 0
7080+ set diffline $f2l
69447081
69457082 } elseif {$diffinhdr } {
69467083 if {![string compare -length 12 " rename from " $line ]} {
@@ -6974,6 +7111,7 @@ proc getblobdiffline {bdf ids} {
69747111 } else {
69757112 set line [encoding convertfrom $diffencoding $line ]
69767113 set x [string range $line 0 0]
7114+ set here [$ctext index " end - 1 chars" ]
69777115 if {$x == " -" || $x == " +" } {
69787116 set tag [expr {$x == " +" }]
69797117 $ctext insert end " $line \n " d$tag
@@ -6984,6 +7122,14 @@ proc getblobdiffline {bdf ids} {
69847122 # or something else we don't recognize
69857123 $ctext insert end " $line \n " hunksep
69867124 }
7125+ if {$targetline ne {} && ($x eq " " || $x eq " +" )} {
7126+ if {$diffline == $targetline } {
7127+ mark_ctext_line [lindex [split $here .] 0]
7128+ set targetline {}
7129+ } else {
7130+ incr diffline
7131+ }
7132+ }
69877133 }
69887134 }
69897135 $ctext conf -state disabled
0 commit comments