Skip to content

Commit 172c92b

Browse files
committed
git-gui: Run blame twice on the same file and display both outputs
We now perform two passes over any input file given to the blame viewer. Our first pass is a quick "git-blame" with no options, getting the details of how each line arrived into this file. We are specifically ignoring/omitting the rename detection logic as this first pass is to determine why things got into the state they are in. Once the first pass is complete and is displayed in the UI we run a second pass, using the much more CPU intensive "-M -C -C" options to perform extensive rename/movement detection. The output of this second pass is shown in a different column, allowing the user to see for any given line how it got to be, and if it came from somewhere else, where that is. This is actually very instructive when run on our own lib/branch.tcl script. That file grew recently out of a very large block of code in git-gui.sh. The first pass shows when I created that file, while the second pass shows the original commit information. Signed-off-by: Shawn O. Pearce <[email protected]>
1 parent debcd0f commit 172c92b

File tree

1 file changed

+113
-63
lines changed

1 file changed

+113
-63
lines changed

lib/blame.tcl

Lines changed: 113 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ field w_path ; # label showing the current file path
1818
field w_columns ; # list of all column widgets in the viewer
1919
field w_line ; # text column: all line numbers
2020
field w_amov ; # text column: annotations + move tracking
21+
field w_asim ; # text column: annotations (simple computation)
2122
field w_file ; # text column: actual file data
2223
field w_cviewer ; # pane showing commit message
2324
field status ; # text variable bound to status bar
@@ -39,13 +40,15 @@ field path ; # input filename to view in $commit
3940

4041
field current_fd {} ; # background process running
4142
field highlight_line -1 ; # current line selected
43+
field highlight_column {} ; # current commit column selected
4244
field highlight_commit {} ; # sha1 of commit selected
4345
field old_bgcolor {} ; # background of current selection
4446

4547
field total_lines 0 ; # total length of file
4648
field blame_lines 0 ; # number of lines computed
4749
field have_commit ; # array commit -> 1
4850
field amov_data ; # list of {commit origfile origline}
51+
field asim_data ; # list of {commit origfile origline}
4952

