From 905d9c9653a7dc324a1c6fbf883a1b9bcdc6e5bf Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 30 May 2007 11:27:49 -0400 Subject: [PATCH 01/46] git-gui: Allow creating a branch when none exists If the user has no branches at all (their refs/heads/ is empty) and they are on a detached HEAD we have a valid repository but there are no branches to populate into the branch pulldown in the create branch dialog. Instead of erroring out we can skip that part of the dialog, much like we do with tracking branches or tags when the user doesn't have any. Signed-off-by: Shawn O. Pearce --- lib/branch.tcl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/branch.tcl b/lib/branch.tcl index caaee5cf17..4f648b2bc7 100644 --- a/lib/branch.tcl +++ b/lib/branch.tcl @@ -201,12 +201,14 @@ proc do_create_branch {} { pack $w.desc -anchor nw -fill x -pady 5 -padx 5 labelframe $w.from -text {Starting Revision} - radiobutton $w.from.head_r \ - -text {Local Branch:} \ - -value head \ - -variable create_branch_revtype - eval tk_optionMenu $w.from.head_m create_branch_head $all_heads - grid $w.from.head_r $w.from.head_m -sticky w + if {$all_heads ne {}} { + radiobutton $w.from.head_r \ + -text {Local Branch:} \ + -value head \ + -variable create_branch_revtype + eval tk_optionMenu $w.from.head_m create_branch_head $all_heads + grid $w.from.head_r $w.from.head_m -sticky w + } set all_trackings [all_tracking_branches] if {$all_trackings ne {}} { set create_branch_trackinghead [lindex $all_trackings 0] From b8848f7753762ff8c4e34b3c15e788c5f7e6781f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 31 May 2007 23:32:54 -0400 Subject: [PATCH 02/46] git-gui: Allow as few as 0 lines of diff context Johannes Sixt pointed out that dropping to 0 lines of context does allow the user to get more fine-grained hunk selection, especially since we don't currently support "highlight and apply (or revert)". Signed-off-by: Shawn O. Pearce --- git-gui.sh | 6 +++--- lib/diff.tcl | 2 +- lib/option.tcl | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index dba585111c..d6472636c3 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2038,17 +2038,17 @@ lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add separator $ctxm add command \ -label {Show Less Context} \ - -command {if {$repo_config(gui.diffcontext) >= 2} { + -command {if {$repo_config(gui.diffcontext) >= 1} { incr repo_config(gui.diffcontext) -1 reshow_diff }} lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add command \ -label {Show More Context} \ - -command { + -command {if {$repo_config(gui.diffcontext) < 99} { incr repo_config(gui.diffcontext) reshow_diff - } + }} lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add separator $ctxm add command -label {Options...} \ diff --git a/lib/diff.tcl b/lib/diff.tcl index 7e715a6865..29436b50cb 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -145,7 +145,7 @@ proc show_diff {path w {lno {}}} { lappend cmd -p lappend cmd --no-color - if {$repo_config(gui.diffcontext) > 0} { + if {$repo_config(gui.diffcontext) >= 0} { lappend cmd "-U$repo_config(gui.diffcontext)" } if {$w eq $ui_index} { diff --git a/lib/option.tcl b/lib/option.tcl index 17fcc65f78..11dd9be6b9 100644 --- a/lib/option.tcl +++ b/lib/option.tcl @@ -173,7 +173,7 @@ proc do_options {} { {i-1..5 merge.verbosity {Merge Verbosity}} {b gui.trustmtime {Trust File Modification Timestamps}} - {i-1..99 gui.diffcontext {Number of Diff Context Lines}} + {i-0..99 gui.diffcontext {Number of Diff Context Lines}} {t gui.newbranchtemplate {New Branch Name Template}} } { set type [lindex $option 0] From c289f6fa1f8642a5caf728ef8ff87afd5718cd99 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Sat, 2 Jun 2007 01:09:56 +0200 Subject: [PATCH 03/46] Make the installation target of git-gui a little less chatty Signed-off-by: Alex Riesen Signed-off-by: Shawn O. Pearce --- Makefile | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 3de0de1a23..404bff0ad9 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,12 @@ all:: # Define V=1 to have a more verbose compile. # +QUIET = +QUIET_MSG = : +ifndef V + QUIET = @ + QUIET_MSG = echo ' ' +endif GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -109,12 +115,14 @@ GIT-GUI-VARS: .FORCE-GIT-GUI-VARS all:: $(ALL_PROGRAMS) lib/tclIndex install: all - $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) - $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)' - $(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)' - $(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;) + $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(QUIET_MSG)INSTALL git-gui; $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(QUIET)$(foreach p,$(GITGUI_BUILT_INS),$(QUIET_MSG)INSTALL $p;\ + rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && \ + ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) + $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)' + $(QUIET)$(foreach p,lib/tclIndex $(ALL_LIBFILES), $(QUIET_MSG)INSTALL $p;\ + $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;) dist-version: @mkdir -p $(TARDIR) From 160e82284eda034fea84dcc946f9c1965176f25f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 18:20:30 -0400 Subject: [PATCH 04/46] git-gui: Don't quit when we destroy a child widget Its wrong to exit the application if we destroy a random widget contained withing something else; especially if its some small trivial thing that has no impact on the overall operation. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index d6472636c3..a8185a3014 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1600,7 +1600,7 @@ unset browser doc_path doc_url # -- Standard bindings # -bind . do_quit +bind . {if {{%W} eq {.}} do_quit} bind all <$M1B-Key-q> do_quit bind all <$M1B-Key-Q> do_quit bind all <$M1B-Key-w> {destroy [winfo toplevel %W]} From 6309172ea56294d08674cf35df92d6a3fa695480 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 17:18:46 -0400 Subject: [PATCH 05/46] git-gui: Attach font_ui to all spinbox widgets Earlier I missed making sure our spinbox widgets used the same font as the other widgets around them. This meant that using a main font with a size of 20 would make every widget in the options dialog huge, but the spinboxes would be left with whatever the OS native font is. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index a8185a3014..daee5601b1 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1205,7 +1205,7 @@ font create font_diffbold foreach class {Button Checkbutton Entry Label Labelframe Listbox Menu Message - Radiobutton Text} { + Radiobutton Spinbox Text} { option add *$class.font font_ui } unset class From cfb07cca7d9a517fae1bdc741c41c06d150a852f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 16:11:26 -0400 Subject: [PATCH 06/46] git-gui: Verify Tcl/Tk is new enough for our needs For quite a while we have been assuming the user is running on a Tcl/Tk 8.4 or later platform. This may not be the case on some very old systems. Unfortunately I am pretty far down the path of using the Tcl/Tk 8.4 commands and options and cannot easily work around them to support earlier versions of Tcl/Tk. So we'll check that we are using the correct version up front, and if not we'll stop with a related error message. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/git-gui.sh b/git-gui.sh index daee5601b1..cc1625bfac 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -20,6 +20,22 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA} +###################################################################### +## +## Tcl/Tk sanity check + +if {[catch {package require Tcl 8.4} err] + || [catch {package require Tk 8.4} err] +} { + catch {wm withdraw .} + tk_messageBox \ + -icon error \ + -type ok \ + -title "git-gui: fatal error" \ + -message $err + exit 1 +} + ###################################################################### ## ## configure our library From cb8773d16c8619901f46a96ecfc5c2b11c2e82a2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 20:09:00 -0400 Subject: [PATCH 07/46] Revert "Make the installation target of git-gui a little less chatty" This reverts commit c289f6fa1f8642a5caf728ef8ff87afd5718cd99. Junio pointed out that Alex's change breaks in some cases, like when V=1, and is more verbose than it should be even if that worked. I'm backing it out and redoing it. Signed-off-by: Shawn O. Pearce --- Makefile | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/Makefile b/Makefile index 404bff0ad9..3de0de1a23 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,6 @@ all:: # Define V=1 to have a more verbose compile. # -QUIET = -QUIET_MSG = : -ifndef V - QUIET = @ - QUIET_MSG = echo ' ' -endif GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@ -115,14 +109,12 @@ GIT-GUI-VARS: .FORCE-GIT-GUI-VARS all:: $(ALL_PROGRAMS) lib/tclIndex install: all - $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(QUIET)$(QUIET_MSG)INSTALL git-gui; $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' - $(QUIET)$(foreach p,$(GITGUI_BUILT_INS),$(QUIET_MSG)INSTALL $p;\ - rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && \ - ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) - $(QUIET)$(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)' - $(QUIET)$(foreach p,lib/tclIndex $(ALL_LIBFILES), $(QUIET_MSG)INSTALL $p;\ - $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;) + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(INSTALL) git-gui '$(DESTDIR_SQ)$(gitexecdir_SQ)' + $(foreach p,$(GITGUI_BUILT_INS), rm -f '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' && ln '$(DESTDIR_SQ)$(gitexecdir_SQ)/git-gui' '$(DESTDIR_SQ)$(gitexecdir_SQ)/$p' ;) + $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(libdir_SQ)' + $(INSTALL) -m644 lib/tclIndex '$(DESTDIR_SQ)$(libdir_SQ)' + $(foreach p,$(ALL_LIBFILES), $(INSTALL) -m644 $p '$(DESTDIR_SQ)$(libdir_SQ)' ;) dist-version: @mkdir -p $(TARDIR) From 9adccb057e2654f259bd98c04012e97a30322c1b Mon Sep 17 00:00:00 2001 From: Matthijs Melchior Date: Tue, 5 Jun 2007 23:50:02 +0200 Subject: [PATCH 08/46] New selection indication and softer colors The default font was already bold, so marking the selected file with bold font did not work. Change that to lightgray background. Also, the header colors are now softer, giving better readability. Signed-off-by: Matthijs Melchior Signed-off-by: Shawn O. Pearce --- git-gui.sh | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index cc1625bfac..6a5e2dc160 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1731,7 +1731,7 @@ pack .vpane -anchor n -side top -fill both -expand 1 # frame .vpane.files.index -height 100 -width 200 label .vpane.files.index.title -text {Staged Changes (Will Be Committed)} \ - -background green + -background lightgreen text $ui_index -background white -borderwidth 0 \ -width 20 -height 10 \ -wrap none \ @@ -1751,7 +1751,7 @@ pack $ui_index -side left -fill both -expand 1 # frame .vpane.files.workdir -height 100 -width 200 label .vpane.files.workdir.title -text {Unstaged Changes (Will Not Be Committed)} \ - -background red + -background lightsalmon text $ui_workdir -background white -borderwidth 0 \ -width 20 -height 10 \ -wrap none \ @@ -1768,10 +1768,8 @@ pack $ui_workdir -side left -fill both -expand 1 .vpane.files add .vpane.files.workdir -sticky nsew foreach i [list $ui_index $ui_workdir] { - $i tag conf in_diff -font font_uibold - $i tag conf in_sel \ - -background [$i cget -foreground] \ - -foreground [$i cget -background] + $i tag conf in_diff -background lightgray + $i tag conf in_sel -background lightgray } unset i @@ -1929,18 +1927,18 @@ proc trace_current_diff_path {varname args} { } trace add variable current_diff_path write trace_current_diff_path -frame .vpane.lower.diff.header -background orange +frame .vpane.lower.diff.header -background gold label .vpane.lower.diff.header.status \ - -background orange \ + -background gold \ -width $max_status_desc \ -anchor w \ -justify left label .vpane.lower.diff.header.file \ - -background orange \ + -background gold \ -anchor w \ -justify left label .vpane.lower.diff.header.path \ - -background orange \ + -background gold \ -anchor w \ -justify left pack .vpane.lower.diff.header.status -side left From a46fe1c1c0007fbbe0c196e7cc0db89567a8eae0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Thu, 31 May 2007 23:58:55 -0400 Subject: [PATCH 09/46] git-gui: Add a 4 digit commit abbreviation to the blame viewer We now show the first 4 digits of each commit in the left most column of our blame viewer, before the line numbers. These are drawn as the data becomes available from git-blame --incremental, and helps the user to visually group lines together. I'm using only the first 4 digits because within a given cluster of lines its unlikely that two neighboring commits will have the same 4 digit prefix. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 8b032d9590..155bbe37f0 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -8,6 +8,7 @@ field path ; # input filename to view in $commit field w field w_line +field w_cgrp field w_load field w_file field w_cmit @@ -65,6 +66,14 @@ constructor new {i_commit i_path} { -font font_diff $w.out.linenumber_t tag conf linenumber -justify right + text $w.out.commit_t \ + -background white -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 4 \ + -font font_diff + text $w.out.file_t \ -background white -borderwidth 0 \ -state disabled \ @@ -79,16 +88,18 @@ constructor new {i_commit i_path} { -command [list scrollbar2many [list \ $w.out.loaded_t \ $w.out.linenumber_t \ + $w.out.commit_t \ $w.out.file_t \ ] yview] grid \ + $w.out.commit_t \ $w.out.linenumber_t \ $w.out.loaded_t \ $w.out.file_t \ $w.out.sby \ -sticky nsew - grid conf $w.out.sbx -column 2 -sticky we - grid columnconfigure $w.out 2 -weight 1 + grid conf $w.out.sbx -column 3 -sticky we + grid columnconfigure $w.out 3 -weight 1 grid rowconfigure $w.out 0 -weight 1 pack $w.out -fill both -expand 1 @@ -123,11 +134,13 @@ constructor new {i_commit i_path} { -command [cb _copycommit] set w_line $w.out.linenumber_t + set w_cgrp $w.out.commit_t set w_load $w.out.loaded_t set w_file $w.out.file_t set w_cmit $w.cm.t foreach i [list \ + $w.out.commit_t \ $w.out.loaded_t \ $w.out.linenumber_t \ $w.out.file_t] { @@ -136,6 +149,7 @@ constructor new {i_commit i_path} { -foreground [$i cget -background] $i conf -yscrollcommand \ [list many2scrollbar [list \ + $w.out.commit_t \ $w.out.loaded_t \ $w.out.linenumber_t \ $w.out.file_t \ @@ -150,6 +164,7 @@ constructor new {i_commit i_path} { } foreach i [list \ + $w.out.commit_t \ $w.out.loaded_t \ $w.out.linenumber_t \ $w.out.file_t \ @@ -182,16 +197,20 @@ constructor new {i_commit i_path} { method _read_file {fd} { $w_load conf -state normal + $w_cgrp conf -state normal $w_line conf -state normal $w_file conf -state normal while {[gets $fd line] >= 0} { regsub "\r\$" $line {} line incr total_lines + $w_load insert end "\n" + $w_cgrp insert end "\n" $w_line insert end "$total_lines\n" linenumber $w_file insert end "$line\n" } $w_load conf -state disabled + $w_cgrp conf -state disabled $w_line conf -state disabled $w_file conf -state disabled @@ -212,6 +231,7 @@ method _read_file {fd} { } ifdeleted { catch {close $fd} } method _read_blame {fd} { + $w_cgrp conf -state normal while {[gets $fd line] >= 0} { if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ cmit original_line final_line line_count]} { @@ -221,10 +241,14 @@ method _read_blame {fd} { set r_line_count $line_count if {[catch {set g $order($cmit)}]} { + $w_cgrp tag conf g$cmit $w_line tag conf g$cmit $w_file tag conf g$cmit + + $w_cgrp tag raise in_sel $w_line tag raise in_sel $w_file tag raise in_sel + $w_file tag raise sel set order($cmit) $commit_count incr commit_count @@ -235,18 +259,25 @@ method _read_blame {fd} { set n $r_line_count set lno $r_final_line set cmit $r_commit + set abbr [string range $cmit 0 4] while {$n > 0} { set lno_e "$lno.0 lineend + 1c" if {[catch {set g g$line_commit($lno)}]} { $w_load tag add annotated $lno.0 $lno_e } else { + $w_cgrp tag remove g$g $lno.0 $lno_e $w_line tag remove g$g $lno.0 $lno_e $w_file tag remove g$g $lno.0 $lno_e } set line_commit($lno) $cmit set line_file($lno) $file + + $w_cgrp delete $lno.0 $lno_e + $w_cgrp insert $lno.0 "$abbr\n" + + $w_cgrp tag add g$cmit $lno.0 $lno_e $w_line tag add g$cmit $lno.0 $lno_e $w_file tag add g$cmit $lno.0 $lno_e @@ -273,6 +304,7 @@ method _read_blame {fd} { set header($r_commit,$key) $data } } + $w_cgrp conf -state disabled if {[eof $fd]} { close $fd @@ -298,8 +330,12 @@ method _click {cur_w pos} { if {$lno eq {}} return set lno_e "$lno.0 + 1 line" + + $w_cgrp tag remove in_sel 0.0 end $w_line tag remove in_sel 0.0 end $w_file tag remove in_sel 0.0 end + + $w_cgrp tag add in_sel $lno.0 $lno_e $w_line tag add in_sel $lno.0 $lno_e $w_file tag add in_sel $lno.0 $lno_e @@ -321,6 +357,7 @@ method _showcommit {lno} { set i 0 foreach c $blame_colors { set h [lindex $commit_list [expr {$idx - 1 + $i}]] + $w_cgrp tag conf g$h -background white $w_line tag conf g$h -background white $w_file tag conf g$h -background white incr i @@ -337,6 +374,7 @@ method _showcommit {lno} { set i 0 foreach c $blame_colors { set h [lindex $commit_list [expr {$idx - 1 + $i}]] + $w_cgrp tag conf g$h -background $c $w_line tag conf g$h -background $c $w_file tag conf g$h -background $c incr i From d89a494fcae246b696a2fe234ccf166669a3a45e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 00:05:49 -0400 Subject: [PATCH 10/46] git-gui: Cleanup blame::new widget initialization A lot of this code was pre-class, which meant that I just sort of copied and pasted my way through it, rather than being really smart and using a variable for each widget's path name. Since we have a field for each path, we can use those throughout the constructor and make things a lot neater. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 77 +++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 155bbe37f0..2d0c3f2b68 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -48,25 +48,28 @@ constructor new {i_commit i_path} { pack $w.path -side top -fill x frame $w.out - text $w.out.loaded_t \ + set w_load $w.out.loaded_t + text $w_load \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ -height 40 \ -width 1 \ -font font_diff - $w.out.loaded_t tag conf annotated -background grey + $w_load tag conf annotated -background grey - text $w.out.linenumber_t \ + set w_line $w.out.linenumber_t + text $w_line \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ -height 40 \ -width 5 \ -font font_diff - $w.out.linenumber_t tag conf linenumber -justify right + $w_line tag conf linenumber -justify right - text $w.out.commit_t \ + set w_cgrp $w.out.commit_t + text $w_cgrp \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ @@ -74,7 +77,8 @@ constructor new {i_commit i_path} { -width 4 \ -font font_diff - text $w.out.file_t \ + set w_file $w.out.file_t + text $w_file \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ @@ -83,19 +87,19 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.out.sbx set] \ -font font_diff - scrollbar $w.out.sbx -orient h -command [list $w.out.file_t xview] + scrollbar $w.out.sbx -orient h -command [list $w_file xview] scrollbar $w.out.sby -orient v \ -command [list scrollbar2many [list \ - $w.out.loaded_t \ - $w.out.linenumber_t \ - $w.out.commit_t \ - $w.out.file_t \ + $w_load \ + $w_line \ + $w_cgrp \ + $w_file \ ] yview] grid \ - $w.out.commit_t \ - $w.out.linenumber_t \ - $w.out.loaded_t \ - $w.out.file_t \ + $w_cgrp \ + $w_line \ + $w_load \ + $w_file \ $w.out.sby \ -sticky nsew grid conf $w.out.sbx -column 3 -sticky we @@ -112,7 +116,8 @@ constructor new {i_commit i_path} { pack $w.status -side bottom -fill x frame $w.cm - text $w.cm.t \ + set w_cmit $w.cm.t + text $w_cmit \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ @@ -121,11 +126,11 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.cm.sbx set] \ -yscrollcommand [list $w.cm.sby set] \ -font font_diff - scrollbar $w.cm.sbx -orient h -command [list $w.cm.t xview] - scrollbar $w.cm.sby -orient v -command [list $w.cm.t yview] + scrollbar $w.cm.sbx -orient h -command [list $w_cmit xview] + scrollbar $w.cm.sby -orient v -command [list $w_cmit yview] pack $w.cm.sby -side right -fill y pack $w.cm.sbx -side bottom -fill x - pack $w.cm.t -expand 1 -fill both + pack $w_cmit -expand 1 -fill both pack $w.cm -side bottom -fill x menu $w.ctxm -tearoff 0 @@ -133,26 +138,20 @@ constructor new {i_commit i_path} { -label "Copy Commit" \ -command [cb _copycommit] - set w_line $w.out.linenumber_t - set w_cgrp $w.out.commit_t - set w_load $w.out.loaded_t - set w_file $w.out.file_t - set w_cmit $w.cm.t - foreach i [list \ - $w.out.commit_t \ - $w.out.loaded_t \ - $w.out.linenumber_t \ - $w.out.file_t] { + $w_cgrp \ + $w_load \ + $w_line \ + $w_file] { $i tag conf in_sel \ -background [$i cget -foreground] \ -foreground [$i cget -background] $i conf -yscrollcommand \ [list many2scrollbar [list \ - $w.out.commit_t \ - $w.out.loaded_t \ - $w.out.linenumber_t \ - $w.out.file_t \ + $w_cgrp \ + $w_load \ + $w_line \ + $w_file \ ] yview $w.out.sby] bind $i "[cb _click $i @%x,%y]; focus $i" bind_button3 $i " @@ -164,11 +163,11 @@ constructor new {i_commit i_path} { } foreach i [list \ - $w.out.commit_t \ - $w.out.loaded_t \ - $w.out.linenumber_t \ - $w.out.file_t \ - $w.cm.t] { + $w_cgrp \ + $w_load \ + $w_line \ + $w_file \ + $w_cmit] { bind $i {catch {%W yview scroll -1 units};break} bind $i {catch {%W yview scroll 1 units};break} bind $i {catch {%W xview scroll -1 units};break} @@ -181,7 +180,7 @@ constructor new {i_commit i_path} { bind $i {catch {%W yview scroll 1 pages};break} } - bind $w.cm.t [list focus $w.cm.t] + bind $w_cmit [list focus $w_cmit] bind $top [list focus $top] bind $top [list delete_this $this] From bea39c2ddb01af2908a5932231fde02b52a262d7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 00:08:58 -0400 Subject: [PATCH 11/46] git-gui: Remove empty blank line at end of blame The blame viewer has this silly blank line at the bottom of it; we really don't want to see it displayed as we will never get any blame data for that line (it doesn't exist in the source). Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 2d0c3f2b68..a6f0b4ab18 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -203,10 +203,15 @@ method _read_file {fd} { regsub "\r\$" $line {} line incr total_lines - $w_load insert end "\n" - $w_cgrp insert end "\n" - $w_line insert end "$total_lines\n" linenumber - $w_file insert end "$line\n" + if {$total_lines > 1} { + $w_load insert end "\n" + $w_cgrp insert end "\n" + $w_line insert end "\n" + $w_file insert end "\n" + } + + $w_line insert end "$total_lines" linenumber + $w_file insert end "$line" } $w_load conf -state disabled $w_cgrp conf -state disabled From f96cd7b6c9e9664d2fd6ec50bbade126355ad4f4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 00:38:31 -0400 Subject: [PATCH 12/46] git-gui: Improve the coloring in blame viewer The git-gui blame viewer has always been ugly as s**t. Linus Torvalds suggested the coloring scheme I'm using here, which is two different shades of grey for the background colors, and black text on a pale green background for the currently selected/focused commit. The difference is a massive improvement. The interface no longer will cause seizures in people who are prone to that sort of thing. It no longer uses a very offensive hot pink. The green being current actually makes sense. And not having the background of the other non-current lines change when you change the current commit is really a big deal. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 76 ++++++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index a6f0b4ab18..f48624a99e 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -31,6 +31,12 @@ field r_orig_line ; # original line number field r_final_line ; # final line number field r_line_count ; # lines in this region +variable active_color #98e1a0 +variable group_colors { + #cbcbcb + #e1e1e1 +} + constructor new {i_commit i_path} { set commit $i_commit set path $i_path @@ -143,9 +149,6 @@ constructor new {i_commit i_path} { $w_load \ $w_line \ $w_file] { - $i tag conf in_sel \ - -background [$i cget -foreground] \ - -foreground [$i cget -background] $i conf -yscrollcommand \ [list many2scrollbar [list \ $w_cgrp \ @@ -235,6 +238,8 @@ method _read_file {fd} { } ifdeleted { catch {close $fd} } method _read_blame {fd} { + variable group_colors + $w_cgrp conf -state normal while {[gets $fd line] >= 0} { if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ @@ -245,15 +250,14 @@ method _read_blame {fd} { set r_line_count $line_count if {[catch {set g $order($cmit)}]} { - $w_cgrp tag conf g$cmit - $w_line tag conf g$cmit - $w_file tag conf g$cmit + set bg [lindex $group_colors 0] + set group_colors [lrange $group_colors 1 end] + lappend group_colors $bg - $w_cgrp tag raise in_sel - $w_line tag raise in_sel - $w_file tag raise in_sel + $w_cgrp tag conf g$cmit -background $bg + $w_line tag conf g$cmit -background $bg + $w_file tag conf g$cmit -background $bg - $w_file tag raise sel set order($cmit) $commit_count incr commit_count lappend commit_list $cmit @@ -273,6 +277,10 @@ method _read_blame {fd} { $w_cgrp tag remove g$g $lno.0 $lno_e $w_line tag remove g$g $lno.0 $lno_e $w_file tag remove g$g $lno.0 $lno_e + + $w_cgrp tag remove a$g $lno.0 $lno_e + $w_line tag remove a$g $lno.0 $lno_e + $w_file tag remove a$g $lno.0 $lno_e } set line_commit($lno) $cmit @@ -285,6 +293,10 @@ method _read_blame {fd} { $w_line tag add g$cmit $lno.0 $lno_e $w_file tag add g$cmit $lno.0 $lno_e + $w_cgrp tag add a$cmit $lno.0 $lno_e + $w_line tag add a$cmit $lno.0 $lno_e + $w_file tag add a$cmit $lno.0 $lno_e + if {$highlight_line == -1} { if {[lindex [$w_file yview] 0] == 0} { $w_file see $lno.0 @@ -332,40 +344,18 @@ method _status {} { method _click {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] if {$lno eq {}} return - - set lno_e "$lno.0 + 1 line" - - $w_cgrp tag remove in_sel 0.0 end - $w_line tag remove in_sel 0.0 end - $w_file tag remove in_sel 0.0 end - - $w_cgrp tag add in_sel $lno.0 $lno_e - $w_line tag add in_sel $lno.0 $lno_e - $w_file tag add in_sel $lno.0 $lno_e - _showcommit $this $lno } -variable blame_colors { - #ff4040 - #ff40ff - #4040ff -} - method _showcommit {lno} { global repo_config - variable blame_colors + variable active_color if {$highlight_commit ne {}} { - set idx $order($highlight_commit) - set i 0 - foreach c $blame_colors { - set h [lindex $commit_list [expr {$idx - 1 + $i}]] - $w_cgrp tag conf g$h -background white - $w_line tag conf g$h -background white - $w_file tag conf g$h -background white - incr i - } + set cmit $highlight_commit + $w_cgrp tag conf a$cmit -background {} + $w_line tag conf a$cmit -background {} + $w_file tag conf a$cmit -background {} } $w_cmit conf -state normal @@ -374,15 +364,9 @@ method _showcommit {lno} { set cmit {} $w_cmit insert end "Loading annotation..." } else { - set idx $order($cmit) - set i 0 - foreach c $blame_colors { - set h [lindex $commit_list [expr {$idx - 1 + $i}]] - $w_cgrp tag conf g$h -background $c - $w_line tag conf g$h -background $c - $w_file tag conf g$h -background $c - incr i - } + $w_cgrp tag conf a$cmit -background $active_color + $w_line tag conf a$cmit -background $active_color + $w_file tag conf a$cmit -background $active_color set author_name {} set author_email {} From c9e6bfd8a9a18c12d01e0d96c74ca0a7f64a2846 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 01:04:46 -0400 Subject: [PATCH 13/46] git-gui: Simplify consecutive lines that come from the same commit If two consecutive lines in the final file came from the same commit then we store a "|" in the first column rather than the commit id, for the second and subsequent lines in that block. This cleans up the interface so runs associated with the same commit can be more easily seen visually. We also now use the abbreviation "work" for the uncommitted stuff in your working directory, rather than "0000". This looks nicer to the eyes and explains pretty quickly what is going on. There was also a minor bug in the commit abbreviation column for the last line of the file. This is now also fixed. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index f48624a99e..86160092c6 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -267,7 +267,18 @@ method _read_blame {fd} { set n $r_line_count set lno $r_final_line set cmit $r_commit - set abbr [string range $cmit 0 4] + + if {[regexp {^0{40}$} $cmit]} { + set abbr work + } else { + set abbr [string range $cmit 0 4] + } + + if {![catch {set ncmit $line_commit([expr {$lno - 1}])}]} { + if {$ncmit eq $cmit} { + set abbr | + } + } while {$n > 0} { set lno_e "$lno.0 lineend + 1c" @@ -286,8 +297,9 @@ method _read_blame {fd} { set line_commit($lno) $cmit set line_file($lno) $file - $w_cgrp delete $lno.0 $lno_e - $w_cgrp insert $lno.0 "$abbr\n" + $w_cgrp delete $lno.0 "$lno.0 lineend" + $w_cgrp insert $lno.0 $abbr + set abbr | $w_cgrp tag add g$cmit $lno.0 $lno_e $w_line tag add g$cmit $lno.0 $lno_e @@ -311,6 +323,13 @@ method _read_blame {fd} { incr blame_lines } + if {![catch {set ncmit $line_commit($lno)}]} { + if {$ncmit eq $cmit} { + $w_cgrp delete $lno.0 "$lno.0 lineend + 1c" + $w_cgrp insert $lno.0 "|\n" + } + } + set hc $highlight_commit if {$hc ne {} && [expr {$order($hc) + 1}] == $order($cmit)} { From 37ebc93f6dddb6d73034f027873266eef1e3e774 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 02:59:21 -0400 Subject: [PATCH 14/46] git-gui: Use arror cursor in blame viewer file data Since we don't allow the user to select text from the file viewer right now I'm disabling the normal text cursor and putting in a plain arror instead. This way users don't think they can select and copy text, because they can't. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/blame.tcl b/lib/blame.tcl index 86160092c6..33596cd892 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -38,6 +38,8 @@ variable group_colors { } constructor new {i_commit i_path} { + global cursor_ptr + set commit $i_commit set path $i_path @@ -149,6 +151,7 @@ constructor new {i_commit i_path} { $w_load \ $w_line \ $w_file] { + $i conf -cursor $cursor_ptr $i conf -yscrollcommand \ [list many2scrollbar [list \ $w_cgrp \ From 41bf23d6cc58c229e5e966a98c1b2c9cd06e95f7 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 03:01:45 -0400 Subject: [PATCH 15/46] git-gui: Display tooltips in blame viewer When the mouse is over a particular line and we have blame data for that line, but its not the active commit, we should show the user information about that commit like who the author was and what the subject (first line) was. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 126 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 33596cd892..fef28a347e 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -31,6 +31,11 @@ field r_orig_line ; # original line number field r_final_line ; # final line number field r_line_count ; # lines in this region +field tooltip_wm {} ; # Current tooltip toplevel, if open +field tooltip_timer {} ; # Current timer event for our tooltip +field tooltip_commit {} ; # Commit in tooltip +field tooltip_text {} ; # Text in current tooltip + variable active_color #98e1a0 variable group_colors { #cbcbcb @@ -159,8 +164,16 @@ constructor new {i_commit i_path} { $w_line \ $w_file \ ] yview $w.out.sby] - bind $i "[cb _click $i @%x,%y]; focus $i" + bind $i " + [cb _hide_tooltip] + [cb _click $i @%x,%y] + focus $i + " + bind $i [cb _show_tooltip $i @%x,%y] + bind $i [cb _hide_tooltip] + bind $i [cb _hide_tooltip] bind_button3 $i " + [cb _hide_tooltip] set cursorX %x set cursorY %y set cursorW %W @@ -447,6 +460,10 @@ $msg" set highlight_line $lno set highlight_commit $cmit + + if {$highlight_commit eq $tooltip_commit} { + _hide_tooltip $this + } } method _copycommit {} { @@ -461,4 +478,111 @@ method _copycommit {} { } } +method _show_tooltip {cur_w pos} { + set lno [lindex [split [$cur_w index $pos] .] 0] + if {[catch {set cmit $line_commit($lno)}]} { + _hide_tooltip $this + return + } + + if {$cmit eq $highlight_commit} { + _hide_tooltip $this + return + } + + if {$cmit eq $tooltip_commit} { + _position_tooltip $this + } elseif {$tooltip_wm ne {}} { + _open_tooltip $this $cur_w + } elseif {$tooltip_timer eq {}} { + set tooltip_timer [after 1000 [cb _open_tooltip $cur_w]] + } +} + +method _open_tooltip {cur_w} { + set tooltip_timer {} + set pos_x [winfo pointerx $cur_w] + set pos_y [winfo pointery $cur_w] + if {[winfo containing $pos_x $pos_y] ne $cur_w} { + _hide_tooltip $this + return + } + + set pos @[join [list \ + [expr {$pos_x - [winfo rootx $cur_w]}] \ + [expr {$pos_y - [winfo rooty $cur_w]}]] ,] + set lno [lindex [split [$cur_w index $pos] .] 0] + set cmit $line_commit($lno) + + set author_name {} + set author_email {} + set author_time {} + catch {set author_name $header($cmit,author)} + catch {set author_email $header($cmit,author-mail)} + catch {set author_time [clock format \ + $header($cmit,author-time) \ + -format {%Y-%m-%d %H:%M:%S} + ]} + + set committer_name {} + set committer_email {} + set committer_time {} + catch {set committer_name $header($cmit,committer)} + catch {set committer_email $header($cmit,committer-mail)} + catch {set committer_time [clock format \ + $header($cmit,committer-time) \ + -format {%Y-%m-%d %H:%M:%S} + ]} + + set summary {} + catch {set summary $header($cmit,summary)} + + set tooltip_commit $cmit + set tooltip_text "commit $cmit +$author_name $author_email $author_time +$summary" + + if {$tooltip_wm ne "$cur_w.tooltip"} { + _hide_tooltip $this + + set tooltip_wm [toplevel $cur_w.tooltip -borderwidth 1] + wm overrideredirect $tooltip_wm 1 + wm transient $tooltip_wm [winfo toplevel $cur_w] + pack [label $tooltip_wm.label \ + -background lightyellow \ + -foreground black \ + -textvariable @tooltip_text \ + -justify left] + } + _position_tooltip $this +} + +method _position_tooltip {} { + set req_w [winfo reqwidth $tooltip_wm.label] + set req_h [winfo reqheight $tooltip_wm.label] + set pos_x [expr {[winfo pointerx .] + 5}] + set pos_y [expr {[winfo pointery .] + 10}] + + set g "${req_w}x${req_h}" + if {$pos_x >= 0} {append g +} + append g $pos_x + if {$pos_y >= 0} {append g +} + append g $pos_y + + wm geometry $tooltip_wm $g + raise $tooltip_wm +} + +method _hide_tooltip {} { + if {$tooltip_wm ne {}} { + destroy $tooltip_wm + set tooltip_wm {} + set tooltip_commit {} + } + if {$tooltip_timer ne {}} { + after cancel $tooltip_timer + set tooltip_timer {} + } +} + } From 74fe89857807c2194b1c202b4e429289d777ecb2 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 03:19:27 -0400 Subject: [PATCH 16/46] git-gui: Highlight the blame commit header from everything else The selected commit's blame header is now drawn in green, using the same background color that is shown in the main file content viewer. The result is a much better looking commit pane, as we use bold for header "keys" and proportional width fonts for the stuff that doesn't need to be fixed width to maintain its formatting. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index fef28a347e..4730c2b1ea 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -43,6 +43,7 @@ variable group_colors { } constructor new {i_commit i_path} { + variable active_color global cursor_ptr set commit $i_commit @@ -139,6 +140,14 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.cm.sbx set] \ -yscrollcommand [list $w.cm.sby set] \ -font font_diff + $w_cmit tag conf header_key \ + -tabs {3c} \ + -background $active_color \ + -font font_uibold + $w_cmit tag conf header_val \ + -background $active_color \ + -font font_ui + $w_cmit tag raise sel scrollbar $w.cm.sbx -orient h -command [list $w_cmit xview] scrollbar $w.cm.sby -orient v -command [list $w_cmit yview] pack $w.cm.sby -side right -fill y @@ -449,12 +458,21 @@ method _showcommit {lno} { set header($cmit,message) $msg } - $w_cmit insert end "commit $cmit -Author: $author_name $author_email $author_time -Committer: $committer_name $committer_email $committer_time -Original File: [escape_path $line_file($lno)] + $w_cmit insert end "commit $cmit\n" header_key + $w_cmit insert end "Author:\t" header_key + $w_cmit insert end "$author_name $author_email" header_val + $w_cmit insert end "$author_time\n" header_val + + $w_cmit insert end "Committer:\t" header_key + $w_cmit insert end "$committer_name $committer_email" header_val + $w_cmit insert end "$committer_time\n" header_val + + if {$line_file($lno) ne $path} { + $w_cmit insert end "Original File:\t" header_key + $w_cmit insert end "[escape_path $line_file($lno)]\n" header_val + } -$msg" + $w_cmit insert end "\n$msg" } $w_cmit conf -state disabled From 8154e1a624cd768aada2565857151e6032b42a8c Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 03:33:28 -0400 Subject: [PATCH 17/46] git-gui: Remove unnecessary reshow of blamed commit Because we no longer redraw colors every time we select a particular commit there is no need to redraw the screen after we get a new commit in from blame --incremental. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 4730c2b1ea..eaf2fb36f8 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -354,12 +354,6 @@ method _read_blame {fd} { $w_cgrp insert $lno.0 "|\n" } } - - set hc $highlight_commit - if {$hc ne {} - && [expr {$order($hc) + 1}] == $order($cmit)} { - _showcommit $this $highlight_line - } } elseif {[regexp {^([a-z-]+) (.*)$} $line line key data]} { set header($r_commit,$key) $data } From b5a4122474486ccf785dfb78e939e040ac43067c Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 03:34:00 -0400 Subject: [PATCH 18/46] git-gui: Cleanup minor style nit Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index eaf2fb36f8..ac45fb1513 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -173,7 +173,7 @@ constructor new {i_commit i_path} { $w_line \ $w_file \ ] yview $w.out.sby] - bind $i " + bind $i " [cb _hide_tooltip] [cb _click $i @%x,%y] focus $i From ddc1fa8f883fdef4d7501f3f08474f8f75927533 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 15:31:01 -0400 Subject: [PATCH 19/46] git-gui: Space the commit group continuation out in blame view The | in the continued lines of the same commit group as not easily seen on the left edge; putting a single space in front of the pipe makes it slightly more visually appealing to me as I can follow the line down through the group to the next commit marker. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index ac45fb1513..93693d099a 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -301,7 +301,7 @@ method _read_blame {fd} { if {![catch {set ncmit $line_commit([expr {$lno - 1}])}]} { if {$ncmit eq $cmit} { - set abbr | + set abbr { |} } } @@ -324,7 +324,7 @@ method _read_blame {fd} { $w_cgrp delete $lno.0 "$lno.0 lineend" $w_cgrp insert $lno.0 $abbr - set abbr | + set abbr { |} $w_cgrp tag add g$cmit $lno.0 $lno_e $w_line tag add g$cmit $lno.0 $lno_e @@ -351,7 +351,7 @@ method _read_blame {fd} { if {![catch {set ncmit $line_commit($lno)}]} { if {$ncmit eq $cmit} { $w_cgrp delete $lno.0 "$lno.0 lineend + 1c" - $w_cgrp insert $lno.0 "|\n" + $w_cgrp insert $lno.0 " |\n" } } } elseif {[regexp {^([a-z-]+) (.*)$} $line line key data]} { From 223475a77c36919942c92f66c87b1e772a0ee2af Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 16:10:56 -0400 Subject: [PATCH 20/46] git-gui: Show author initials in blame groups Frequently when I'm looking at blocks of code in the blame viewer I want to know who is the culprit, or who I should be praising for a job well done. The tooltips nicely show this if I mouse over a block, but it doesn't work to get this detail at a glance. Since we don't use the leftmost commit column for anything after the first line within a commit group I'm now tossing the author's initials into that field, right justified. It is quite clearly not a SHA-1 number as we always show the SHA-1 in lowercase, while we explicitly select only the uppercase characters from an author's name field, and only those that are following whitespace. I'm using initials here over anything else as they are quite commonly unique within small development teams. The leading part of the email address field was out for some of the teams I work with, as there the email addresses are all of the form "Givenname.Surname@initech.com". That will never fit into the 4 characters available. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 58 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 93693d099a..02e439cbc6 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -294,16 +294,39 @@ method _read_blame {fd} { set cmit $r_commit if {[regexp {^0{40}$} $cmit]} { - set abbr work + set commit_abbr work } else { - set abbr [string range $cmit 0 4] + set commit_abbr [string range $cmit 0 4] } - if {![catch {set ncmit $line_commit([expr {$lno - 1}])}]} { - if {$ncmit eq $cmit} { - set abbr { |} + set author_abbr {} + set a_name {} + catch {set a_name $header($cmit,author)} + while {$a_name ne {}} { + if {![regexp {^([[:upper:]])} $a_name _a]} break + append author_abbr $_a + unset _a + if {![regsub \ + {^[[:upper:]][^\s]*\s+} \ + $a_name {} a_name ]} break + } + if {$author_abbr eq {}} { + set author_abbr { |} + } else { + set author_abbr [string range $author_abbr 0 3] + while {[string length $author_abbr] < 4} { + set author_abbr " $author_abbr" } } + unset a_name + + set first_lno $lno + while { + ![catch {set ncmit $line_commit([expr {$first_lno - 1}])}] + && $ncmit eq $cmit + } { + incr first_lno -1 + } while {$n > 0} { set lno_e "$lno.0 lineend + 1c" @@ -323,8 +346,13 @@ method _read_blame {fd} { set line_file($lno) $file $w_cgrp delete $lno.0 "$lno.0 lineend" - $w_cgrp insert $lno.0 $abbr - set abbr { |} + if {$lno == $first_lno} { + $w_cgrp insert $lno.0 $commit_abbr + } elseif {$lno == [expr {$first_lno + 1}]} { + $w_cgrp insert $lno.0 $author_abbr + } else { + $w_cgrp insert $lno.0 { |} + } $w_cgrp tag add g$cmit $lno.0 $lno_e $w_line tag add g$cmit $lno.0 $lno_e @@ -348,12 +376,20 @@ method _read_blame {fd} { incr blame_lines } - if {![catch {set ncmit $line_commit($lno)}]} { - if {$ncmit eq $cmit} { - $w_cgrp delete $lno.0 "$lno.0 lineend + 1c" - $w_cgrp insert $lno.0 " |\n" + while {![catch {set ncmit $line_commit($lno)}] + && $ncmit eq $cmit} { + $w_cgrp delete $lno.0 "$lno.0 lineend" + + if {$lno == $first_lno} { + $w_cgrp insert $lno.0 $commit_abbr + } elseif {$lno == [expr {$first_lno + 1}]} { + $w_cgrp insert $lno.0 $author_abbr + } else { + $w_cgrp insert $lno.0 { |} } + incr lno } + } elseif {[regexp {^([a-z-]+) (.*)$} $line line key data]} { set header($r_commit,$key) $data } From d0b741dc08d1c036e0fbf68c72dda02545c39b85 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 17:55:43 -0400 Subject: [PATCH 21/46] git-gui: Allow the user to control the blame/commit split point At one point I tried to present the blame viewer to an audience of people on a 640 by 480 pixel LCD projector. This did not work at all as the top area (the file data) was taking up all of the screen realestate and the split point was not adjustable by the user. In general locking the user into a specific ratio of display is just not user friendly. So we now place a split pane control into the middle of our blame window, so the user can adjust it to their current needs. If the window increases (or decreases) in height we assign the difference to the file data area, as that is generally the area of the window that users are trying to see more of when they grow the window. Unfortunately there appears to be a bug in the "pack" layout manager in Tcl/Tk 8.4.1. The status bar and the lower commit pane was being squashed if the window decreased in height. I think the pack manager was just not decreasing the size of the panedwindow slave properly if the main window shrank. Switching to the "grid" layout manager fixes the problem, but is slightly uglier setup code. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 104 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 79 insertions(+), 25 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 02e439cbc6..f15e5a0723 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -13,6 +13,7 @@ field w_load field w_file field w_cmit field status +field old_height field highlight_line -1 ; # current line selected field highlight_commit {} ; # sha1 of commit selected @@ -59,10 +60,22 @@ constructor new {i_commit i_path} { -borderwidth 1 \ -relief sunken \ -font font_uibold - pack $w.path -side top -fill x - frame $w.out - set w_load $w.out.loaded_t + panedwindow $w.file_pane -orient vertical + frame $w.file_pane.out + frame $w.file_pane.cm + $w.file_pane add $w.file_pane.out \ + -sticky nsew \ + -minsize 100 \ + -height 100 \ + -width 100 + $w.file_pane add $w.file_pane.cm \ + -sticky nsew \ + -minsize 25 \ + -height 25 \ + -width 100 + + set w_load $w.file_pane.out.loaded_t text $w_load \ -background white -borderwidth 0 \ -state disabled \ @@ -72,7 +85,7 @@ constructor new {i_commit i_path} { -font font_diff $w_load tag conf annotated -background grey - set w_line $w.out.linenumber_t + set w_line $w.file_pane.out.linenumber_t text $w_line \ -background white -borderwidth 0 \ -state disabled \ @@ -82,7 +95,7 @@ constructor new {i_commit i_path} { -font font_diff $w_line tag conf linenumber -justify right - set w_cgrp $w.out.commit_t + set w_cgrp $w.file_pane.out.commit_t text $w_cgrp \ -background white -borderwidth 0 \ -state disabled \ @@ -91,18 +104,21 @@ constructor new {i_commit i_path} { -width 4 \ -font font_diff - set w_file $w.out.file_t + set w_file $w.file_pane.out.file_t text $w_file \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ -height 40 \ -width 80 \ - -xscrollcommand [list $w.out.sbx set] \ + -xscrollcommand [list $w.file_pane.out.sbx set] \ -font font_diff - scrollbar $w.out.sbx -orient h -command [list $w_file xview] - scrollbar $w.out.sby -orient v \ + scrollbar $w.file_pane.out.sbx \ + -orient h \ + -command [list $w_file xview] + scrollbar $w.file_pane.out.sby \ + -orient v \ -command [list scrollbar2many [list \ $w_load \ $w_line \ @@ -114,12 +130,11 @@ constructor new {i_commit i_path} { $w_line \ $w_load \ $w_file \ - $w.out.sby \ + $w.file_pane.out.sby \ -sticky nsew - grid conf $w.out.sbx -column 3 -sticky we - grid columnconfigure $w.out 3 -weight 1 - grid rowconfigure $w.out 0 -weight 1 - pack $w.out -fill both -expand 1 + grid conf $w.file_pane.out.sbx -column 3 -sticky we + grid columnconfigure $w.file_pane.out 3 -weight 1 + grid rowconfigure $w.file_pane.out 0 -weight 1 label $w.status \ -textvariable @status \ @@ -127,18 +142,16 @@ constructor new {i_commit i_path} { -justify left \ -borderwidth 1 \ -relief sunken - pack $w.status -side bottom -fill x - frame $w.cm - set w_cmit $w.cm.t + set w_cmit $w.file_pane.cm.t text $w_cmit \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ -height 10 \ -width 80 \ - -xscrollcommand [list $w.cm.sbx set] \ - -yscrollcommand [list $w.cm.sby set] \ + -xscrollcommand [list $w.file_pane.cm.sbx set] \ + -yscrollcommand [list $w.file_pane.cm.sby set] \ -font font_diff $w_cmit tag conf header_key \ -tabs {3c} \ @@ -148,12 +161,15 @@ constructor new {i_commit i_path} { -background $active_color \ -font font_ui $w_cmit tag raise sel - scrollbar $w.cm.sbx -orient h -command [list $w_cmit xview] - scrollbar $w.cm.sby -orient v -command [list $w_cmit yview] - pack $w.cm.sby -side right -fill y - pack $w.cm.sbx -side bottom -fill x + scrollbar $w.file_pane.cm.sbx \ + -orient h \ + -command [list $w_cmit xview] + scrollbar $w.file_pane.cm.sby \ + -orient v \ + -command [list $w_cmit yview] + pack $w.file_pane.cm.sby -side right -fill y + pack $w.file_pane.cm.sbx -side bottom -fill x pack $w_cmit -expand 1 -fill both - pack $w.cm -side bottom -fill x menu $w.ctxm -tearoff 0 $w.ctxm add command \ @@ -172,7 +188,7 @@ constructor new {i_commit i_path} { $w_load \ $w_line \ $w_file \ - ] yview $w.out.sby] + ] yview $w.file_pane.out.sby] bind $i " [cb _hide_tooltip] [cb _click $i @%x,%y] @@ -212,6 +228,29 @@ constructor new {i_commit i_path} { bind $top [list focus $top] bind $top [list delete_this $this] + grid configure $w.path -sticky ew + grid configure $w.file_pane -sticky nsew + grid configure $w.status -sticky ew + grid columnconfigure $top 0 -weight 1 + grid rowconfigure $top 0 -weight 0 + grid rowconfigure $top 1 -weight 1 + grid rowconfigure $top 2 -weight 0 + + set req_w [winfo reqwidth $top] + set req_h [winfo reqheight $top] + if {$req_w < 600} {set req_w 600} + if {$req_h < 400} {set req_h 400} + set g "${req_w}x${req_h}" + wm geometry $top $g + update + + set old_height [winfo height $w.file_pane] + $w.file_pane sash place 0 \ + [lindex [$w.file_pane sash coord 0] 0] \ + [expr {int($old_height * 0.70)}] + bind $w.file_pane \ + "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" + if {$commit eq {}} { set fd [open $path r] } else { @@ -633,4 +672,19 @@ method _hide_tooltip {} { } } +method _resize {new_height} { + set diff [expr {$new_height - $old_height}] + if {$diff == 0} return + + set my [expr {[winfo height $w.file_pane] - 25}] + set o [$w.file_pane sash coord 0] + set ox [lindex $o 0] + set oy [expr {[lindex $o 1] + $diff}] + if {$oy < 0} {set oy 0} + if {$oy > $my} {set oy $my} + $w.file_pane sash place 0 $ox $oy + + set old_height $new_height +} + } From 982cf98fa47b8db890b84febda325e461f8a407d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 18:29:20 -0400 Subject: [PATCH 22/46] git-gui: Display a progress bar during blame annotation gathering Computing the blame records for a large file with a long project history can take git a while to run; traditionally we have shown a little meter in the status area of our blame viewer that lets the user know how many lines have been finished, and how far we are through the process. Usually such progress indicators are drawn with a little progress bar in the window, where the bar shows how much has been completed and hides itself when the process is complete. I'm using a very simple hack to do that: draw a canvas with a filled rectangle. Of course the time remaining has absolutely no relationship to the progress meter. It could take very little time for git-blame to get the first 90% of the file, and then it could take many times that to get the remaining 10%. So the progress meter doesn't really have any sort of assurances that it relates to the true progress of the work. But in practice on some ugly history it does seem to hold a reasonable indicator to the completion status. Besides, its amusing to watch and that keeps the user from realizing git is being somewhat slow. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index f15e5a0723..1223c567ab 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -136,13 +136,6 @@ constructor new {i_commit i_path} { grid columnconfigure $w.file_pane.out 3 -weight 1 grid rowconfigure $w.file_pane.out 0 -weight 1 - label $w.status \ - -textvariable @status \ - -anchor w \ - -justify left \ - -borderwidth 1 \ - -relief sunken - set w_cmit $w.file_pane.cm.t text $w_cmit \ -background white -borderwidth 0 \ @@ -171,6 +164,23 @@ constructor new {i_commit i_path} { pack $w.file_pane.cm.sbx -side bottom -fill x pack $w_cmit -expand 1 -fill both + frame $w.status \ + -borderwidth 1 \ + -relief sunken + label $w.status.l \ + -textvariable @status \ + -anchor w \ + -justify left + canvas $w.status.c \ + -width 100 \ + -height [expr {int([winfo reqheight $w.status.l] * 0.6)}] \ + -borderwidth 1 \ + -relief groove \ + -highlightt 0 + $w.status.c create rectangle 0 0 0 20 -tags bar -fill navy + pack $w.status.l -side left + pack $w.status.c -side right + menu $w.ctxm -tearoff 0 $w.ctxm add command \ -label "Copy Commit" \ @@ -226,7 +236,7 @@ constructor new {i_commit i_path} { bind $w_cmit [list focus $w_cmit] bind $top [list focus $top] - bind $top [list delete_this $this] + bind $w_file [list delete_this $this] grid configure $w.path -sticky ew grid configure $w.file_pane -sticky nsew @@ -438,6 +448,7 @@ method _read_blame {fd} { if {[eof $fd]} { close $fd set status {Annotation complete.} + destroy $w.status.c } else { _status $this } @@ -452,6 +463,7 @@ method _status {} { set status [format \ "Loading annotations... %i of %i lines annotated (%2i%%)" \ $have $total $pdone] + $w.status.c coords bar 0 0 $pdone 20 } method _click {cur_w pos} { From 22c6769d917635732fe9e6824aa30536155266b3 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 21:47:12 -0400 Subject: [PATCH 23/46] git-gui: Allow digging through history in blame viewer gitweb has long had a feature where the user can click on any commit the blame display and go visit that commit's information page. From the user could go get the blame display for the file they are tracking, and try to digg through the history of any part of the code they are interested in seeing. We now offer somewhat similiar functionality in git-gui. The 4 digit commit abreviation in the first column of our blame view is now offered as a hyperlink if the commit isn't the one we are now viewing the blame output for (as there is no point in linking back to yourself). Clicking on that link will stop the current blame engine (if still running), push the new target commit onto the history stack, and restart the blame viewer at that commit, using the "original file name" as supplied by git-blame for that chunk of the output. Users can navigate back to a version they had been viewing before by way of a back button, which offers the prior commits in a popup menu displayed right below the back button. I'm always showing the menu here as the cost of switching between views is very high; you don't want to jump to a commit you are not interested in looking at again. During switches we throw away all data except the cached commit data, as that is relatively small compared to most source files and their annotation marks. Unfortunately throwing this per-file data away in Tcl seems to take some time; I probably should move the line indexed arrays to proper lists and use [lindex] rather than the array lookup (usually lists are faster). We now start the git-blame process using "nice", so that its priority will drop hopefully below our own. If I don't do this the blame engine gets a lot of CPU under Windows 2000 and the git-gui user interface is almost non-responsive, even though Tcl is just sitting there waiting for events. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 218 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 188 insertions(+), 30 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 1223c567ab..33e8489d06 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -3,18 +3,24 @@ class blame { -field commit ; # input commit to blame -field path ; # input filename to view in $commit - -field w -field w_line -field w_cgrp -field w_load -field w_file -field w_cmit -field status -field old_height - +image create photo ::blame::img_back_arrow -data {R0lGODlhGAAYAIUAAPwCBEzKXFTSZIz+nGzmhGzqfGTidIT+nEzGXHTqhGzmfGzifFzadETCVES+VARWDFzWbHzyjAReDGTadFTOZDSyRDyyTCymPARaFGTedFzSbDy2TCyqRCyqPARaDAyCHES6VDy6VCyiPAR6HCSeNByWLARyFARiDARqFGTifARiFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAYABgAAAajQIBwSCwaj8ikcsk0BppJwRPqHEypQwHBis0WDAdEFyBIKBaMAKLBdjQeSkFBYTBAIvgEoS6JmhUTEwIUDQ4VFhcMGEhyCgoZExoUaxsWHB0THkgfAXUGAhoBDSAVFR0XBnCbDRmgog0hpSIiDJpJIyEQhBUcJCIlwA22SSYVogknEg8eD82qSigdDSknY0IqJQXPYxIl1dZCGNvWw+Dm510GQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} + +field commit ; # input commit to blame +field path ; # input filename to view in $commit +field history {}; # viewer history: {commit path} + +field w ; # top window in this viewer +field w_back ; # our back button +field w_path ; # label showing the current file path +field w_line ; # text column: all line numbers +field w_cgrp ; # text column: abbreviated commit SHA-1s +field w_load ; # text column: loaded indicator +field w_file ; # text column: actual file data +field w_cmit ; # pane showing commit message +field status ; # text variable bound to status bar +field old_height ; # last known height of $w.file_pane + +field current_fd {} ; # background process running field highlight_line -1 ; # current line selected field highlight_commit {} ; # sha1 of commit selected @@ -52,14 +58,42 @@ constructor new {i_commit i_path} { make_toplevel top w wm title $top "[appname] ([reponame]): File Viewer" - set status "Loading $commit:$path..." - label $w.path -text "$commit:$path" \ + frame $w.header -background orange + label $w.header.commit_l \ + -text {Commit:} \ + -background orange \ -anchor w \ - -justify left \ - -borderwidth 1 \ - -relief sunken \ - -font font_uibold + -justify left + set w_back $w.header.commit_b + button $w_back \ + -command [cb _history_menu] \ + -image ::blame::img_back_arrow \ + -borderwidth 0 \ + -relief flat \ + -state disabled \ + -background orange \ + -activebackground orange + label $w.header.commit \ + -textvariable @commit \ + -background orange \ + -anchor w \ + -justify left + label $w.header.path_l \ + -text {File:} \ + -background orange \ + -anchor w \ + -justify left + set w_path $w.header.path + label $w_path \ + -background orange \ + -anchor w \ + -justify left + pack $w.header.commit_l -side left + pack $w_back -side left + pack $w.header.commit -side left + pack $w_path -fill x -side right + pack $w.header.path_l -side right panedwindow $w.file_pane -orient vertical frame $w.file_pane.out @@ -103,6 +137,13 @@ constructor new {i_commit i_path} { -height 40 \ -width 4 \ -font font_diff + $w_cgrp tag conf curr_commit + $w_cgrp tag conf prior_commit \ + -foreground blue \ + -underline 1 + $w_cgrp tag bind prior_commit \ + \ + "[cb _load_commit @%x,%y];break" set w_file $w.file_pane.out.file_t text $w_file \ @@ -171,15 +212,7 @@ constructor new {i_commit i_path} { -textvariable @status \ -anchor w \ -justify left - canvas $w.status.c \ - -width 100 \ - -height [expr {int([winfo reqheight $w.status.l] * 0.6)}] \ - -borderwidth 1 \ - -relief groove \ - -highlightt 0 - $w.status.c create rectangle 0 0 0 20 -tags bar -fill navy pack $w.status.l -side left - pack $w.status.c -side right menu $w.ctxm -tearoff 0 $w.ctxm add command \ @@ -238,7 +271,7 @@ constructor new {i_commit i_path} { bind $top [list focus $top] bind $w_file [list delete_this $this] - grid configure $w.path -sticky ew + grid configure $w.header -sticky ew grid configure $w.file_pane -sticky nsew grid configure $w.status -sticky ew grid columnconfigure $top 0 -weight 1 @@ -261,6 +294,66 @@ constructor new {i_commit i_path} { bind $w.file_pane \ "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" + _load $this +} + +method _load {} { + _hide_tooltip $this + + if {$total_lines != 0 || $current_fd ne {}} { + if {$current_fd ne {}} { + catch {close $current_fd} + set current_fd {} + } + + set highlight_line -1 + set highlight_commit {} + set total_lines 0 + set blame_lines 0 + set commit_count 0 + set commit_list {} + array unset order + array unset line_commit + array unset line_file + + $w_load conf -state normal + $w_cgrp conf -state normal + $w_line conf -state normal + $w_file conf -state normal + + $w_load delete 0.0 end + $w_cgrp delete 0.0 end + $w_line delete 0.0 end + $w_file delete 0.0 end + + $w_load conf -state disabled + $w_cgrp conf -state disabled + $w_line conf -state disabled + $w_file conf -state disabled + } + + if {[winfo exists $w.status.c]} { + $w.status.c coords bar 0 0 0 20 + } else { + canvas $w.status.c \ + -width 100 \ + -height [expr {int([winfo reqheight $w.status.l] * 0.6)}] \ + -borderwidth 1 \ + -relief groove \ + -highlightt 0 + $w.status.c create rectangle 0 0 0 20 -tags bar -fill navy + pack $w.status.c -side right + } + + if {$history eq {}} { + $w_back conf -state disabled + } else { + $w_back conf -state normal + } + lappend history [list $commit $path] + + set status "Loading $commit:[escape_path $path]..." + $w_path conf -text [escape_path $path] if {$commit eq {}} { set fd [open $path r] } else { @@ -269,9 +362,52 @@ constructor new {i_commit i_path} { } fconfigure $fd -blocking 0 -translation lf -encoding binary fileevent $fd readable [cb _read_file $fd] + set current_fd $fd +} + +method _history_menu {} { + set m $w.backmenu + if {[winfo exists $m]} { + $m delete 0 end + } else { + menu $m -tearoff 0 + } + + for {set i [expr {[llength $history] - 2}] + } {$i >= 0} {incr i -1} { + set e [lindex $history $i] + set c [lindex $e 0] + set f [lindex $e 1] + + if {[regexp {^[0-9a-f]{40}$} $c]} { + set t [string range $c 0 8]... + } else { + set t $c + } + if {![catch {set summary $header($c,summary)}]} { + append t " $summary" + } + + $m add command -label $t -command [cb _goback $i $c $f] + } + set X [winfo rootx $w_back] + set Y [expr {[winfo rooty $w_back] + [winfo height $w_back]}] + tk_popup $m $X $Y +} + +method _goback {i c f} { + set history [lrange $history 0 [expr {$i - 1}]] + set commit $c + set path $f + _load $this } method _read_file {fd} { + if {$fd ne $current_fd} { + catch {close $fd} + return + } + $w_load conf -state normal $w_cgrp conf -state normal $w_line conf -state normal @@ -298,7 +434,7 @@ method _read_file {fd} { if {[eof $fd]} { close $fd _status $this - set cmd [list git blame -M -C --incremental] + set cmd {nice git blame -M -C --incremental} if {$commit eq {}} { lappend cmd --contents $path } else { @@ -308,12 +444,18 @@ method _read_file {fd} { set fd [open "| $cmd" r] fconfigure $fd -blocking 0 -translation lf -encoding binary fileevent $fd readable [cb _read_blame $fd] + set current_fd $fd } } ifdeleted { catch {close $fd} } method _read_blame {fd} { variable group_colors + if {$fd ne $current_fd} { + catch {close $fd} + return + } + $w_cgrp conf -state normal while {[gets $fd line] >= 0} { if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ @@ -344,7 +486,12 @@ method _read_blame {fd} { if {[regexp {^0{40}$} $cmit]} { set commit_abbr work + set commit_type curr_commit + } elseif {$cmit eq $commit} { + set commit_abbr this + set commit_type curr_commit } else { + set commit_type prior_commit set commit_abbr [string range $cmit 0 4] } @@ -396,7 +543,7 @@ method _read_blame {fd} { $w_cgrp delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_cgrp insert $lno.0 $commit_abbr + $w_cgrp insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { $w_cgrp insert $lno.0 $author_abbr } else { @@ -430,7 +577,7 @@ method _read_blame {fd} { $w_cgrp delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_cgrp insert $lno.0 $commit_abbr + $w_cgrp insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { $w_cgrp insert $lno.0 $author_abbr } else { @@ -447,6 +594,7 @@ method _read_blame {fd} { if {[eof $fd]} { close $fd + set current_fd {} set status {Annotation complete.} destroy $w.status.c } else { @@ -472,6 +620,16 @@ method _click {cur_w pos} { _showcommit $this $lno } +method _load_commit {pos} { + set lno [lindex [split [$w_cgrp index $pos] .] 0] + if {[catch {set cmit $line_commit($lno)}]} return + if {[catch {set file $line_file($lno) }]} return + + set commit $cmit + set path $file + _load $this +} + method _showcommit {lno} { global repo_config variable active_color From 669fbc3d09b259bb3bc3bd2ab126ceb28db61b16 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 21:54:06 -0400 Subject: [PATCH 24/46] git-gui: Combine blame groups only if commit and filename match Consecutive chunks of a file could come from the same commit, but have different original file names. Previously we would have put them into a single group, but then the hyperlink would jump to only one of the files, and the other would not be accessible. Now we can get to the other file too. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 33e8489d06..33d5204f32 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -518,8 +518,10 @@ method _read_blame {fd} { set first_lno $lno while { - ![catch {set ncmit $line_commit([expr {$first_lno - 1}])}] + ![catch {set ncmit $line_commit([expr {$first_lno - 1}])}] + && ![catch {set nfile $line_file([expr {$first_lno - 1}])}] && $ncmit eq $cmit + && $nfile eq $file } { incr first_lno -1 } @@ -572,8 +574,12 @@ method _read_blame {fd} { incr blame_lines } - while {![catch {set ncmit $line_commit($lno)}] - && $ncmit eq $cmit} { + while { + ![catch {set ncmit $line_commit($lno)}] + && ![catch {set nfile $line_file($lno)}] + && $ncmit eq $cmit + && $nfile eq $file + } { $w_cgrp delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { From 79c50bf3ee1e0fb5c257ed6f6680cae726a4c412 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 21:59:29 -0400 Subject: [PATCH 25/46] git-gui: Show original filename in blame tooltip If we have two commits right next to each other in the final file and they were kept as different blocks in the leftmost column then its probably because the original filename was different. To help the user know where they are digging into when they click on that link we now show the original file in the tooltip, but to save space we do so only if the original file is not the same as the file we are currently viewing. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/blame.tcl b/lib/blame.tcl index 33d5204f32..bd8e631f34 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -805,6 +805,13 @@ method _open_tooltip {cur_w} { $author_name $author_email $author_time $summary" + set file $line_file($lno) + if {$file ne $path} { + append tooltip_text " + +Original File: $file" + } + if {$tooltip_wm ne "$cur_w.tooltip"} { _hide_tooltip $this From 08dda17e00e676c5cd1b4f2a8245c318d6c97f82 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 1 Jun 2007 23:48:18 -0400 Subject: [PATCH 26/46] git-gui: Use a label instead of a button for the back button Apparently Tk on Mac OS X won't draw a button with an image using a transparent background. Instead it draws the button using some sort of 3D effect, even though I asked for no relief and no border. The background is also not our orange that we expected it to be. Earlier I had tried this same trick on Windows and it draws the same way as the button did, so I'm going to switch to the label as that seems to be more portable. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index bd8e631f34..2f7503ad6b 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -66,14 +66,18 @@ constructor new {i_commit i_path} { -anchor w \ -justify left set w_back $w.header.commit_b - button $w_back \ - -command [cb _history_menu] \ + label $w_back \ -image ::blame::img_back_arrow \ -borderwidth 0 \ -relief flat \ -state disabled \ -background orange \ -activebackground orange + bind $w_back " + if {\[$w_back cget -state\] eq {normal}} { + [cb _history_menu] + } + " label $w.header.commit \ -textvariable @commit \ -background orange \ From b55a243dfc51865445e4b13e84dc6d4cb917bcdf Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 00:09:55 -0400 Subject: [PATCH 27/46] git-gui: Clip the commit summaries in the blame history menu Some commit lines can get really long when users enter a lot of text without linewrapping (for example). Rather than letting the menu get out of control in terms of width we clip the summary to the first 50+ characters. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/blame.tcl b/lib/blame.tcl index 2f7503ad6b..85e9e0dc32 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -390,6 +390,9 @@ method _history_menu {} { } if {![catch {set summary $header($c,summary)}]} { append t " $summary" + if {[string length $t] > 70} { + set t [string range $t 0 66]... + } } $m add command -label $t -command [cb _goback $i $c $f] From 0eab69a4a97294c9d6751fad17d1273e28f4a4cd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 02:38:26 -0400 Subject: [PATCH 28/46] git-gui: Remove the loaded column from the blame viewer Originally I had placed this loaded column between the line number and the file line data to help users know if a particular line has received annotation data or not yet. This way users would know if the line(s) they were interested in were ready for viewing, or if they still had to wait. It also was an entertaining way for the user to spend their time waiting for git-blame --incremental to compute the complete set of annotations. However it is completely useless now that we show the abbreviated commit SHA-1 and author initials in the leftmost column. That area is empty until we get the annotation data, and as soon as we get it in we display something there, indicating to the user that there is now blame data ready. Further with the tooltips the user is likely to see the data as soon as it comes in, as they are probably not keeping their mouse perfectly still. So I'm removing the field to save screen space for more useful things, like file content. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 85e9e0dc32..ca73ba7d14 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -14,7 +14,6 @@ field w_back ; # our back button field w_path ; # label showing the current file path field w_line ; # text column: all line numbers field w_cgrp ; # text column: abbreviated commit SHA-1s -field w_load ; # text column: loaded indicator field w_file ; # text column: actual file data field w_cmit ; # pane showing commit message field status ; # text variable bound to status bar @@ -113,16 +112,6 @@ constructor new {i_commit i_path} { -height 25 \ -width 100 - set w_load $w.file_pane.out.loaded_t - text $w_load \ - -background white -borderwidth 0 \ - -state disabled \ - -wrap none \ - -height 40 \ - -width 1 \ - -font font_diff - $w_load tag conf annotated -background grey - set w_line $w.file_pane.out.linenumber_t text $w_line \ -background white -borderwidth 0 \ @@ -165,7 +154,6 @@ constructor new {i_commit i_path} { scrollbar $w.file_pane.out.sby \ -orient v \ -command [list scrollbar2many [list \ - $w_load \ $w_line \ $w_cgrp \ $w_file \ @@ -173,12 +161,11 @@ constructor new {i_commit i_path} { grid \ $w_cgrp \ $w_line \ - $w_load \ $w_file \ $w.file_pane.out.sby \ -sticky nsew - grid conf $w.file_pane.out.sbx -column 3 -sticky we - grid columnconfigure $w.file_pane.out 3 -weight 1 + grid conf $w.file_pane.out.sbx -column 2 -sticky we + grid columnconfigure $w.file_pane.out 2 -weight 1 grid rowconfigure $w.file_pane.out 0 -weight 1 set w_cmit $w.file_pane.cm.t @@ -225,14 +212,12 @@ constructor new {i_commit i_path} { foreach i [list \ $w_cgrp \ - $w_load \ $w_line \ $w_file] { $i conf -cursor $cursor_ptr $i conf -yscrollcommand \ [list many2scrollbar [list \ $w_cgrp \ - $w_load \ $w_line \ $w_file \ ] yview $w.file_pane.out.sby] @@ -255,7 +240,6 @@ constructor new {i_commit i_path} { foreach i [list \ $w_cgrp \ - $w_load \ $w_line \ $w_file \ $w_cmit] { @@ -320,17 +304,14 @@ method _load {} { array unset line_commit array unset line_file - $w_load conf -state normal $w_cgrp conf -state normal $w_line conf -state normal $w_file conf -state normal - $w_load delete 0.0 end $w_cgrp delete 0.0 end $w_line delete 0.0 end $w_file delete 0.0 end - $w_load conf -state disabled $w_cgrp conf -state disabled $w_line conf -state disabled $w_file conf -state disabled @@ -415,7 +396,6 @@ method _read_file {fd} { return } - $w_load conf -state normal $w_cgrp conf -state normal $w_line conf -state normal $w_file conf -state normal @@ -424,7 +404,6 @@ method _read_file {fd} { incr total_lines if {$total_lines > 1} { - $w_load insert end "\n" $w_cgrp insert end "\n" $w_line insert end "\n" $w_file insert end "\n" @@ -433,7 +412,6 @@ method _read_file {fd} { $w_line insert end "$total_lines" linenumber $w_file insert end "$line" } - $w_load conf -state disabled $w_cgrp conf -state disabled $w_line conf -state disabled $w_file conf -state disabled @@ -535,9 +513,7 @@ method _read_blame {fd} { while {$n > 0} { set lno_e "$lno.0 lineend + 1c" - if {[catch {set g g$line_commit($lno)}]} { - $w_load tag add annotated $lno.0 $lno_e - } else { + if {![catch {set g g$line_commit($lno)}]} { $w_cgrp tag remove g$g $lno.0 $lno_e $w_line tag remove g$g $lno.0 $lno_e $w_file tag remove g$g $lno.0 $lno_e From 063257076d8ea2bbf185ca33192583e03099e955 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 02:55:53 -0400 Subject: [PATCH 29/46] git-gui: Remove unnecessary space between columns in blame viewer On Mac OS X the OS has "features" that like to draw thick black borders around the text field that has focus. This is nice if you want to know where your text is going and are blind as a bat, but it isn't the best thing to have in a table that is being faked through the abuse of Tk text widgets. By setting our takefocus, highlightthickness and padx/y we can get rid of this border and get our text widgets packed right next to each other, with no padding between them. This makes the blame background color smoothly run across the entire line of commit data, line number and file content. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index ca73ba7d14..1346fa5452 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -114,16 +114,22 @@ constructor new {i_commit i_path} { set w_line $w.file_pane.out.linenumber_t text $w_line \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ -height 40 \ -width 5 \ -font font_diff - $w_line tag conf linenumber -justify right + $w_line tag conf linenumber -justify right -rmargin 5 set w_cgrp $w.file_pane.out.commit_t text $w_cgrp \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ @@ -140,6 +146,9 @@ constructor new {i_commit i_path} { set w_file $w.file_pane.out.file_t text $w_file \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ From 000a10696c0bc1e428bbd22af9e19b27795e72dd Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 14:31:01 -0400 Subject: [PATCH 30/46] git-gui: Use lighter colors in blame view The colors I originally picked out on a Mac OS X system look a tad too dark on a Windows 2000 system; the greys are dark enough to make it difficult to read some lines of text and the green used to highlight the current commit was also difficult to read text on. I also added a third grey to the mix, to try and help some files that wind up with a number of neighboring chunks getting the same colors. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 1346fa5452..1c3f5e985e 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -42,10 +42,11 @@ field tooltip_timer {} ; # Current timer event for our tooltip field tooltip_commit {} ; # Commit in tooltip field tooltip_text {} ; # Text in current tooltip -variable active_color #98e1a0 +variable active_color #c0edc5 variable group_colors { - #cbcbcb + #d6d6d6 #e1e1e1 + #ececec } constructor new {i_commit i_path} { From 375e1365a62df3cd944ec0e91051b94d710a7c6d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 14:35:44 -0400 Subject: [PATCH 31/46] git-gui: Make the line number column slightly wider in blame Most source code files are under 9,999 lines of text, so using a field width of 5 characters meant that we should have had one char padding on the left edge (because we right-justify the line number). Unfortunately when I added the right margin earlier (when I removed the padding) I ate into the extra character's space, losing the left margin. This put the line numbers too close to the commit column in any file with more than 999 lines in it. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 1c3f5e985e..5561702683 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -122,7 +122,7 @@ constructor new {i_commit i_path} { -state disabled \ -wrap none \ -height 40 \ - -width 5 \ + -width 6 \ -font font_diff $w_line tag conf linenumber -justify right -rmargin 5 From 81fb7efeda2ce14cbb44b91eed37aeeb2e541832 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 14:41:10 -0400 Subject: [PATCH 32/46] git-gui: Automatically expand the line number column as needed After we finish reading a chunk of data from the file stream we know how many digits we need in the line number column to show the current maximum line number. If our line number column isn't wide enough, we should expand it out to the correct width. Any file over our default allowance of 5 digits (99,999 lines) is so large that the slight UI "glitch" when we widen the column out is trivial compared to the time it will take Git to fully do the annotations. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/blame.tcl b/lib/blame.tcl index 5561702683..0666dcadc1 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -422,12 +422,19 @@ method _read_file {fd} { $w_line insert end "$total_lines" linenumber $w_file insert end "$line" } + + set ln_wc [expr {[string length $total_lines] + 2}] + if {[$w_line cget -width] < $ln_wc} { + $w_line conf -width $ln_wc + } + $w_cgrp conf -state disabled $w_line conf -state disabled $w_file conf -state disabled if {[eof $fd]} { close $fd + _status $this set cmd {nice git blame -M -C --incremental} if {$commit eq {}} { From b61101579fdc647c14a54105a361b549a97c09a4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 14:45:35 -0400 Subject: [PATCH 33/46] git-gui: Remove unused commit_list from blame viewer This list used to store the commits in the order we received them in. I originally was using it to update the colors of the commit before and the commit after the current commit, but since that interface concept turned out to be horribly ugly and has been removed we no longer need this list. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 0666dcadc1..a01e22385b 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -25,8 +25,7 @@ field highlight_commit {} ; # sha1 of commit selected field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed -field commit_count 0 ; # number of commits in $commit_list -field commit_list {} ; # list of commit sha1 in receipt order +field commit_count 0 ; # number of commits loaded field order ; # array commit -> receipt order field header ; # array commit,key -> header field field line_commit ; # array line -> sha1 commit @@ -309,7 +308,6 @@ method _load {} { set total_lines 0 set blame_lines 0 set commit_count 0 - set commit_list {} array unset order array unset line_commit array unset line_file @@ -478,7 +476,6 @@ method _read_blame {fd} { set order($cmit) $commit_count incr commit_count - lappend commit_list $cmit } } elseif {[string match {filename *} $line]} { set file [string range $line 9 end] From c17c1751339bbb13e8927b0e98274cfee406821e Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 15:13:35 -0400 Subject: [PATCH 34/46] git-gui: Better document our blame variables The array variable "order" used to be used to tell us in what order each commit was received in. Recent changes have removed that need for an ordering and the "order" array is now just a boolean 'do we have that commit yet' flag. The colors were moved to fields, so they appear inside of the blame viewer instance. This keeps two different concurrently running blame viewers from stepping on each other's ordering of the colors in group_colors. Most of the other fields were moved around a little bit so that they are organized by major category and value lifespan. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 66 ++++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index a01e22385b..24965d9915 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -5,10 +5,13 @@ class blame { image create photo ::blame::img_back_arrow -data {R0lGODlhGAAYAIUAAPwCBEzKXFTSZIz+nGzmhGzqfGTidIT+nEzGXHTqhGzmfGzifFzadETCVES+VARWDFzWbHzyjAReDGTadFTOZDSyRDyyTCymPARaFGTedFzSbDy2TCyqRCyqPARaDAyCHES6VDy6VCyiPAR6HCSeNByWLARyFARiDARqFGTifARiFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAAAALAAAAAAYABgAAAajQIBwSCwaj8ikcsk0BppJwRPqHEypQwHBis0WDAdEFyBIKBaMAKLBdjQeSkFBYTBAIvgEoS6JmhUTEwIUDQ4VFhcMGEhyCgoZExoUaxsWHB0THkgfAXUGAhoBDSAVFR0XBnCbDRmgog0hpSIiDJpJIyEQhBUcJCIlwA22SSYVogknEg8eD82qSigdDSknY0IqJQXPYxIl1dZCGNvWw+Dm510GQQAh/mhDcmVhdGVkIGJ5IEJNUFRvR0lGIFBybyB2ZXJzaW9uIDIuNQ0KqSBEZXZlbENvciAxOTk3LDE5OTguIEFsbCByaWdodHMgcmVzZXJ2ZWQuDQpodHRwOi8vd3d3LmRldmVsY29yLmNvbQA7} -field commit ; # input commit to blame -field path ; # input filename to view in $commit +# Persistant data (survives loads) +# field history {}; # viewer history: {commit path} +field header ; # array commit,key -> header field +# Tk UI control paths +# field w ; # top window in this viewer field w_back ; # our back button field w_path ; # label showing the current file path @@ -19,37 +22,41 @@ field w_cmit ; # pane showing commit message field status ; # text variable bound to status bar field old_height ; # last known height of $w.file_pane -field current_fd {} ; # background process running -field highlight_line -1 ; # current line selected -field highlight_commit {} ; # sha1 of commit selected +# Tk UI colors +# +field active_color #c0edc5 +field group_colors { + #d6d6d6 + #e1e1e1 + #ececec +} + +# Current blame data; cleared/reset on each load +# +field commit ; # input commit to blame +field path ; # input filename to view in $commit + +field current_fd {} ; # background process running +field highlight_line -1 ; # current line selected +field highlight_commit {} ; # sha1 of commit selected field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed -field commit_count 0 ; # number of commits loaded -field order ; # array commit -> receipt order -field header ; # array commit,key -> header field +field have_commit ; # array commit -> 1 field line_commit ; # array line -> sha1 commit field line_file ; # array line -> file name -field r_commit ; # commit currently being parsed -field r_orig_line ; # original line number -field r_final_line ; # final line number -field r_line_count ; # lines in this region +field r_commit ; # commit currently being parsed +field r_orig_line ; # original line number +field r_final_line ; # final line number +field r_line_count ; # lines in this region -field tooltip_wm {} ; # Current tooltip toplevel, if open -field tooltip_timer {} ; # Current timer event for our tooltip -field tooltip_commit {} ; # Commit in tooltip -field tooltip_text {} ; # Text in current tooltip - -variable active_color #c0edc5 -variable group_colors { - #d6d6d6 - #e1e1e1 - #ececec -} +field tooltip_wm {} ; # Current tooltip toplevel, if open +field tooltip_timer {} ; # Current timer event for our tooltip +field tooltip_commit {} ; # Commit in tooltip +field tooltip_text {} ; # Text in current tooltip constructor new {i_commit i_path} { - variable active_color global cursor_ptr set commit $i_commit @@ -307,8 +314,7 @@ method _load {} { set highlight_commit {} set total_lines 0 set blame_lines 0 - set commit_count 0 - array unset order + array unset have_commit array unset line_commit array unset line_file @@ -449,8 +455,6 @@ method _read_file {fd} { } ifdeleted { catch {close $fd} } method _read_blame {fd} { - variable group_colors - if {$fd ne $current_fd} { catch {close $fd} return @@ -465,7 +469,7 @@ method _read_blame {fd} { set r_final_line $final_line set r_line_count $line_count - if {[catch {set g $order($cmit)}]} { + if {[catch {set g $have_commit($cmit)}]} { set bg [lindex $group_colors 0] set group_colors [lrange $group_colors 1 end] lappend group_colors $bg @@ -474,8 +478,7 @@ method _read_blame {fd} { $w_line tag conf g$cmit -background $bg $w_file tag conf g$cmit -background $bg - set order($cmit) $commit_count - incr commit_count + set have_commit($cmit) 1 } } elseif {[string match {filename *} $line]} { set file [string range $line 9 end] @@ -635,7 +638,6 @@ method _load_commit {pos} { method _showcommit {lno} { global repo_config - variable active_color if {$highlight_commit ne {}} { set cmit $highlight_commit From 14c4dfd3d1807885121b5e7b16610e335f824da4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 15:34:52 -0400 Subject: [PATCH 35/46] git-gui: Cleanup redundant column management in blame viewer The code to handle our three different text widgets is a bit on the messy side as we issue the same command on all three widgets one at a time. Adding (or removing) columns from the viewer is messy, as a lot of locations need to have the new column added into the sequence, or removed from it. We also now delete the tags we create for each commit when we switch to display another "commit:path" pair. This way the text viewer doesn't get bogged down with a massive number of tags as we traverse through history. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 121 +++++++++++++++++++------------------------------- 1 file changed, 46 insertions(+), 75 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 24965d9915..5fb3df4de7 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -15,6 +15,7 @@ field header ; # array commit,key -> header field field w ; # top window in this viewer field w_back ; # our back button field w_path ; # label showing the current file path +field w_columns ; # list of all column widgets in the viewer field w_line ; # text column: all line numbers field w_cgrp ; # text column: abbreviated commit SHA-1s field w_file ; # text column: actual file data @@ -39,6 +40,7 @@ field path ; # input filename to view in $commit field current_fd {} ; # background process running field highlight_line -1 ; # current line selected field highlight_commit {} ; # sha1 of commit selected +field old_bgcolor {} ; # background of current selection field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed @@ -164,24 +166,23 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.file_pane.out.sbx set] \ -font font_diff + set w_columns [list $w_cgrp $w_line $w_file] + scrollbar $w.file_pane.out.sbx \ -orient h \ -command [list $w_file xview] scrollbar $w.file_pane.out.sby \ -orient v \ - -command [list scrollbar2many [list \ - $w_line \ - $w_cgrp \ - $w_file \ - ] yview] - grid \ - $w_cgrp \ - $w_line \ - $w_file \ - $w.file_pane.out.sby \ - -sticky nsew - grid conf $w.file_pane.out.sbx -column 2 -sticky we - grid columnconfigure $w.file_pane.out 2 -weight 1 + -command [list scrollbar2many $w_columns yview] + eval grid $w_columns $w.file_pane.out.sby -sticky nsew + grid conf \ + $w.file_pane.out.sbx \ + -column [expr {[llength $w_columns] - 1}] \ + -sticky we + grid columnconfigure \ + $w.file_pane.out \ + [expr {[llength $w_columns] - 1}] \ + -weight 1 grid rowconfigure $w.file_pane.out 0 -weight 1 set w_cmit $w.file_pane.cm.t @@ -226,17 +227,10 @@ constructor new {i_commit i_path} { -label "Copy Commit" \ -command [cb _copycommit] - foreach i [list \ - $w_cgrp \ - $w_line \ - $w_file] { + foreach i $w_columns { $i conf -cursor $cursor_ptr - $i conf -yscrollcommand \ - [list many2scrollbar [list \ - $w_cgrp \ - $w_line \ - $w_file \ - ] yview $w.file_pane.out.sby] + $i conf -yscrollcommand [list many2scrollbar \ + $w_columns yview $w.file_pane.out.sby] bind $i " [cb _hide_tooltip] [cb _click $i @%x,%y] @@ -254,11 +248,7 @@ constructor new {i_commit i_path} { " } - foreach i [list \ - $w_cgrp \ - $w_line \ - $w_file \ - $w_cmit] { + foreach i [concat $w_columns $w_cmit] { bind $i {catch {%W yview scroll -1 units};break} bind $i {catch {%W yview scroll 1 units};break} bind $i {catch {%W xview scroll -1 units};break} @@ -310,6 +300,15 @@ method _load {} { set current_fd {} } + foreach i $w_columns { + $i conf -state normal + $i delete 0.0 end + foreach cmit [array names have_commit] { + $i tag delete g$cmit + } + $i conf -state disabled + } + set highlight_line -1 set highlight_commit {} set total_lines 0 @@ -317,18 +316,6 @@ method _load {} { array unset have_commit array unset line_commit array unset line_file - - $w_cgrp conf -state normal - $w_line conf -state normal - $w_file conf -state normal - - $w_cgrp delete 0.0 end - $w_line delete 0.0 end - $w_file delete 0.0 end - - $w_cgrp conf -state disabled - $w_line conf -state disabled - $w_file conf -state disabled } if {[winfo exists $w.status.c]} { @@ -410,17 +397,13 @@ method _read_file {fd} { return } - $w_cgrp conf -state normal - $w_line conf -state normal - $w_file conf -state normal + foreach i $w_columns {$i conf -state normal} while {[gets $fd line] >= 0} { regsub "\r\$" $line {} line incr total_lines if {$total_lines > 1} { - $w_cgrp insert end "\n" - $w_line insert end "\n" - $w_file insert end "\n" + foreach i $w_columns {$i insert end "\n"} } $w_line insert end "$total_lines" linenumber @@ -432,9 +415,7 @@ method _read_file {fd} { $w_line conf -width $ln_wc } - $w_cgrp conf -state disabled - $w_line conf -state disabled - $w_file conf -state disabled + foreach i $w_columns {$i conf -state disabled} if {[eof $fd]} { close $fd @@ -473,11 +454,9 @@ method _read_blame {fd} { set bg [lindex $group_colors 0] set group_colors [lrange $group_colors 1 end] lappend group_colors $bg - - $w_cgrp tag conf g$cmit -background $bg - $w_line tag conf g$cmit -background $bg - $w_file tag conf g$cmit -background $bg - + foreach i $w_columns { + $i tag conf g$cmit -background $bg + } set have_commit($cmit) 1 } } elseif {[string match {filename *} $line]} { @@ -531,13 +510,9 @@ method _read_blame {fd} { while {$n > 0} { set lno_e "$lno.0 lineend + 1c" if {![catch {set g g$line_commit($lno)}]} { - $w_cgrp tag remove g$g $lno.0 $lno_e - $w_line tag remove g$g $lno.0 $lno_e - $w_file tag remove g$g $lno.0 $lno_e - - $w_cgrp tag remove a$g $lno.0 $lno_e - $w_line tag remove a$g $lno.0 $lno_e - $w_file tag remove a$g $lno.0 $lno_e + foreach i $w_columns { + $i tag remove g$g $lno.0 $lno_e + } } set line_commit($lno) $cmit @@ -552,13 +527,9 @@ method _read_blame {fd} { $w_cgrp insert $lno.0 { |} } - $w_cgrp tag add g$cmit $lno.0 $lno_e - $w_line tag add g$cmit $lno.0 $lno_e - $w_file tag add g$cmit $lno.0 $lno_e - - $w_cgrp tag add a$cmit $lno.0 $lno_e - $w_line tag add a$cmit $lno.0 $lno_e - $w_file tag add a$cmit $lno.0 $lno_e + foreach i $w_columns { + $i tag add g$cmit $lno.0 $lno_e + } if {$highlight_line == -1} { if {[lindex [$w_file yview] 0] == 0} { @@ -640,10 +611,9 @@ method _showcommit {lno} { global repo_config if {$highlight_commit ne {}} { - set cmit $highlight_commit - $w_cgrp tag conf a$cmit -background {} - $w_line tag conf a$cmit -background {} - $w_file tag conf a$cmit -background {} + foreach i $w_columns { + $i tag conf g$highlight_commit -background $old_bgcolor + } } $w_cmit conf -state normal @@ -652,9 +622,10 @@ method _showcommit {lno} { set cmit {} $w_cmit insert end "Loading annotation..." } else { - $w_cgrp tag conf a$cmit -background $active_color - $w_line tag conf a$cmit -background $active_color - $w_file tag conf a$cmit -background $active_color + set old_bgcolor [$w_file tag cget g$cmit -background] + foreach i $w_columns { + $i tag conf g$cmit -background $active_color + } set author_name {} set author_email {} From 2f85b7e4b421ab032cc2342808640479a988277f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 16:01:43 -0400 Subject: [PATCH 36/46] git-gui: Switch internal blame structure to Tcl lists The Tcl list datatype is significantly faster to work with than the array type, especially if our indexes are a consecutive set of numbers, like say line numbers in a file. This rather large change reorganizes the internal data structure of the blame viewer to use a proper Tcl list for the annotation information about a line. Each line is given its own list within the larger line_data list, where the indexes correspond to various facts about that particular line. The interface does seem to be more responsive this way, with less time required by Tcl to process blame, and to switch to another version of the same file. It could just be a placebo effect, but either way most Tcl experts perfer lists for this type of work over arrays. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 69 +++++++++++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 30 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 5fb3df4de7..d8d27c9cbf 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -45,8 +45,7 @@ field old_bgcolor {} ; # background of current selection field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed field have_commit ; # array commit -> 1 -field line_commit ; # array line -> sha1 commit -field line_file ; # array line -> file name +field line_data ; # list of {commit origfile origline} field r_commit ; # commit currently being parsed field r_orig_line ; # original line number @@ -314,8 +313,6 @@ method _load {} { set total_lines 0 set blame_lines 0 array unset have_commit - array unset line_commit - array unset line_file } if {[winfo exists $w.status.c]} { @@ -338,6 +335,12 @@ method _load {} { } lappend history [list $commit $path] + # Index 0 is always empty. There is never line 0 as + # we use only 1 based lines, as that matches both with + # git-blame output and with Tk's text widget. + # + set line_data [list [list]] + set status "Loading $commit:[escape_path $path]..." $w_path conf -text [escape_path $path] if {$commit eq {}} { @@ -401,6 +404,7 @@ method _read_file {fd} { while {[gets $fd line] >= 0} { regsub "\r\$" $line {} line incr total_lines + lappend line_data {} if {$total_lines > 1} { foreach i $w_columns {$i insert end "\n"} @@ -499,24 +503,22 @@ method _read_blame {fd} { set first_lno $lno while { - ![catch {set ncmit $line_commit([expr {$first_lno - 1}])}] - && ![catch {set nfile $line_file([expr {$first_lno - 1}])}] - && $ncmit eq $cmit - && $nfile eq $file + $first_lno > 1 + && $cmit eq [lindex $line_data [expr {$first_lno - 1}] 0] + && $file eq [lindex $line_data [expr {$first_lno - 1}] 1] } { incr first_lno -1 } while {$n > 0} { set lno_e "$lno.0 lineend + 1c" - if {![catch {set g g$line_commit($lno)}]} { + if {[lindex $line_data $lno] ne {}} { + set g [lindex $line_data $lno 0] foreach i $w_columns { $i tag remove g$g $lno.0 $lno_e } } - - set line_commit($lno) $cmit - set line_file($lno) $file + lset line_data $lno [list $cmit $file] $w_cgrp delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { @@ -546,10 +548,8 @@ method _read_blame {fd} { } while { - ![catch {set ncmit $line_commit($lno)}] - && ![catch {set nfile $line_file($lno)}] - && $ncmit eq $cmit - && $nfile eq $file + $cmit eq [lindex $line_data $lno 0] + && $file eq [lindex $line_data $lno 1] } { $w_cgrp delete $lno.0 "$lno.0 lineend" @@ -599,12 +599,12 @@ method _click {cur_w pos} { method _load_commit {pos} { set lno [lindex [split [$w_cgrp index $pos] .] 0] - if {[catch {set cmit $line_commit($lno)}]} return - if {[catch {set file $line_file($lno) }]} return - - set commit $cmit - set path $file - _load $this + set dat [lindex $line_data $lno] + if {$dat ne {}} { + set commit [lindex $dat 0] + set path [lindex $dat 1] + _load $this + } } method _showcommit {lno} { @@ -618,10 +618,15 @@ method _showcommit {lno} { $w_cmit conf -state normal $w_cmit delete 0.0 end - if {[catch {set cmit $line_commit($lno)}]} { + + set dat [lindex $line_data $lno] + if {$dat eq {}} { set cmit {} $w_cmit insert end "Loading annotation..." } else { + set cmit [lindex $dat 0] + set file [lindex $dat 1] + set old_bgcolor [$w_file tag cget g$cmit -background] foreach i $w_columns { $i tag conf g$cmit -background $active_color @@ -682,9 +687,9 @@ method _showcommit {lno} { $w_cmit insert end "$committer_name $committer_email" header_val $w_cmit insert end "$committer_time\n" header_val - if {$line_file($lno) ne $path} { + if {$file ne $path} { $w_cmit insert end "Original File:\t" header_key - $w_cmit insert end "[escape_path $line_file($lno)]\n" header_val + $w_cmit insert end "[escape_path $file]\n" header_val } $w_cmit insert end "\n$msg" @@ -702,21 +707,24 @@ method _showcommit {lno} { method _copycommit {} { set pos @$::cursorX,$::cursorY set lno [lindex [split [$::cursorW index $pos] .] 0] - if {![catch {set commit $line_commit($lno)}]} { + set dat [lindex $line_data $lno] + if {$dat ne {}} { clipboard clear clipboard append \ -format STRING \ -type STRING \ - -- $commit + -- [lindex $dat 0] } } method _show_tooltip {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] - if {[catch {set cmit $line_commit($lno)}]} { + set dat [lindex $line_data $lno] + if {$dat eq {}} { _hide_tooltip $this return } + set cmit [lindex $dat 0] if {$cmit eq $highlight_commit} { _hide_tooltip $this @@ -745,7 +753,9 @@ method _open_tooltip {cur_w} { [expr {$pos_x - [winfo rootx $cur_w]}] \ [expr {$pos_y - [winfo rooty $cur_w]}]] ,] set lno [lindex [split [$cur_w index $pos] .] 0] - set cmit $line_commit($lno) + set dat [lindex $line_data $lno] + set cmit [lindex $dat 0] + set file [lindex $dat 1] set author_name {} set author_email {} @@ -775,7 +785,6 @@ method _open_tooltip {cur_w} { $author_name $author_email $author_time $summary" - set file $line_file($lno) if {$file ne $path} { append tooltip_text " From c5db65aef3b4268adbadc8019ecbd7d3fdc374e8 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 16:03:52 -0400 Subject: [PATCH 37/46] git-gui: Label the uncommitted blame history entry If the user runs the blame viewer on a working directory file instead of a specific commit-ish then we have no value for the commit SHA1 or the summary line; this causes the history menu to get an empty entry at the very bottom. We now look for this odd case and call the meny entry "Working Directory". Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/blame.tcl b/lib/blame.tcl index d8d27c9cbf..0561fb491d 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -370,6 +370,8 @@ method _history_menu {} { if {[regexp {^[0-9a-f]{40}$} $c]} { set t [string range $c 0 8]... + } elseif {$c eq {}} { + set t {Working Directory} } else { set t $c } From fc816d7b857a5033982b421a384f7b2d932f57e6 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 23:26:24 -0400 Subject: [PATCH 38/46] git-gui: Rename fields in blame viewer to better descriptions Calling the commit message pane $w_cmit is a tad confusing when we also have the $w_cgrp column that shows the abbreviated SHA-1s. So w_cmit -> w_cviewer, as it is the "commit viewer"; and w_cgrp -> w_amov as it is the "annotated commit + move tracking" column. Also changed line_data -> amov_data, as that list is exactly the results shown in w_amov. Why call the column "move tracking"? Because this column holds data from "git blame -M -C". I'm considering adding an additional column that holds the data from "git blame" without -M/-C, showing who did the copy/move, and when they did it. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 116 +++++++++++++++++++++++++------------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 0561fb491d..0531450820 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -17,9 +17,9 @@ field w_back ; # our back button field w_path ; # label showing the current file path field w_columns ; # list of all column widgets in the viewer field w_line ; # text column: all line numbers -field w_cgrp ; # text column: abbreviated commit SHA-1s +field w_amov ; # text column: annotations + move tracking field w_file ; # text column: actual file data -field w_cmit ; # pane showing commit message +field w_cviewer ; # pane showing commit message field status ; # text variable bound to status bar field old_height ; # last known height of $w.file_pane @@ -45,7 +45,7 @@ field old_bgcolor {} ; # background of current selection field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed field have_commit ; # array commit -> 1 -field line_data ; # list of {commit origfile origline} +field amov_data ; # list of {commit origfile origline} field r_commit ; # commit currently being parsed field r_orig_line ; # original line number @@ -133,8 +133,8 @@ constructor new {i_commit i_path} { -font font_diff $w_line tag conf linenumber -justify right -rmargin 5 - set w_cgrp $w.file_pane.out.commit_t - text $w_cgrp \ + set w_amov $w.file_pane.out.amove_t + text $w_amov \ -takefocus 0 \ -highlightthickness 0 \ -padx 0 -pady 0 \ @@ -144,11 +144,11 @@ constructor new {i_commit i_path} { -height 40 \ -width 4 \ -font font_diff - $w_cgrp tag conf curr_commit - $w_cgrp tag conf prior_commit \ + $w_amov tag conf curr_commit + $w_amov tag conf prior_commit \ -foreground blue \ -underline 1 - $w_cgrp tag bind prior_commit \ + $w_amov tag bind prior_commit \ \ "[cb _load_commit @%x,%y];break" @@ -165,7 +165,7 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.file_pane.out.sbx set] \ -font font_diff - set w_columns [list $w_cgrp $w_line $w_file] + set w_columns [list $w_amov $w_line $w_file] scrollbar $w.file_pane.out.sbx \ -orient h \ @@ -184,8 +184,8 @@ constructor new {i_commit i_path} { -weight 1 grid rowconfigure $w.file_pane.out 0 -weight 1 - set w_cmit $w.file_pane.cm.t - text $w_cmit \ + set w_cviewer $w.file_pane.cm.t + text $w_cviewer \ -background white -borderwidth 0 \ -state disabled \ -wrap none \ @@ -194,23 +194,23 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.file_pane.cm.sbx set] \ -yscrollcommand [list $w.file_pane.cm.sby set] \ -font font_diff - $w_cmit tag conf header_key \ + $w_cviewer tag conf header_key \ -tabs {3c} \ -background $active_color \ -font font_uibold - $w_cmit tag conf header_val \ + $w_cviewer tag conf header_val \ -background $active_color \ -font font_ui - $w_cmit tag raise sel + $w_cviewer tag raise sel scrollbar $w.file_pane.cm.sbx \ -orient h \ - -command [list $w_cmit xview] + -command [list $w_cviewer xview] scrollbar $w.file_pane.cm.sby \ -orient v \ - -command [list $w_cmit yview] + -command [list $w_cviewer yview] pack $w.file_pane.cm.sby -side right -fill y pack $w.file_pane.cm.sbx -side bottom -fill x - pack $w_cmit -expand 1 -fill both + pack $w_cviewer -expand 1 -fill both frame $w.status \ -borderwidth 1 \ @@ -247,7 +247,7 @@ constructor new {i_commit i_path} { " } - foreach i [concat $w_columns $w_cmit] { + foreach i [concat $w_columns $w_cviewer] { bind $i {catch {%W yview scroll -1 units};break} bind $i {catch {%W yview scroll 1 units};break} bind $i {catch {%W xview scroll -1 units};break} @@ -260,7 +260,7 @@ constructor new {i_commit i_path} { bind $i {catch {%W yview scroll 1 pages};break} } - bind $w_cmit [list focus $w_cmit] + bind $w_cviewer [list focus $w_cviewer] bind $top [list focus $top] bind $w_file [list delete_this $this] @@ -339,7 +339,7 @@ method _load {} { # we use only 1 based lines, as that matches both with # git-blame output and with Tk's text widget. # - set line_data [list [list]] + set amov_data [list [list]] set status "Loading $commit:[escape_path $path]..." $w_path conf -text [escape_path $path] @@ -406,7 +406,7 @@ method _read_file {fd} { while {[gets $fd line] >= 0} { regsub "\r\$" $line {} line incr total_lines - lappend line_data {} + lappend amov_data {} if {$total_lines > 1} { foreach i $w_columns {$i insert end "\n"} @@ -447,7 +447,7 @@ method _read_blame {fd} { return } - $w_cgrp conf -state normal + $w_amov conf -state normal while {[gets $fd line] >= 0} { if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ cmit original_line final_line line_count]} { @@ -506,29 +506,29 @@ method _read_blame {fd} { set first_lno $lno while { $first_lno > 1 - && $cmit eq [lindex $line_data [expr {$first_lno - 1}] 0] - && $file eq [lindex $line_data [expr {$first_lno - 1}] 1] + && $cmit eq [lindex $amov_data [expr {$first_lno - 1}] 0] + && $file eq [lindex $amov_data [expr {$first_lno - 1}] 1] } { incr first_lno -1 } while {$n > 0} { set lno_e "$lno.0 lineend + 1c" - if {[lindex $line_data $lno] ne {}} { - set g [lindex $line_data $lno 0] + if {[lindex $amov_data $lno] ne {}} { + set g [lindex $amov_data $lno 0] foreach i $w_columns { $i tag remove g$g $lno.0 $lno_e } } - lset line_data $lno [list $cmit $file] + lset amov_data $lno [list $cmit $file] - $w_cgrp delete $lno.0 "$lno.0 lineend" + $w_amov delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_cgrp insert $lno.0 $commit_abbr $commit_type + $w_amov insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { - $w_cgrp insert $lno.0 $author_abbr + $w_amov insert $lno.0 $author_abbr } else { - $w_cgrp insert $lno.0 { |} + $w_amov insert $lno.0 { |} } foreach i $w_columns { @@ -550,17 +550,17 @@ method _read_blame {fd} { } while { - $cmit eq [lindex $line_data $lno 0] - && $file eq [lindex $line_data $lno 1] + $cmit eq [lindex $amov_data $lno 0] + && $file eq [lindex $amov_data $lno 1] } { - $w_cgrp delete $lno.0 "$lno.0 lineend" + $w_amov delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_cgrp insert $lno.0 $commit_abbr $commit_type + $w_amov insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { - $w_cgrp insert $lno.0 $author_abbr + $w_amov insert $lno.0 $author_abbr } else { - $w_cgrp insert $lno.0 { |} + $w_amov insert $lno.0 { |} } incr lno } @@ -569,7 +569,7 @@ method _read_blame {fd} { set header($r_commit,$key) $data } } - $w_cgrp conf -state disabled + $w_amov conf -state disabled if {[eof $fd]} { close $fd @@ -600,8 +600,8 @@ method _click {cur_w pos} { } method _load_commit {pos} { - set lno [lindex [split [$w_cgrp index $pos] .] 0] - set dat [lindex $line_data $lno] + set lno [lindex [split [$w_amov index $pos] .] 0] + set dat [lindex $amov_data $lno] if {$dat ne {}} { set commit [lindex $dat 0] set path [lindex $dat 1] @@ -618,13 +618,13 @@ method _showcommit {lno} { } } - $w_cmit conf -state normal - $w_cmit delete 0.0 end + $w_cviewer conf -state normal + $w_cviewer delete 0.0 end - set dat [lindex $line_data $lno] + set dat [lindex $amov_data $lno] if {$dat eq {}} { set cmit {} - $w_cmit insert end "Loading annotation..." + $w_cviewer insert end "Loading annotation..." } else { set cmit [lindex $dat 0] set file [lindex $dat 1] @@ -680,23 +680,23 @@ method _showcommit {lno} { set header($cmit,message) $msg } - $w_cmit insert end "commit $cmit\n" header_key - $w_cmit insert end "Author:\t" header_key - $w_cmit insert end "$author_name $author_email" header_val - $w_cmit insert end "$author_time\n" header_val + $w_cviewer insert end "commit $cmit\n" header_key + $w_cviewer insert end "Author:\t" header_key + $w_cviewer insert end "$author_name $author_email" header_val + $w_cviewer insert end " $author_time\n" header_val - $w_cmit insert end "Committer:\t" header_key - $w_cmit insert end "$committer_name $committer_email" header_val - $w_cmit insert end "$committer_time\n" header_val + $w_cviewer insert end "Committer:\t" header_key + $w_cviewer insert end "$committer_name $committer_email" header_val + $w_cviewer insert end " $committer_time\n" header_val if {$file ne $path} { - $w_cmit insert end "Original File:\t" header_key - $w_cmit insert end "[escape_path $file]\n" header_val + $w_cviewer insert end "Original File:\t" header_key + $w_cviewer insert end "[escape_path $file]\n" header_val } - $w_cmit insert end "\n$msg" + $w_cviewer insert end "\n$msg" } - $w_cmit conf -state disabled + $w_cviewer conf -state disabled set highlight_line $lno set highlight_commit $cmit @@ -709,7 +709,7 @@ method _showcommit {lno} { method _copycommit {} { set pos @$::cursorX,$::cursorY set lno [lindex [split [$::cursorW index $pos] .] 0] - set dat [lindex $line_data $lno] + set dat [lindex $amov_data $lno] if {$dat ne {}} { clipboard clear clipboard append \ @@ -721,7 +721,7 @@ method _copycommit {} { method _show_tooltip {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] - set dat [lindex $line_data $lno] + set dat [lindex $amov_data $lno] if {$dat eq {}} { _hide_tooltip $this return @@ -755,7 +755,7 @@ method _open_tooltip {cur_w} { [expr {$pos_x - [winfo rootx $cur_w]}] \ [expr {$pos_y - [winfo rooty $cur_w]}]] ,] set lno [lindex [split [$cur_w index $pos] .] 0] - set dat [lindex $line_data $lno] + set dat [lindex $amov_data $lno] set cmit [lindex $dat 0] set file [lindex $dat 1] From debcd0fd02bda82e3c81e6739bcb26135ac00b85 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 17:15:56 -0400 Subject: [PATCH 39/46] git-gui: Display the "Loading annotation..." message in italic If the user clicks on a line region that we haven't yet received an annotation for from git-blame we show them "Loading annotation". But I don't want the user to confuse this loading message with a commit whose first line is "Loading annotation" and think we messed up our display somehow. Since we never use italics for anything else, I'm going with the idea that italic slant can be used to show data is missing/elided out at the time being. Signed-off-by: Shawn O. Pearce --- git-gui.sh | 5 +++++ lib/blame.tcl | 5 ++++- lib/option.tcl | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/git-gui.sh b/git-gui.sh index 6a5e2dc160..dfb4b955eb 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -1024,6 +1024,7 @@ proc incr_font_size {font {amt 1}} { incr sz $amt font configure $font -size $sz font configure ${font}bold -size $sz + font configure ${font}italic -size $sz } ###################################################################### @@ -1216,8 +1217,10 @@ catch { destroy .dummy } +font create font_uiitalic font create font_uibold font create font_diffbold +font create font_diffitalic foreach class {Button Checkbutton Entry Label Labelframe Listbox Menu Message @@ -1249,8 +1252,10 @@ proc apply_config {} { } foreach {cn cv} [font configure $font] { font configure ${font}bold $cn $cv + font configure ${font}italic $cn $cv } font configure ${font}bold -weight bold + font configure ${font}italic -slant italic } } diff --git a/lib/blame.tcl b/lib/blame.tcl index 0531450820..0641ea6d37 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -194,6 +194,9 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.file_pane.cm.sbx set] \ -yscrollcommand [list $w.file_pane.cm.sby set] \ -font font_diff + $w_cviewer tag conf still_loading \ + -font font_uiitalic \ + -justify center $w_cviewer tag conf header_key \ -tabs {3c} \ -background $active_color \ @@ -624,7 +627,7 @@ method _showcommit {lno} { set dat [lindex $amov_data $lno] if {$dat eq {}} { set cmit {} - $w_cviewer insert end "Loading annotation..." + $w_cviewer insert end "Loading annotation..." still_loading } else { set cmit [lindex $dat 0] set file [lindex $dat 1] diff --git a/lib/option.tcl b/lib/option.tcl index 11dd9be6b9..b29e14e64d 100644 --- a/lib/option.tcl +++ b/lib/option.tcl @@ -15,6 +15,9 @@ proc save_config {} { font configure ${font}bold \ -family $global_config_new(gui.$font^^family) \ -size $global_config_new(gui.$font^^size) + font configure ${font}italic \ + -family $global_config_new(gui.$font^^family) \ + -size $global_config_new(gui.$font^^size) set global_config_new(gui.$name) [font configure $font] unset global_config_new(gui.$font^^family) unset global_config_new(gui.$font^^size) From 172c92b47512adc45516cd72e607bea55b2414b4 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 18:21:18 -0400 Subject: [PATCH 40/46] 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 --- lib/blame.tcl | 176 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 113 insertions(+), 63 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 0641ea6d37..54a1ce5b45 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -18,6 +18,7 @@ field w_path ; # label showing the current file path field w_columns ; # list of all column widgets in the viewer field w_line ; # text column: all line numbers field w_amov ; # text column: annotations + move tracking +field w_asim ; # text column: annotations (simple computation) field w_file ; # text column: actual file data field w_cviewer ; # pane showing commit message field status ; # text variable bound to status bar @@ -39,6 +40,7 @@ field path ; # input filename to view in $commit field current_fd {} ; # background process running field highlight_line -1 ; # current line selected +field highlight_column {} ; # current commit column selected field highlight_commit {} ; # sha1 of commit selected field old_bgcolor {} ; # background of current selection @@ -46,6 +48,7 @@ field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed field have_commit ; # array commit -> 1 field amov_data ; # list of {commit origfile origline} +field asim_data ; # list of {commit origfile origline} field r_commit ; # commit currently being parsed field r_orig_line ; # original line number @@ -142,15 +145,32 @@ constructor new {i_commit i_path} { -state disabled \ -wrap none \ -height 40 \ - -width 4 \ + -width 5 \ -font font_diff + $w_amov tag conf author_abbr -justify right -rmargin 5 $w_amov tag conf curr_commit - $w_amov tag conf prior_commit \ - -foreground blue \ - -underline 1 + $w_amov tag conf prior_commit -foreground blue -underline 1 $w_amov tag bind prior_commit \ \ - "[cb _load_commit @%x,%y];break" + "[cb _load_commit $w_amov @amov_data @%x,%y];break" + + set w_asim $w.file_pane.out.asimple_t + text $w_asim \ + -takefocus 0 \ + -highlightthickness 0 \ + -padx 0 -pady 0 \ + -background white -borderwidth 0 \ + -state disabled \ + -wrap none \ + -height 40 \ + -width 4 \ + -font font_diff + $w_asim tag conf author_abbr -justify right + $w_asim tag conf curr_commit + $w_asim tag conf prior_commit -foreground blue -underline 1 + $w_asim tag bind prior_commit \ + \ + "[cb _load_commit $w_asim @asim_data @%x,%y];break" set w_file $w.file_pane.out.file_t text $w_file \ @@ -165,7 +185,7 @@ constructor new {i_commit i_path} { -xscrollcommand [list $w.file_pane.out.sbx set] \ -font font_diff - set w_columns [list $w_amov $w_line $w_file] + set w_columns [list $w_amov $w_asim $w_line $w_file] scrollbar $w.file_pane.out.sbx \ -orient h \ @@ -312,9 +332,9 @@ method _load {} { } set highlight_line -1 + set highlight_column {} set highlight_commit {} set total_lines 0 - set blame_lines 0 array unset have_commit } @@ -343,6 +363,7 @@ method _load {} { # git-blame output and with Tk's text widget. # set amov_data [list [list]] + set asim_data [list [list]] set status "Loading $commit:[escape_path $path]..." $w_path conf -text [escape_path $path] @@ -410,6 +431,7 @@ method _read_file {fd} { regsub "\r\$" $line {} line incr total_lines lappend amov_data {} + lappend asim_data {} if {$total_lines > 1} { foreach i $w_columns {$i insert end "\n"} @@ -428,29 +450,37 @@ method _read_file {fd} { if {[eof $fd]} { close $fd - - _status $this - set cmd {nice git blame -M -C --incremental} - if {$commit eq {}} { - lappend cmd --contents $path - } else { - lappend cmd $commit - } - lappend cmd -- $path - set fd [open "| $cmd" r] - fconfigure $fd -blocking 0 -translation lf -encoding binary - fileevent $fd readable [cb _read_blame $fd] - set current_fd $fd + _exec_blame $this $w_asim @asim_data [list] {} } } ifdeleted { catch {close $fd} } -method _read_blame {fd} { +method _exec_blame {cur_w cur_d options cur_s} { + set cmd [list nice git blame] + set cmd [concat $cmd $options] + lappend cmd --incremental + if {$commit eq {}} { + lappend cmd --contents $path + } else { + lappend cmd $commit + } + lappend cmd -- $path + set fd [open "| $cmd" r] + fconfigure $fd -blocking 0 -translation lf -encoding binary + fileevent $fd readable [cb _read_blame $fd $cur_w $cur_d $cur_s] + set current_fd $fd + set blame_lines 0 + _status $this $cur_s +} + +method _read_blame {fd cur_w cur_d cur_s} { + upvar #0 $cur_d line_data + if {$fd ne $current_fd} { catch {close $fd} return } - $w_amov conf -state normal + $cur_w conf -state normal while {[gets $fd line] >= 0} { if {[regexp {^([a-z0-9]{40}) (\d+) (\d+) (\d+)$} $line line \ cmit original_line final_line line_count]} { @@ -482,7 +512,7 @@ method _read_blame {fd} { set commit_type curr_commit } else { set commit_type prior_commit - set commit_abbr [string range $cmit 0 4] + set commit_abbr [string range $cmit 0 3] } set author_abbr {} @@ -500,51 +530,50 @@ method _read_blame {fd} { set author_abbr { |} } else { set author_abbr [string range $author_abbr 0 3] - while {[string length $author_abbr] < 4} { - set author_abbr " $author_abbr" - } } unset a_name set first_lno $lno while { $first_lno > 1 - && $cmit eq [lindex $amov_data [expr {$first_lno - 1}] 0] - && $file eq [lindex $amov_data [expr {$first_lno - 1}] 1] + && $cmit eq [lindex $line_data [expr {$first_lno - 1}] 0] + && $file eq [lindex $line_data [expr {$first_lno - 1}] 1] } { incr first_lno -1 } while {$n > 0} { set lno_e "$lno.0 lineend + 1c" - if {[lindex $amov_data $lno] ne {}} { - set g [lindex $amov_data $lno 0] + if {[lindex $line_data $lno] ne {}} { + set g [lindex $line_data $lno 0] foreach i $w_columns { $i tag remove g$g $lno.0 $lno_e } } - lset amov_data $lno [list $cmit $file] + lset line_data $lno [list $cmit $file] - $w_amov delete $lno.0 "$lno.0 lineend" + $cur_w delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_amov insert $lno.0 $commit_abbr $commit_type + $cur_w insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { - $w_amov insert $lno.0 $author_abbr + $cur_w insert $lno.0 $author_abbr author_abbr } else { - $w_amov insert $lno.0 { |} + $cur_w insert $lno.0 { |} } foreach i $w_columns { $i tag add g$cmit $lno.0 $lno_e } - if {$highlight_line == -1} { - if {[lindex [$w_file yview] 0] == 0} { + if {$highlight_column eq $cur_w} { + if {$highlight_line == -1 + && [lindex [$w_file yview] 0] == 0} { $w_file see $lno.0 - _showcommit $this $lno + set highlight_line $lno + } + if {$highlight_line == $lno} { + _showcommit $this $cur_w $lno } - } elseif {$highlight_line == $lno} { - _showcommit $this $lno } incr n -1 @@ -553,17 +582,17 @@ method _read_blame {fd} { } while { - $cmit eq [lindex $amov_data $lno 0] - && $file eq [lindex $amov_data $lno 1] + $cmit eq [lindex $line_data $lno 0] + && $file eq [lindex $line_data $lno 1] } { - $w_amov delete $lno.0 "$lno.0 lineend" + $cur_w delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { - $w_amov insert $lno.0 $commit_abbr $commit_type + $cur_w insert $lno.0 $commit_abbr $commit_type } elseif {$lno == [expr {$first_lno + 1}]} { - $w_amov insert $lno.0 $author_abbr + $cur_w insert $lno.0 $author_abbr author_abbr } else { - $w_amov insert $lno.0 { |} + $cur_w insert $lno.0 { |} } incr lno } @@ -572,39 +601,45 @@ method _read_blame {fd} { set header($r_commit,$key) $data } } - $w_amov conf -state disabled + $cur_w conf -state disabled if {[eof $fd]} { close $fd - set current_fd {} - set status {Annotation complete.} - destroy $w.status.c + if {$cur_w eq $w_asim} { + _exec_blame $this $w_amov @amov_data \ + [list -M -C -C] \ + { move/copy tracking} + } else { + set current_fd {} + set status {Annotation complete.} + destroy $w.status.c + } } else { - _status $this + _status $this $cur_s } } ifdeleted { catch {close $fd} } -method _status {} { +method _status {cur_s} { set have $blame_lines set total $total_lines set pdone 0 if {$total} {set pdone [expr {100 * $have / $total}]} set status [format \ - "Loading annotations... %i of %i lines annotated (%2i%%)" \ - $have $total $pdone] + "Loading%s annotations... %i of %i lines annotated (%2i%%)" \ + $cur_s $have $total $pdone] $w.status.c coords bar 0 0 $pdone 20 } method _click {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] - if {$lno eq {}} return - _showcommit $this $lno + _showcommit $this $cur_w $lno } -method _load_commit {pos} { - set lno [lindex [split [$w_amov index $pos] .] 0] - set dat [lindex $amov_data $lno] +method _load_commit {cur_w cur_d pos} { + upvar #0 $cur_d line_data + set lno [lindex [split [$cur_w index $pos] .] 0] + set dat [lindex $line_data $lno] if {$dat ne {}} { set commit [lindex $dat 0] set path [lindex $dat 1] @@ -612,7 +647,7 @@ method _load_commit {pos} { } } -method _showcommit {lno} { +method _showcommit {cur_w lno} { global repo_config if {$highlight_commit ne {}} { @@ -621,10 +656,17 @@ method _showcommit {lno} { } } + if {$cur_w eq $w_amov} { + set dat [lindex $amov_data $lno] + set highlight_column $w_amov + } else { + set dat [lindex $asim_data $lno] + set highlight_column $w_asim + } + $w_cviewer conf -state normal $w_cviewer delete 0.0 end - set dat [lindex $amov_data $lno] if {$dat eq {}} { set cmit {} $w_cviewer insert end "Loading annotation..." still_loading @@ -724,7 +766,11 @@ method _copycommit {} { method _show_tooltip {cur_w pos} { set lno [lindex [split [$cur_w index $pos] .] 0] - set dat [lindex $amov_data $lno] + if {$cur_w eq $w_amov} { + set dat [lindex $amov_data $lno] + } else { + set dat [lindex $asim_data $lno] + } if {$dat eq {}} { _hide_tooltip $this return @@ -758,7 +804,11 @@ method _open_tooltip {cur_w} { [expr {$pos_x - [winfo rootx $cur_w]}] \ [expr {$pos_y - [winfo rooty $cur_w]}]] ,] set lno [lindex [split [$cur_w index $pos] .] 0] - set dat [lindex $amov_data $lno] + if {$cur_w eq $w_amov} { + set dat [lindex $amov_data $lno] + } else { + set dat [lindex $asim_data $lno] + } set cmit [lindex $dat 0] set file [lindex $dat 1] From 383d4e0f8b72f739c16ef7d723a134d59a0a0c2f Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sat, 2 Jun 2007 19:03:55 -0400 Subject: [PATCH 41/46] git-gui: Display both commits in our tooltips If we have commit data from both the simple blame and the rename/move tracking blame and they differ than there is a bigger story to tell. We now include data from both commits so that the user can see that this link as moved, who moved it, and where it originated from. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 130 ++++++++++++++++++++++++++++---------------------- 1 file changed, 72 insertions(+), 58 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 54a1ce5b45..f0dafff18e 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -56,9 +56,9 @@ field r_final_line ; # final line number field r_line_count ; # lines in this region field tooltip_wm {} ; # Current tooltip toplevel, if open +field tooltip_t {} ; # Text widget in $tooltip_wm field tooltip_timer {} ; # Current timer event for our tooltip -field tooltip_commit {} ; # Commit in tooltip -field tooltip_text {} ; # Text in current tooltip +field tooltip_commit {} ; # Commit(s) in tooltip constructor new {i_commit i_path} { global cursor_ptr @@ -653,6 +653,7 @@ method _showcommit {cur_w lno} { if {$highlight_commit ne {}} { foreach i $w_columns { $i tag conf g$highlight_commit -background $old_bgcolor + $i tag lower g$highlight_commit } } @@ -677,6 +678,7 @@ method _showcommit {cur_w lno} { set old_bgcolor [$w_file tag cget g$cmit -background] foreach i $w_columns { $i tag conf g$cmit -background $active_color + $i tag raise g$cmit } set author_name {} @@ -746,7 +748,7 @@ method _showcommit {cur_w lno} { set highlight_line $lno set highlight_commit $cmit - if {$highlight_commit eq $tooltip_commit} { + if {[lsearch -exact $tooltip_commit $highlight_commit] != -1} { _hide_tooltip $this } } @@ -765,26 +767,7 @@ method _copycommit {} { } method _show_tooltip {cur_w pos} { - set lno [lindex [split [$cur_w index $pos] .] 0] - if {$cur_w eq $w_amov} { - set dat [lindex $amov_data $lno] - } else { - set dat [lindex $asim_data $lno] - } - if {$dat eq {}} { - _hide_tooltip $this - return - } - set cmit [lindex $dat 0] - - if {$cmit eq $highlight_commit} { - _hide_tooltip $this - return - } - - if {$cmit eq $tooltip_commit} { - _position_tooltip $this - } elseif {$tooltip_wm ne {}} { + if {$tooltip_wm ne {}} { _open_tooltip $this $cur_w } elseif {$tooltip_timer eq {}} { set tooltip_timer [after 1000 [cb _open_tooltip $cur_w]] @@ -800,70 +783,101 @@ method _open_tooltip {cur_w} { return } + if {$tooltip_wm ne "$cur_w.tooltip"} { + _hide_tooltip $this + + set tooltip_wm [toplevel $cur_w.tooltip -borderwidth 1] + wm overrideredirect $tooltip_wm 1 + wm transient $tooltip_wm [winfo toplevel $cur_w] + set tooltip_t $tooltip_wm.label + text $tooltip_t \ + -takefocus 0 \ + -highlightthickness 0 \ + -relief flat \ + -borderwidth 0 \ + -wrap none \ + -background lightyellow \ + -foreground black + $tooltip_t tag conf section_header -font font_uibold + pack $tooltip_t + } else { + $tooltip_t conf -state normal + $tooltip_t delete 0.0 end + } + set pos @[join [list \ [expr {$pos_x - [winfo rootx $cur_w]}] \ [expr {$pos_y - [winfo rooty $cur_w]}]] ,] set lno [lindex [split [$cur_w index $pos] .] 0] if {$cur_w eq $w_amov} { set dat [lindex $amov_data $lno] + set org {} } else { set dat [lindex $asim_data $lno] + set org [lindex $amov_data $lno] } + set cmit [lindex $dat 0] - set file [lindex $dat 1] + set tooltip_commit [list $cmit] set author_name {} - set author_email {} + set summary {} set author_time {} catch {set author_name $header($cmit,author)} - catch {set author_email $header($cmit,author-mail)} + catch {set summary $header($cmit,summary)} catch {set author_time [clock format \ $header($cmit,author-time) \ -format {%Y-%m-%d %H:%M:%S} ]} - set committer_name {} - set committer_email {} - set committer_time {} - catch {set committer_name $header($cmit,committer)} - catch {set committer_email $header($cmit,committer-mail)} - catch {set committer_time [clock format \ - $header($cmit,committer-time) \ - -format {%Y-%m-%d %H:%M:%S} - ]} + $tooltip_t insert end "commit $cmit\n" + $tooltip_t insert end "$author_name $author_time\n" + $tooltip_t insert end "$summary" - set summary {} - catch {set summary $header($cmit,summary)} + if {$org ne {} && [lindex $org 0] ne $cmit} { + $tooltip_t insert 0.0 "Moved Here By:\n" section_header + set cmit [lindex $org 0] + set file [lindex $org 1] + lappend tooltip_commit $cmit - set tooltip_commit $cmit - set tooltip_text "commit $cmit -$author_name $author_email $author_time -$summary" + set author_name {} + set summary {} + set author_time {} + catch {set author_name $header($cmit,author)} + catch {set summary $header($cmit,summary)} + catch {set author_time [clock format \ + $header($cmit,author-time) \ + -format {%Y-%m-%d %H:%M:%S} + ]} - if {$file ne $path} { - append tooltip_text " + $tooltip_t insert end "\n\n" + $tooltip_t insert end "Originally By:\n" section_header + $tooltip_t insert end "commit $cmit\n" + $tooltip_t insert end "$author_name $author_time\n" + $tooltip_t insert end "$summary" -Original File: $file" + if {$file ne $path} { + $tooltip_t insert end "\n" + $tooltip_t insert end "File: " section_header + $tooltip_t insert end $file + } } - if {$tooltip_wm ne "$cur_w.tooltip"} { - _hide_tooltip $this - - set tooltip_wm [toplevel $cur_w.tooltip -borderwidth 1] - wm overrideredirect $tooltip_wm 1 - wm transient $tooltip_wm [winfo toplevel $cur_w] - pack [label $tooltip_wm.label \ - -background lightyellow \ - -foreground black \ - -textvariable @tooltip_text \ - -justify left] - } + $tooltip_t conf -state disabled _position_tooltip $this } method _position_tooltip {} { - set req_w [winfo reqwidth $tooltip_wm.label] - set req_h [winfo reqheight $tooltip_wm.label] + set max_h [lindex [split [$tooltip_t index end] .] 0] + set max_w 0 + for {set i 1} {$i <= $max_h} {incr i} { + set c [lindex [split [$tooltip_t index "$i.0 lineend"] .] 1] + if {$c > $max_w} {set max_w $c} + } + $tooltip_t conf -width $max_w -height $max_h + + set req_w [winfo reqwidth $tooltip_t] + set req_h [winfo reqheight $tooltip_t] set pos_x [expr {[winfo pointerx .] + 5}] set pos_y [expr {[winfo pointery .] + 10}] From 0dfed77b3cc81342aee4c81e477d636a378c51cb Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Mon, 4 Jun 2007 04:07:35 -0400 Subject: [PATCH 42/46] git-gui: Jump to original line in blame viewer When the user clicks on a commit link within one of the columns in the blame viewer we now jump them not just to that commit/file pair but also to the line of the original file. This saves the user a lot of time, as they don't need to search through the new file data for the chunk they were previously looking at. We also restore the prior view when the user clicks the back button to return to a pior commit/file pair that they were looking at. Turned out this was quite tricky to get working in Tk. Every time I tried to jump the text widgets to the correct locations by way of the "yview moveto" or "see" subcommands Tk performed the change until the current event finished dispatching, and then reset the views back to 0, making the change never take place. Forcing Tk to run the pending events before we jump the UI resolves the issue. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 55 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index f0dafff18e..44c2bb9d84 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -310,10 +310,10 @@ constructor new {i_commit i_path} { bind $w.file_pane \ "if {{$w.file_pane} eq {%W}} {[cb _resize %h]}" - _load $this + _load $this {} } -method _load {} { +method _load {jump} { _hide_tooltip $this if {$total_lines != 0 || $current_fd ne {}} { @@ -331,6 +331,10 @@ method _load {} { $i conf -state disabled } + $w_cviewer conf -state normal + $w_cviewer delete 0.0 end + $w_cviewer conf -state disabled + set highlight_line -1 set highlight_column {} set highlight_commit {} @@ -356,7 +360,6 @@ method _load {} { } else { $w_back conf -state normal } - lappend history [list $commit $path] # Index 0 is always empty. There is never line 0 as # we use only 1 based lines, as that matches both with @@ -374,7 +377,7 @@ method _load {} { set fd [open "| $cmd" r] } fconfigure $fd -blocking 0 -translation lf -encoding binary - fileevent $fd readable [cb _read_file $fd] + fileevent $fd readable [cb _read_file $fd $jump] set current_fd $fd } @@ -386,7 +389,7 @@ method _history_menu {} { menu $m -tearoff 0 } - for {set i [expr {[llength $history] - 2}] + for {set i [expr {[llength $history] - 1}] } {$i >= 0} {incr i -1} { set e [lindex $history $i] set c [lindex $e 0] @@ -406,21 +409,22 @@ method _history_menu {} { } } - $m add command -label $t -command [cb _goback $i $c $f] + $m add command -label $t -command [cb _goback $i] } set X [winfo rootx $w_back] set Y [expr {[winfo rooty $w_back] + [winfo height $w_back]}] tk_popup $m $X $Y } -method _goback {i c f} { +method _goback {i} { + set dat [lindex $history $i] set history [lrange $history 0 [expr {$i - 1}]] - set commit $c - set path $f - _load $this + set commit [lindex $dat 0] + set path [lindex $dat 1] + _load $this [lrange $dat 2 5] } -method _read_file {fd} { +method _read_file {fd jump} { if {$fd ne $current_fd} { catch {close $fd} return @@ -450,6 +454,22 @@ method _read_file {fd} { if {[eof $fd]} { close $fd + + # If we don't force Tk to update the widgets *right now* + # none of our jump commands will cause a change in the UI. + # + update + + if {[llength $jump] == 1} { + set highlight_line [lindex $jump 0] + $w_file see "$highlight_line.0" + } elseif {[llength $jump] == 4} { + set highlight_column [lindex $jump 0] + set highlight_line [lindex $jump 1] + $w_file xview moveto [lindex $jump 2] + $w_file yview moveto [lindex $jump 3] + } + _exec_blame $this $w_asim @asim_data [list] {} } } ifdeleted { catch {close $fd} } @@ -502,6 +522,7 @@ method _read_blame {fd cur_w cur_d cur_s} { set file [string range $line 9 end] set n $r_line_count set lno $r_final_line + set oln $r_orig_line set cmit $r_commit if {[regexp {^0{40}$} $cmit]} { @@ -550,7 +571,7 @@ method _read_blame {fd cur_w cur_d cur_s} { $i tag remove g$g $lno.0 $lno_e } } - lset line_data $lno [list $cmit $file] + lset line_data $lno [list $cmit $file $oln] $cur_w delete $lno.0 "$lno.0 lineend" if {$lno == $first_lno} { @@ -578,6 +599,7 @@ method _read_blame {fd cur_w cur_d cur_s} { incr n -1 incr lno + incr oln incr blame_lines } @@ -641,9 +663,16 @@ method _load_commit {cur_w cur_d pos} { set lno [lindex [split [$cur_w index $pos] .] 0] set dat [lindex $line_data $lno] if {$dat ne {}} { + lappend history [list \ + $commit $path \ + $highlight_column \ + $highlight_line \ + [lindex [$w_file xview] 0] \ + [lindex [$w_file yview] 0] \ + ] set commit [lindex $dat 0] set path [lindex $dat 1] - _load $this + _load $this [list [lindex $dat 2]] } } From 5d198d676667ecd3beeac816049bfc777b9c8566 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 6 Jun 2007 02:53:36 -0400 Subject: [PATCH 43/46] git-gui: Use three colors for the blame viewer background To prevent neighboring lines that are different commits from using the same background color we now use 3 colors and assign them by selecting the color that is not used before or after the line in question. We still color "on the fly" as we receive hunks from git-blame, but we delay our color decisions until we are getting the original location data (the slower -M -C -C pass) as that is usually more fine-grained than the current location data. Credit goes to Martin Waitz for the tri-coloring concept. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 80 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 44c2bb9d84..5ea7bfea90 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -26,8 +26,8 @@ field old_height ; # last known height of $w.file_pane # Tk UI colors # -field active_color #c0edc5 -field group_colors { +variable active_color #c0edc5 +variable group_colors { #d6d6d6 #e1e1e1 #ececec @@ -42,11 +42,9 @@ field current_fd {} ; # background process running field highlight_line -1 ; # current line selected field highlight_column {} ; # current commit column selected field highlight_commit {} ; # sha1 of commit selected -field old_bgcolor {} ; # background of current selection field total_lines 0 ; # total length of file field blame_lines 0 ; # number of lines computed -field have_commit ; # array commit -> 1 field amov_data ; # list of {commit origfile origline} field asim_data ; # list of {commit origfile origline} @@ -62,6 +60,8 @@ field tooltip_commit {} ; # Commit(s) in tooltip constructor new {i_commit i_path} { global cursor_ptr + variable active_color + variable group_colors set commit $i_commit set path $i_path @@ -250,6 +250,10 @@ constructor new {i_commit i_path} { -command [cb _copycommit] foreach i $w_columns { + for {set g 0} {$g < [llength $group_colors]} {incr g} { + $i tag conf color$g -background [lindex $group_colors $g] + } + $i conf -cursor $cursor_ptr $i conf -yscrollcommand [list many2scrollbar \ $w_columns yview $w.file_pane.out.sby] @@ -314,6 +318,8 @@ constructor new {i_commit i_path} { } method _load {jump} { + variable group_colors + _hide_tooltip $this if {$total_lines != 0 || $current_fd ne {}} { @@ -325,8 +331,10 @@ method _load {jump} { foreach i $w_columns { $i conf -state normal $i delete 0.0 end - foreach cmit [array names have_commit] { - $i tag delete g$cmit + foreach g [$i tag names] { + if {[regexp {^g[0-9a-f]{40}$} $g]} { + $i tag delete $g + } } $i conf -state disabled } @@ -339,7 +347,6 @@ method _load {jump} { set highlight_column {} set highlight_commit {} set total_lines 0 - array unset have_commit } if {[winfo exists $w.status.c]} { @@ -494,6 +501,7 @@ method _exec_blame {cur_w cur_d options cur_s} { method _read_blame {fd cur_w cur_d cur_s} { upvar #0 $cur_d line_data + variable group_colors if {$fd ne $current_fd} { catch {close $fd} @@ -508,16 +516,6 @@ method _read_blame {fd cur_w cur_d cur_s} { set r_orig_line $original_line set r_final_line $final_line set r_line_count $line_count - - if {[catch {set g $have_commit($cmit)}]} { - set bg [lindex $group_colors 0] - set group_colors [lrange $group_colors 1 end] - lappend group_colors $bg - foreach i $w_columns { - $i tag conf g$cmit -background $bg - } - set have_commit($cmit) 1 - } } elseif {[string match {filename *} $line]} { set file [string range $line 9 end] set n $r_line_count @@ -563,6 +561,30 @@ method _read_blame {fd cur_w cur_d cur_s} { incr first_lno -1 } + set color {} + if {$first_lno < $lno} { + foreach g [$w_file tag names $first_lno.0] { + if {[regexp {^color[0-9]+$} $g]} { + set color $g + break + } + } + } else { + set i [lsort [concat \ + [$w_file tag names "[expr {$first_lno - 1}].0"] \ + [$w_file tag names "[expr {$lno + $n}].0"] \ + ]] + for {set g 0} {$g < [llength $group_colors]} {incr g} { + if {[lsearch -sorted -exact $i color$g] == -1} { + set color color$g + break + } + } + } + if {$color eq {}} { + set color color0 + } + while {$n > 0} { set lno_e "$lno.0 lineend + 1c" if {[lindex $line_data $lno] ne {}} { @@ -583,6 +605,14 @@ method _read_blame {fd cur_w cur_d cur_s} { } foreach i $w_columns { + if {$cur_w eq $w_amov} { + for {set g 0} \ + {$g < [llength $group_colors]} \ + {incr g} { + $i tag remove color$g $lno.0 $lno_e + } + $i tag add $color $lno.0 $lno_e + } $i tag add g$cmit $lno.0 $lno_e } @@ -616,6 +646,18 @@ method _read_blame {fd cur_w cur_d cur_s} { } else { $cur_w insert $lno.0 { |} } + + if {$cur_w eq $w_amov} { + foreach i $w_columns { + for {set g 0} \ + {$g < [llength $group_colors]} \ + {incr g} { + $i tag remove color$g $lno.0 $lno_e + } + $i tag add $color $lno.0 $lno_e + } + } + incr lno } @@ -678,10 +720,11 @@ method _load_commit {cur_w cur_d pos} { method _showcommit {cur_w lno} { global repo_config + variable active_color if {$highlight_commit ne {}} { foreach i $w_columns { - $i tag conf g$highlight_commit -background $old_bgcolor + $i tag conf g$highlight_commit -background {} $i tag lower g$highlight_commit } } @@ -704,7 +747,6 @@ method _showcommit {cur_w lno} { set cmit [lindex $dat 0] set file [lindex $dat 1] - set old_bgcolor [$w_file tag cget g$cmit -background] foreach i $w_columns { $i tag conf g$cmit -background $active_color $i tag raise g$cmit From 949da61b9b84bfb48ed2ff2dea068a1d19fb847b Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 6 Jun 2007 03:03:16 -0400 Subject: [PATCH 44/46] git-gui: Improve our labeling of blame annotation types It feels wrong to call the -M -C -C annotations "move/copy tracking" as they are actually the original locations. So I'm relabeling the status bar to show "copy/move tracking annotations" for the current file (no -M -C -C) as that set of annotations tells us who put the hunk here (who moved/copied it). I'm now calling the -M -C -C pass "original location annotations" as that's what we're really digging for. I also tried to clarify some of the text in the hover tooltip. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 5ea7bfea90..0400d6effe 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -477,7 +477,9 @@ method _read_file {fd jump} { $w_file yview moveto [lindex $jump 3] } - _exec_blame $this $w_asim @asim_data [list] {} + _exec_blame $this $w_asim @asim_data \ + [list] \ + { copy/move tracking} } } ifdeleted { catch {close $fd} } @@ -672,7 +674,7 @@ method _read_blame {fd cur_w cur_d cur_s} { if {$cur_w eq $w_asim} { _exec_blame $this $w_amov @amov_data \ [list -M -C -C] \ - { move/copy tracking} + { original location} } else { set current_fd {} set status {Annotation complete.} @@ -906,7 +908,7 @@ method _open_tooltip {cur_w} { $tooltip_t insert end "$summary" if {$org ne {} && [lindex $org 0] ne $cmit} { - $tooltip_t insert 0.0 "Moved Here By:\n" section_header + $tooltip_t insert 0.0 "Copied/Moved Here By:\n" section_header set cmit [lindex $org 0] set file [lindex $org 1] lappend tooltip_commit $cmit @@ -929,7 +931,7 @@ method _open_tooltip {cur_w} { if {$file ne $path} { $tooltip_t insert end "\n" - $tooltip_t insert end "File: " section_header + $tooltip_t insert end "In File: " section_header $tooltip_t insert end $file } } From 0f32da53df706220e7392a29d8e462b57345df3d Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 6 Jun 2007 03:22:22 -0400 Subject: [PATCH 45/46] git-gui: Favor the original annotations over the recent ones Usually when you are looking at blame annotations for a region of a file you are more interested in why something was originally done then why it is here now. This is because most of the time when we get original annotation data we are looking at a simple refactoring performed to better organize code, not to change its semantic meaning or function. Reorganizations are sometimes of interest, but not usually. We now show the original commit data first in the tooltip. This actually looks quite nice as the original commit will usually have an author date prior to the current (aka move/copy) annotation's commit, so the two commits will now tend to appear in chronological order. I also found myself to always be clicking on the line of interest in the file column but I always wanted the original tracking data and not the move/copy data. So I changed our default commit from $asim_data (the simple move/copy annotation) to the more complex $amov_data (the -M -C -C original annotation). Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index 0400d6effe..cb0f2c40b7 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -731,12 +731,12 @@ method _showcommit {cur_w lno} { } } - if {$cur_w eq $w_amov} { - set dat [lindex $amov_data $lno] - set highlight_column $w_amov - } else { + if {$cur_w eq $w_asim} { set dat [lindex $asim_data $lno] set highlight_column $w_asim + } else { + set dat [lindex $amov_data $lno] + set highlight_column $w_amov } $w_cviewer conf -state normal @@ -908,7 +908,9 @@ method _open_tooltip {cur_w} { $tooltip_t insert end "$summary" if {$org ne {} && [lindex $org 0] ne $cmit} { - $tooltip_t insert 0.0 "Copied/Moved Here By:\n" section_header + set save [$tooltip_t get 0.0 end] + $tooltip_t delete 0.0 end + set cmit [lindex $org 0] set file [lindex $org 1] lappend tooltip_commit $cmit @@ -923,17 +925,19 @@ method _open_tooltip {cur_w} { -format {%Y-%m-%d %H:%M:%S} ]} - $tooltip_t insert end "\n\n" $tooltip_t insert end "Originally By:\n" section_header $tooltip_t insert end "commit $cmit\n" $tooltip_t insert end "$author_name $author_time\n" - $tooltip_t insert end "$summary" + $tooltip_t insert end "$summary\n" if {$file ne $path} { - $tooltip_t insert end "\n" $tooltip_t insert end "In File: " section_header - $tooltip_t insert end $file + $tooltip_t insert end "$file\n" } + + $tooltip_t insert end "\n" + $tooltip_t insert end "Copied Or Moved Here By:\n" section_header + $tooltip_t insert end $save } $tooltip_t conf -state disabled From d80ded01de0189fe7179913d3ecdeecadf2052a0 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Fri, 8 Jun 2007 02:02:48 -0400 Subject: [PATCH 46/46] git-gui: Changed blame header bar background to match main window The main window's diff header bar background switched from orange to gold recently, and I liked the effect it had on readability of the text. Since I wanted the blame viewer to match, here it is. Though this probably should be a user defined color, or at least a constant somewhere that everyone can reference. Signed-off-by: Shawn O. Pearce --- lib/blame.tcl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/blame.tcl b/lib/blame.tcl index cb0f2c40b7..98687c77da 100644 --- a/lib/blame.tcl +++ b/lib/blame.tcl @@ -69,10 +69,10 @@ constructor new {i_commit i_path} { make_toplevel top w wm title $top "[appname] ([reponame]): File Viewer" - frame $w.header -background orange + frame $w.header -background gold label $w.header.commit_l \ -text {Commit:} \ - -background orange \ + -background gold \ -anchor w \ -justify left set w_back $w.header.commit_b @@ -81,8 +81,8 @@ constructor new {i_commit i_path} { -borderwidth 0 \ -relief flat \ -state disabled \ - -background orange \ - -activebackground orange + -background gold \ + -activebackground gold bind $w_back " if {\[$w_back cget -state\] eq {normal}} { [cb _history_menu] @@ -90,17 +90,17 @@ constructor new {i_commit i_path} { " label $w.header.commit \ -textvariable @commit \ - -background orange \ + -background gold \ -anchor w \ -justify left label $w.header.path_l \ -text {File:} \ - -background orange \ + -background gold \ -anchor w \ -justify left set w_path $w.header.path label $w_path \ - -background orange \ + -background gold \ -anchor w \ -justify left pack $w.header.commit_l -side left