@@ -2249,6 +2249,7 @@ proc makewindow {} {
2249
2249
bind $cflist <ButtonRelease-1> {treeclick %W %x %y}
2250
2250
global ctxbut
2251
2251
bind $cflist $ctxbut {pop_flist_menu %W %X %Y %x %y}
2252
+ bind $ctext $ctxbut {pop_diff_menu %W %X %Y %x %y}
2252
2253
2253
2254
set maincursor [. cget -cursor]
2254
2255
set textcursor [$ctext cget -cursor]
@@ -2291,6 +2292,13 @@ proc makewindow {} {
2291
2292
{mc " Blame parent commit" command {external_blame 1}}
2292
2293
}
2293
2294
$flist_menu configure -tearoff 0
2295
+
2296
+ global diff_menu
2297
+ set diff_menu .diffctxmenu
2298
+ makemenu $diff_menu {
2299
+ {mc " Run git gui blame on this line" command {external_blame_diff}}
2300
+ }
2301
+ $diff_menu configure -tearoff 0
2294
2302
}
2295
2303
2296
2304
# Windows sends all mouse wheel events to the current focused window, not
@@ -2993,6 +3001,34 @@ proc pop_flist_menu {w X Y x y} {
2993
3001
tk_popup $flist_menu $X $Y
2994
3002
}
2995
3003
3004
+ proc find_ctext_fileinfo {line} {
3005
+ global ctext_file_names ctext_file_lines
3006
+
3007
+ set ok [bsearch $ctext_file_lines $line ]
3008
+ set tline [lindex $ctext_file_lines $ok ]
3009
+
3010
+ if {$ok >= [llength $ctext_file_lines ] || $line < $tline } {
3011
+ return {}
3012
+ } else {
3013
+ return [list [lindex $ctext_file_names $ok ] $tline ]
3014
+ }
3015
+ }
3016
+
3017
+ proc pop_diff_menu {w X Y x y} {
3018
+ global ctext diff_menu flist_menu_file
3019
+ global diff_menu_txtpos diff_menu_line
3020
+ global diff_menu_filebase
3021
+
3022
+ stopfinding
3023
+ set diff_menu_txtpos [split [$w index " @$x ,$y " ] " ." ]
3024
+ set diff_menu_line [lindex $diff_menu_txtpos 0]
3025
+ set f [find_ctext_fileinfo $diff_menu_line ]
3026
+ if {$f eq {}} return
3027
+ set flist_menu_file [lindex $f 0]
3028
+ set diff_menu_filebase [lindex $f 1]
3029
+ tk_popup $diff_menu $X $Y
3030
+ }
3031
+
2996
3032
proc flist_hl {only} {
2997
3033
global flist_menu_file findstring gdttype
2998
3034
@@ -3099,7 +3135,96 @@ proc external_diff {} {
3099
3135
}
3100
3136
}
3101
3137
3102
- proc external_blame {parent_idx} {
3138
+ proc find_hunk_blamespec {base line} {
3139
+ global ctext
3140
+
3141
+ # Find and parse the hunk header
3142
+ set s_lix [$ctext search -backwards -regexp ^@@ " $line .0 lineend" $base .0]
3143
+ if {$s_lix eq {}} return
3144
+
3145
+ set s_line [$ctext get $s_lix " $s_lix + 1 lines" ]
3146
+ if {![regexp {^@@@*(( -\d+(,\d+)?)+) \+(\d+)(,\d+)? @@} $s_line \
3147
+ s_line old_specs osz osz1 new_line nsz]} {
3148
+ return
3149
+ }
3150
+
3151
+ # base lines for the parents
3152
+ set base_lines [list $new_line ]
3153
+ foreach old_spec [lrange [split $old_specs " " ] 1 end] {
3154
+ if {![regexp -- {-(\d+)(,\d+)?} $old_spec \
3155
+ old_spec old_line osz]} {
3156
+ return
3157
+ }
3158
+ lappend base_lines $old_line
3159
+ }
3160
+
3161
+ # Now scan the lines to determine offset within the hunk
3162
+ set parent {}
3163
+ set max_parent [expr {[llength $base_lines ]-2}]
3164
+ set dline 0
3165
+ set s_lno [lindex [split $s_lix " ." ] 0]
3166
+
3167
+ for {set i $line } {$i > $s_lno } {incr i -1} {
3168
+ set c_line [$ctext get $i .0 " $i .0 + 1 lines" ]
3169
+ # Determine if the line is removed
3170
+ set chunk [string range $c_line 0 $max_parent ]
3171
+ set removed_idx [string first " -" $chunk ]
3172
+ # Choose a parent index
3173
+ if {$parent eq {}} {
3174
+ if {$removed_idx >= 0} {
3175
+ set parent $removed_idx
3176
+ } else {
3177
+ set unchanged_idx [string first " " $chunk ]
3178
+ if {$unchanged_idx >= 0} {
3179
+ set parent $unchanged_idx
3180
+ } else {
3181
+ # blame the current commit
3182
+ set parent -1
3183
+ }
3184
+ }
3185
+ }
3186
+ # then count other lines that belong to it
3187
+ if {$parent >= 0} {
3188
+ set code [string index $c_line $parent ]
3189
+ if {$code eq " -" || ($removed_idx < 0 && $code ne " +" )} {
3190
+ incr dline
3191
+ }
3192
+ } else {
3193
+ if {$removed_idx < 0} {
3194
+ incr dline
3195
+ }
3196
+ }
3197
+ }
3198
+
3199
+ if {$parent eq {}} { set parent -1 }
3200
+ incr parent
3201
+ incr dline [lindex $base_lines $parent ]
3202
+ return [list $parent $dline ]
3203
+ }
3204
+
3205
+ proc external_blame_diff {} {
3206
+ global currentid diffmergeid cmitmode
3207
+ global diff_menu_txtpos diff_menu_line
3208
+ global diff_menu_filebase flist_menu_file
3209
+
3210
+ if {$cmitmode eq " tree" } {
3211
+ set parent_idx 0
3212
+ set line [expr {$diff_menu_line - $diff_menu_filebase - 1}]
3213
+ } else {
3214
+ set hinfo [find_hunk_blamespec $diff_menu_filebase $diff_menu_line ]
3215
+ if {$hinfo ne {}} {
3216
+ set parent_idx [lindex $hinfo 0]
3217
+ set line [lindex $hinfo 1]
3218
+ } else {
3219
+ set parent_idx 0
3220
+ set line 0
3221
+ }
3222
+ }
3223
+
3224
+ external_blame $parent_idx $line
3225
+ }
3226
+
3227
+ proc external_blame {parent_idx {line {}}} {
3103
3228
global flist_menu_file
3104
3229
global nullid nullid2
3105
3230
global parentlist selectedline currentid
@@ -3115,7 +3240,12 @@ proc external_blame {parent_idx} {
3115
3240
return
3116
3241
}
3117
3242
3118
- if {[catch {exec git gui blame $base_commit $flist_menu_file &} err]} {
3243
+ set cmdline [list git gui blame]
3244
+ if {$line ne {} && $line > 1} {
3245
+ lappend cmdline " --line=$line "
3246
+ }
3247
+ lappend cmdline $base_commit $flist_menu_file
3248
+ if {[catch {eval exec $cmdline &} err]} {
3119
3249
error_popup " [ mc " git gui blame: command failed:" ] $err "
3120
3250
}
3121
3251
}
@@ -6364,6 +6494,7 @@ proc gettreeline {gtf id} {
6364
6494
6365
6495
proc showfile {f} {
6366
6496
global treefilelist treeidlist diffids nullid nullid2
6497
+ global ctext_file_names ctext_file_lines
6367
6498
global ctext commentend
6368
6499
6369
6500
set i [lsearch -exact $treefilelist($diffids) $f ]
@@ -6387,6 +6518,8 @@ proc showfile {f} {
6387
6518
filerun $bf [list getblobline $bf $diffids ]
6388
6519
$ctext config -state normal
6389
6520
clear_ctext $commentend
6521
+ lappend ctext_file_names $f
6522
+ lappend ctext_file_lines [lindex [split $commentend " ." ] 0]
6390
6523
$ctext insert end " \n "
6391
6524
$ctext insert end " $f \n " filesep
6392
6525
$ctext config -state disabled
@@ -6447,6 +6580,7 @@ proc mergediff {id} {
6447
6580
proc getmergediffline {mdf id np} {
6448
6581
global diffmergeid ctext cflist mergemax
6449
6582
global difffilestart mdifffd treediffs
6583
+ global ctext_file_names ctext_file_lines
6450
6584
global diffencoding
6451
6585
6452
6586
$ctext conf -state normal
@@ -6465,6 +6599,8 @@ proc getmergediffline {mdf id np} {
6465
6599
lappend difffilestart $here
6466
6600
lappend treediffs($id ) $fname
6467
6601
add_flist [list $fname ]
6602
+ lappend ctext_file_names $fname
6603
+ lappend ctext_file_lines [lindex [split $here " ." ] 0]
6468
6604
set diffencoding [get_path_encoding $fname ]
6469
6605
set l [expr {(78 - [string length $fname ]) / 2}]
6470
6606
set pad [string range " ----------------------------------------" 1 $l ]
@@ -6733,11 +6869,13 @@ proc setinlist {var i val} {
6733
6869
6734
6870
proc makediffhdr {fname ids} {
6735
6871
global ctext curdiffstart treediffs
6872
+ global ctext_file_names
6736
6873
6737
6874
set i [lsearch -exact $treediffs($ids) $fname ]
6738
6875
if {$i >= 0} {
6739
6876
setinlist difffilestart $i $curdiffstart
6740
6877
}
6878
+ set ctext_file_names [lreplace $ctext_file_names end end $fname ]
6741
6879
set l [expr {(78 - [string length $fname ]) / 2}]
6742
6880
set pad [string range " ----------------------------------------" 1 $l ]
6743
6881
$ctext insert $curdiffstart " $pad $fname $pad " filesep
@@ -6746,6 +6884,7 @@ proc makediffhdr {fname ids} {
6746
6884
proc getblobdiffline {bdf ids} {
6747
6885
global diffids blobdifffd ctext curdiffstart
6748
6886
global diffnexthead diffnextnote difffilestart
6887
+ global ctext_file_names ctext_file_lines
6749
6888
global diffinhdr treediffs
6750
6889
global diffencoding
6751
6890
@@ -6763,6 +6902,8 @@ proc getblobdiffline {bdf ids} {
6763
6902
# start of a new file
6764
6903
$ctext insert end " \n "
6765
6904
set curdiffstart [$ctext index " end - 1c" ]
6905
+ lappend ctext_file_names " "
6906
+ lappend ctext_file_lines [lindex [split $curdiffstart " ." ] 0]
6766
6907
$ctext insert end " \n " filesep
6767
6908
# If the name hasn't changed the length will be odd,
6768
6909
# the middle char will be a space, and the two bits either
@@ -6899,6 +7040,7 @@ proc nextfile {} {
6899
7040
6900
7041
proc clear_ctext {{first 1.0}} {
6901
7042
global ctext smarktop smarkbot
7043
+ global ctext_file_names ctext_file_lines
6902
7044
global pendinglinks
6903
7045
6904
7046
set l [lindex [split $first .] 0]
@@ -6912,6 +7054,8 @@ proc clear_ctext {{first 1.0}} {
6912
7054
if {$first eq " 1.0" } {
6913
7055
catch {unset pendinglinks}
6914
7056
}
7057
+ set ctext_file_names {}
7058
+ set ctext_file_lines {}
6915
7059
}
6916
7060
6917
7061
proc settabs {{firstab {}}} {
0 commit comments