5053
field r_commit ; # commit currently being parsed
5154
field r_orig_line ; # original line number
@@ -142,15 +145,32 @@ constructor new {i_commit i_path} {
142145
-state disabled \
143146
-wrap none \
144147
-height 40 \
145-
-width 4 \
148+
-width 5 \
146149
-font font_diff
150+
$w_amov tag conf author_abbr -justify right -rmargin 5
147151
$w_amov tag conf curr_commit
148-
$w_amov tag conf prior_commit \
149-
-foreground blue \
150-
-underline 1
152+
$w_amov tag conf prior_commit -foreground blue -underline 1
151153
$w_amov tag bind prior_commit \
152154
<Button-1> \
153-
"[cb _load_commit @%x,%y];break"
155+
"[cb _load_commit $w_amov @amov_data @%x,%y];break"
156+
157+
set w_asim $w.file_pane.out.asimple_t
158+
text $w_asim \
159+
-takefocus 0 \
160+
-highlightthickness 0 \
161+
-padx 0 -pady 0 \
162+
-background white -borderwidth 0 \
163+
-state disabled \
164+
-wrap none \
165+
-height 40 \
166+
-width 4 \
167+
-font font_diff
168+
$w_asim tag conf author_abbr -justify right
169+
$w_asim tag conf curr_commit
170+
$w_asim tag conf prior_commit -foreground blue -underline 1
171+
$w_asim tag bind prior_commit \
172+
<Button-1> \
173+
"[cb _load_commit $w_asim @asim_data @%x,%y];break"
154174

155175
set w_file $w.file_pane.out.file_t
156176
text $w_file \
@@ -165,7 +185,7 @@ constructor new {i_commit i_path} {
165185
-xscrollcommand [list $w.file_pane.out.sbx set] \
166186
-font font_diff
167187

168-
set w_columns [list $w_amov $w_line $w_file]
188+
set w_columns [list $w_amov $w_asim $w_line $w_file]
169189

170190
scrollbar $w.file_pane.out.sbx \
171191
-orient h \
@@ -312,9 +332,9 @@ method _load {} {
312332
}
313333

314334
set highlight_line -1
335+
set highlight_column {}
315336
set highlight_commit {}
316337
set total_lines 0
317-
set blame_lines 0
318338
array unset have_commit
319339
}
320340

@@ -343,6 +363,7 @@ method _load {} {
343363
# git-blame output and with Tk's text widget.
344364
#
345365
set amov_data [list [list]]
366+
set asim_data [list [list]]
346367

347368
set status "Loading $commit:[escape_path $path]..."
348369
$w_path conf -text [escape_path $path]
@@ -410,6 +431,7 @@ method _read_file {fd} {
410431
regsub "\r\$" $line {} line
411432
incr total_lines
412433
lappend amov_data {}
434+
lappend asim_data {}
413435

414436
if {$total_lines > 1} {
415437
foreach i $w_columns {$i insert end "\n"}
@@ -428,29 +450,37 @@ method _read_file {fd} {
428450

429451
if {[eof $fd]} {
430452
close $fd
431-
432-
_status $this
433-
set cmd {nice git blame -M -C --incremental}
434-
if {$commit eq {}} {
435-
lappend cmd --contents $path
436-
} else {
437-
lappend cmd $commit
438-
}
439-
lappend cmd -- $path
440-
set fd [open "| $cmd" r]
441-
fconfigure $fd -blocking 0 -translation lf -encoding binary
442-
fileevent $fd readable [cb _read_blame $fd]
443-
set current_fd $fd
453+
_exec_blame $this $w_asim @asim_data [list] {}
444454
}
445455
} ifdeleted { catch {close $fd} }
446456

447-
method _read_blame {fd} {
457+
method _exec_blame {cur_w cur_d options cur_s} {
458+
set cmd [list nice git blame]
459+
set cmd [concat $cmd $options]
460+
lappend cmd --incremental
461+
if {$commit eq {}} {
462+
lappend cmd --contents $path
463+
} else {
464+
lappend cmd $commit
465+
}
466+
lappend cmd -- $path
467+
set fd [open "| $cmd" r]
468+
fconfigure $fd -blocking 0 -translation lf -encoding binary
469+
fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d $cur_s]
470+
set current_fd $fd
471+
set blame_lines 0
472+
_status $this $cur_s
473+
}
474+
475+
method _read_blame {fd cur_w cur_d cur_s} {
476+
upvar #0 $cur_d line_data
477+
448478
if {$fd ne $current_fd} {
449479
catch {close $fd}
450480
return
451481
}
452482

453-
$w_amov conf -state normal
483+
$cur_w conf -state normal
454484
while {[gets $fd line] >= 0} {
455485
if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \
456486
cmit original_line final_line line_count]} {
@@ -482,7 +512,7 @@ method _read_blame {fd} {
482512
set commit_type curr_commit
483513
} else {
484514
set commit_type prior_commit
485-
set commit_abbr [string range $cmit 0 4]
515+
set commit_abbr [string range $cmit 0 3]
486516
}
487517

488518
set author_abbr {}
@@ -500,51 +530,50 @@ method _read_blame {fd} {
500530
set author_abbr { |}
501531
} else {
502532
set author_abbr [string range $author_abbr 0 3]
503-
while {[string length $author_abbr] < 4} {
504-
set author_abbr " $author_abbr"
505-
}
506533
}
507534
unset a_name
508535

509536
set first_lno $lno
510537
while {
511538
$first_lno > 1
512-
&& $cmit eq [lindex $amov_data [expr {$first_lno - 1}] 0]
513-
&& $file eq [lindex $amov_data [expr {$first_lno - 1}] 1]
539+
&& $cmit eq [lindex $line_data [expr {$first_lno - 1}] 0]
540+
&& $file eq [lindex $line_data [expr {$first_lno - 1}] 1]
514541
} {
515542
incr first_lno -1
516543
}
517544

518545
while {$n > 0} {
519546
set lno_e "$lno.0 lineend + 1c"
520-
if {[lindex $amov_data $lno] ne {}} {
521-
set g [lindex $amov_data $lno 0]
547+
if {[lindex $line_data $lno] ne {}} {
548+
set g [lindex $line_data $lno 0]
522549
foreach i $w_columns {
523550
$i tag remove g$g $lno.0 $lno_e
524551
}
525552
}
526-
lset amov_data $lno [list $cmit $file]
553+
lset line_data $lno [list $cmit $file]
527554

528-
$w_amov delete $lno.0 "$lno.0 lineend"
555+
$cur_w delete $lno.0 "$lno.0 lineend"
529556
if {$lno == $first_lno} {
530-
$w_amov insert $lno.0 $commit_abbr $commit_type
557+
$cur_w insert $lno.0 $commit_abbr $commit_type
531558
} elseif {$lno == [expr {$first_lno + 1}]} {
532-
$w_amov insert $lno.0 $author_abbr
559+
$cur_w insert $lno.0 $author_abbr author_abbr
533560
} else {
534-
$w_amov insert $lno.0 { |}
561+
$cur_w insert $lno.0 { |}
535562
}
536563

537564
foreach i $w_columns {
538565
$i tag add g$cmit $lno.0 $lno_e
539566
}
540567

541-
if {$highlight_line == -1} {
542-
if {[lindex [$w_file yview] 0] == 0} {
568+
if {$highlight_column eq $cur_w} {
569+
if {$highlight_line == -1
570+
&& [lindex [$w_file yview] 0] == 0} {
543571
$w_file see $lno.0
544-
_showcommit $this $lno
572+
set highlight_line $lno
573+
}
574+
if {$highlight_line == $lno} {
575+
_showcommit $this $cur_w $lno
545576
}
546-
} elseif {$highlight_line == $lno} {
547-
_showcommit $this $lno
548577
}
549578

550579
incr n -1
@@ -553,17 +582,17 @@ method _read_blame {fd} {
553582
}
554583

555584
while {
556-
$cmit eq [lindex $amov_data $lno 0]
557-
&& $file eq [lindex $amov_data $lno 1]
585+
$cmit eq [lindex $line_data $lno 0]
586+
&& $file eq [lindex $line_data $lno 1]
558587
} {
559-
$w_amov delete $lno.0 "$lno.0 lineend"
588+
$cur_w delete $lno.0 "$lno.0 lineend"
560589

561590
if {$lno == $first_lno} {
562-
$w_amov insert $lno.0 $commit_abbr $commit_type
591+
$cur_w insert $lno.0 $commit_abbr $commit_type
563592
} elseif {$lno == [expr {$first_lno + 1}]} {
564-
$w_amov insert $lno.0 $author_abbr
593+
$cur_w insert $lno.0 $author_abbr author_abbr
565594
} else {
566-
$w_amov insert $lno.0 { |}
595+
$cur_w insert $lno.0 { |}
567596
}
568597
incr lno
569598
}
@@ -572,47 +601,53 @@ method _read_blame {fd} {
572601
set header($r_commit,$key) $data
573602
}
574603
}
575-
$w_amov conf -state disabled
604+
$cur_w conf -state disabled
576605

577606
if {[eof $fd]} {
578607
close $fd
579-
set current_fd {}
580-
set status {Annotation complete.}
581-
destroy $w.status.c
608+
if {$cur_w eq $w_asim} {
609+
_exec_blame $this $w_amov @amov_data \
610+
[list -M -C -C] \
611+
{ move/copy tracking}
612+
} else {
613+
set current_fd {}
614+
set status {Annotation complete.}
615+
destroy $w.status.c
616+
}
582617
} else {
583-
_status $this
618+
_status $this $cur_s
584619
}
585620
} ifdeleted { catch {close $fd} }
586621

587-
method _status {} {
622+
method _status {cur_s} {
588623
set have $blame_lines
589624
set total $total_lines
590625
set pdone 0
591626
if {$total} {set pdone [expr {100 * $have / $total}]}
592627

593628
set status [format \
594-
"Loading annotations... %i of %i lines annotated (%2i%%)" \
595-
$have $total $pdone]
629+
"Loading%s annotations... %i of %i lines annotated (%2i%%)" \
630+
$cur_s $have $total $pdone]
596631
$w.status.c coords bar 0 0 $pdone 20
597632
}
598633

599634
method _click {cur_w pos} {
600635
set lno [lindex [split [$cur_w index $pos] .] 0]
601-
if {$lno eq {}} return
602-
_showcommit $this $lno
636+
_showcommit $this $cur_w $lno
603637
}
604638

605-
method _load_commit {pos} {
606-
set lno [lindex [split [$w_amov index $pos] .] 0]
607-
set dat [lindex $amov_data $lno]
639+
method _load_commit {cur_w cur_d pos} {
640+
upvar #0 $cur_d line_data
641+
set lno [lindex [split [$cur_w index $pos] .] 0]
642+
set dat [lindex $line_data $lno]
608643
if {$dat ne {}} {
609644
set commit [lindex $dat 0]
610645
set path [lindex $dat 1]
611646
_load $this
612647
}
613648
}
614649

615-
method _showcommit {lno} {
650+
method _showcommit {cur_w lno} {
616651
global repo_config
617652

618653
if {$highlight_commit ne {}} {
@@ -621,10 +656,17 @@ method _showcommit {lno} {
621656
}
622657
}
623658

659+
if {$cur_w eq $w_amov} {
660+
set dat [lindex $amov_data $lno]
661+
set highlight_column $w_amov
662+
} else {
663+
set dat [lindex $asim_data $lno]
664+
set highlight_column $w_asim
665+
}
666+
624667
$w_cviewer conf -state normal
625668
$w_cviewer delete 0.0 end
626669

627-
set dat [lindex $amov_data $lno]
628670
if {$dat eq {}} {
629671
set cmit {}
630672
$w_cviewer insert end "Loading annotation..." still_loading
@@ -724,7 +766,11 @@ method _copycommit {} {
724766

725767
method _show_tooltip {cur_w pos} {
726768
set lno [lindex [split [$cur_w index $pos] .] 0]
727-
set dat [lindex $amov_data $lno]
769+
if {$cur_w eq $w_amov} {
770+
set dat [lindex $amov_data $lno]
771+
} else {
772+
set dat [lindex $asim_data $lno]
773+
}
728774
if {$dat eq {}} {
729775
_hide_tooltip $this
730776
return
@@ -758,7 +804,11 @@ method _open_tooltip {cur_w} {
758804
[expr {$pos_x - [winfo rootx $cur_w]}] \
759805
[expr {$pos_y - [winfo rooty $cur_w]}]] ,]
760806
set lno [lindex [split [$cur_w index $pos] .] 0]
761-
set dat [lindex $amov_data $lno]
807+
if {$cur_w eq $w_amov} {
808+
set dat [lindex $amov_data $lno]
809+
} else {
810+
set dat [lindex $asim_data $lno]
811+
}
762812
set cmit [lindex $dat 0]
763813
set file [lindex $dat 1]
764814

0 commit comments

Comments
 (0)