Merge branch 'bw/commit-scrollbuffer'
authorPratyush Yadav <me@yadavpratyush.com>
Fri, 13 Sep 2019 20:49:38 +0000 (02:19 +0530)
committerPratyush Yadav <me@yadavpratyush.com>
Fri, 13 Sep 2019 20:49:38 +0000 (02:19 +0530)
Add a scrollbar at the bottom of the commit message buffer.

* bw/commit-scrollbuffer:
git-gui: add horizontal scrollbar to commit buffer

git-gui.sh
lib/checkout_op.tcl
lib/commit.tcl
lib/diff.tcl
lib/index.tcl
index ad962d4fbebb93a6f420ef5ddc987ed6fafa3074..8ecb98b09ba81a624ce82d31ac302f02c29d67e0 100755 (executable)
@@ -1341,6 +1341,7 @@ set HEAD {}
 set PARENT {}
 set MERGE_HEAD [list]
 set commit_type {}
+set commit_type_is_amend 0
 set empty_tree {}
 set current_branch {}
 set is_detached 0
@@ -1348,8 +1349,9 @@ set current_diff_path {}
 set is_3way_diff 0
 set is_submodule_diff 0
 set is_conflict_diff 0
-set selected_commit_type new
 set diff_empty_count 0
+set last_revert {}
+set last_revert_enc {}
 
 set nullid "0000000000000000000000000000000000000000"
 set nullid2 "0000000000000000000000000000000000000001"
@@ -1435,7 +1437,7 @@ proc PARENT {} {
 }
 
 proc force_amend {} {
-       global selected_commit_type
+       global commit_type_is_amend
        global HEAD PARENT MERGE_HEAD commit_type
 
        repository_state newType newHEAD newMERGE_HEAD
@@ -1444,7 +1446,7 @@ proc force_amend {} {
        set MERGE_HEAD $newMERGE_HEAD
        set commit_type $newType
 
-       set selected_commit_type amend
+       set commit_type_is_amend 1
        do_select_commit_type
 }
 
@@ -2495,7 +2497,7 @@ proc force_first_diff {after} {
 
 proc toggle_or_diff {mode w args} {
        global file_states file_lists current_diff_path ui_index ui_workdir
-       global last_clicked selected_paths
+       global last_clicked selected_paths file_lists_last_clicked
 
        if {$mode eq "click"} {
                foreach {x y} $args break
@@ -2527,6 +2529,8 @@ proc toggle_or_diff {mode w args} {
        $ui_index tag remove in_sel 0.0 end
        $ui_workdir tag remove in_sel 0.0 end
 
+       set file_lists_last_clicked($w) $path
+
        # Determine the state of the file
        if {[info exists file_states($path)]} {
                set state [lindex $file_states($path) 0]
@@ -2640,6 +2644,26 @@ proc show_less_context {} {
        }
 }
 
+proc focus_widget {widget} {
+       global file_lists last_clicked selected_paths
+       global file_lists_last_clicked
+
+       if {[llength $file_lists($widget)] > 0} {
+               set path $file_lists_last_clicked($widget)
+               set index [lsearch -sorted -exact $file_lists($widget) $path]
+               if {$index < 0} {
+                       set index 0
+                       set path [lindex $file_lists($widget) $index]
+               }
+
+               focus $widget
+               set last_clicked [list $widget [expr $index + 1]]
+               array unset selected_paths
+               set selected_paths($path) 1
+               show_diff $path $widget
+       }
+}
+
 ######################################################################
 ##
 ## ui construction
@@ -2828,19 +2852,10 @@ if {[is_enabled multicommit] || [is_enabled singlecommit]} {
        menu .mbar.commit
 
        if {![is_enabled nocommit]} {
-               .mbar.commit add radiobutton \
-                       -label [mc "New Commit"] \
-                       -command do_select_commit_type \
-                       -variable selected_commit_type \
-                       -value new
-               lappend disable_on_lock \
-                       [list .mbar.commit entryconf [.mbar.commit index last] -state]
-
-               .mbar.commit add radiobutton \
+               .mbar.commit add checkbutton \
                        -label [mc "Amend Last Commit"] \
-                       -command do_select_commit_type \
-                       -variable selected_commit_type \
-                       -value amend
+                       -variable commit_type_is_amend \
+                       -command do_select_commit_type
                lappend disable_on_lock \
                        [list .mbar.commit entryconf [.mbar.commit index last] -state]
 
@@ -3313,18 +3328,10 @@ set ui_comm .vpane.lower.commarea.buffer.frame.t
 set ui_coml .vpane.lower.commarea.buffer.header.l
 
 if {![is_enabled nocommit]} {
-       ${NS}::radiobutton .vpane.lower.commarea.buffer.header.new \
-               -text [mc "New Commit"] \
-               -command do_select_commit_type \
-               -variable selected_commit_type \
-               -value new
-       lappend disable_on_lock \
-               [list .vpane.lower.commarea.buffer.header.new conf -state]
-       ${NS}::radiobutton .vpane.lower.commarea.buffer.header.amend \
+       ${NS}::checkbutton .vpane.lower.commarea.buffer.header.amend \
                -text [mc "Amend Last Commit"] \
-               -command do_select_commit_type \
-               -variable selected_commit_type \
-               -value amend
+               -variable commit_type_is_amend \
+               -command do_select_commit_type
        lappend disable_on_lock \
                [list .vpane.lower.commarea.buffer.header.amend conf -state]
 }
@@ -3349,7 +3356,6 @@ pack $ui_coml -side left -fill x
 
 if {![is_enabled nocommit]} {
        pack .vpane.lower.commarea.buffer.header.amend -side right
-       pack .vpane.lower.commarea.buffer.header.new -side right
 }
 
 textframe .vpane.lower.commarea.buffer.frame
@@ -3588,15 +3594,31 @@ set ctxm .vpane.lower.diff.body.ctxm
 menu $ctxm -tearoff 0
 $ctxm add command \
        -label [mc "Apply/Reverse Hunk"] \
-       -command {apply_hunk $cursorX $cursorY}
+       -command {apply_or_revert_hunk $cursorX $cursorY 0}
 set ui_diff_applyhunk [$ctxm index last]
 lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state]
 $ctxm add command \
        -label [mc "Apply/Reverse Line"] \
-       -command {apply_range_or_line $cursorX $cursorY; do_rescan}
+       -command {apply_or_revert_range_or_line $cursorX $cursorY 0; do_rescan}
 set ui_diff_applyline [$ctxm index last]
 lappend diff_actions [list $ctxm entryconf $ui_diff_applyline -state]
 $ctxm add separator
+$ctxm add command \
+       -label [mc "Revert Hunk"] \
+       -command {apply_or_revert_hunk $cursorX $cursorY 1}
+set ui_diff_reverthunk [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_reverthunk -state]
+$ctxm add command \
+       -label [mc "Revert Line"] \
+       -command {apply_or_revert_range_or_line $cursorX $cursorY 1; do_rescan}
+set ui_diff_revertline [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_revertline -state]
+$ctxm add command \
+       -label [mc "Undo Last Revert"] \
+       -command {undo_last_revert; do_rescan}
+set ui_diff_undorevert [$ctxm index last]
+lappend diff_actions [list $ctxm entryconf $ui_diff_undorevert -state]
+$ctxm add separator
 $ctxm add command \
        -label [mc "Show Less Context"] \
        -command show_less_context
@@ -3675,7 +3697,7 @@ proc has_textconv {path} {
 }
 
 proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
-       global current_diff_path file_states
+       global current_diff_path file_states last_revert
        set ::cursorX $x
        set ::cursorY $y
        if {[info exists file_states($current_diff_path)]} {
@@ -3689,19 +3711,28 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
                tk_popup $ctxmsm $X $Y
        } else {
                set has_range [expr {[$::ui_diff tag nextrange sel 0.0] != {}}]
+               set u [mc "Undo Last Revert"]
                if {$::ui_index eq $::current_diff_side} {
                        set l [mc "Unstage Hunk From Commit"]
+                       set h [mc "Revert Hunk"]
+
                        if {$has_range} {
                                set t [mc "Unstage Lines From Commit"]
+                               set r [mc "Revert Lines"]
                        } else {
                                set t [mc "Unstage Line From Commit"]
+                               set r [mc "Revert Line"]
                        }
                } else {
                        set l [mc "Stage Hunk For Commit"]
+                       set h [mc "Revert Hunk"]
+
                        if {$has_range} {
                                set t [mc "Stage Lines For Commit"]
+                               set r [mc "Revert Lines"]
                        } else {
                                set t [mc "Stage Line For Commit"]
+                               set r [mc "Revert Line"]
                        }
                }
                if {$::is_3way_diff
@@ -3712,11 +3743,35 @@ proc popup_diff_menu {ctxm ctxmmg ctxmsm x y X Y} {
                        || [string match {T?} $state]
                        || [has_textconv $current_diff_path]} {
                        set s disabled
+                       set revert_state disabled
                } else {
                        set s normal
+
+                       # Only allow reverting changes in the working tree. If
+                       # the user wants to revert changes in the index, they
+                       # need to unstage those first.
+                       if {$::ui_workdir eq $::current_diff_side} {
+                               set revert_state normal
+                       } else {
+                               set revert_state disabled
+                       }
                }
+
+               if {$last_revert eq {}} {
+                       set undo_state disabled
+               } else {
+                       set undo_state normal
+               }
+
                $ctxm entryconf $::ui_diff_applyhunk -state $s -label $l
                $ctxm entryconf $::ui_diff_applyline -state $s -label $t
+               $ctxm entryconf $::ui_diff_revertline -state $revert_state \
+                       -label $r
+               $ctxm entryconf $::ui_diff_reverthunk -state $revert_state \
+                       -label $h
+               $ctxm entryconf $::ui_diff_undorevert -state $undo_state \
+                       -label $u
+
                tk_popup $ctxm $X $Y
        }
 }
@@ -3858,6 +3913,14 @@ foreach i [list $ui_index $ui_workdir] {
 }
 unset i
 
+bind .   <Alt-Key-1> {focus_widget $::ui_workdir}
+bind .   <Alt-Key-2> {focus_widget $::ui_index}
+bind .   <Alt-Key-3> {focus $::ui_diff}
+bind .   <Alt-Key-4> {focus $::ui_comm}
+
+set file_lists_last_clicked($ui_index) {}
+set file_lists_last_clicked($ui_workdir) {}
+
 set file_lists($ui_index) [list]
 set file_lists($ui_workdir) [list]
 
index 9e7412c446f715588b9cfe21654a3447e8680e12..a5228297db2c6bcccaf61d906143ecfffacf9822 100644 (file)
@@ -389,7 +389,7 @@ $err
 }
 
 method _after_readtree {} {
-       global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
+       global commit_type HEAD MERGE_HEAD PARENT
        global current_branch is_detached
        global ui_comm
 
@@ -490,12 +490,12 @@ method _update_repo_state {} {
        #    amend mode our file lists are accurate and we can avoid
        #    the rescan.
        #
-       global selected_commit_type commit_type HEAD MERGE_HEAD PARENT
+       global commit_type_is_amend commit_type HEAD MERGE_HEAD PARENT
        global ui_comm
 
        unlock_index
        set name [_name $this]
-       set selected_commit_type new
+       set commit_type_is_amend 0
        if {[string match amend* $commit_type]} {
                $ui_comm delete 0.0 end
                $ui_comm edit reset
index 83620b7cbc3a194fb17d395c17c10c9dd7f1683f..384f18f226a469440f9b14d70f7ef366202a7bf1 100644 (file)
@@ -327,7 +327,7 @@ proc commit_writetree {curHEAD msg_p} {
 proc commit_committree {fd_wt curHEAD msg_p} {
        global HEAD PARENT MERGE_HEAD commit_type commit_author
        global current_branch
-       global ui_comm selected_commit_type
+       global ui_comm commit_type_is_amend
        global file_states selected_paths rescan_active
        global repo_config
        global env
@@ -461,8 +461,8 @@ A rescan will be automatically started now.
 
        # -- Update in memory status
        #
-       set selected_commit_type new
        set commit_type normal
+       set commit_type_is_amend 0
        set HEAD $cmt_id
        set PARENT $cmt_id
        set MERGE_HEAD [list]
index 4cae10a4c7f197aab9ae0bc145254a8d4a1bae50..96288fcc332e0083a56fcbb9248bc10ac536388e 100644 (file)
@@ -55,7 +55,7 @@ proc reshow_diff {{after {}}} {
 
 proc force_diff_encoding {enc} {
        global current_diff_path
-       
+
        if {$current_diff_path ne {}} {
                force_path_encoding $current_diff_path $enc
                reshow_diff
@@ -567,24 +567,31 @@ proc read_diff {fd conflict_size cont_info} {
        }
 }
 
-proc apply_hunk {x y} {
+proc apply_or_revert_hunk {x y revert} {
        global current_diff_path current_diff_header current_diff_side
-       global ui_diff ui_index file_states
+       global ui_diff ui_index file_states last_revert last_revert_enc
 
        if {$current_diff_path eq {} || $current_diff_header eq {}} return
        if {![lock_index apply_hunk]} return
 
-       set apply_cmd {apply --cached --whitespace=nowarn}
+       set apply_cmd {apply --whitespace=nowarn}
        set mi [lindex $file_states($current_diff_path) 0]
        if {$current_diff_side eq $ui_index} {
                set failed_msg [mc "Failed to unstage selected hunk."]
-               lappend apply_cmd --reverse
+               lappend apply_cmd --reverse --cached
                if {[string index $mi 0] ne {M}} {
                        unlock_index
                        return
                }
        } else {
-               set failed_msg [mc "Failed to stage selected hunk."]
+               if {$revert} {
+                       set failed_msg [mc "Failed to revert selected hunk."]
+                       lappend apply_cmd --reverse
+               } else {
+                       set failed_msg [mc "Failed to stage selected hunk."]
+                       lappend apply_cmd --cached
+               }
+
                if {[string index $mi 1] ne {M}} {
                        unlock_index
                        return
@@ -603,29 +610,40 @@ proc apply_hunk {x y} {
                set e_lno end
        }
 
+       set wholepatch "$current_diff_header[$ui_diff get $s_lno $e_lno]"
+
        if {[catch {
                set enc [get_path_encoding $current_diff_path]
                set p [eval git_write $apply_cmd]
                fconfigure $p -translation binary -encoding $enc
-               puts -nonewline $p $current_diff_header
-               puts -nonewline $p [$ui_diff get $s_lno $e_lno]
+               puts -nonewline $p $wholepatch
                close $p} err]} {
                error_popup "$failed_msg\n\n$err"
                unlock_index
                return
        }
 
+       if {$revert} {
+               # Save a copy of this patch for undoing reverts.
+               set last_revert $wholepatch
+               set last_revert_enc $enc
+       }
+
        $ui_diff conf -state normal
        $ui_diff delete $s_lno $e_lno
        $ui_diff conf -state disabled
 
+       # Check if the hunk was the last one in the file.
        if {[$ui_diff get 1.0 end] eq "\n"} {
                set o _
        } else {
                set o ?
        }
 
-       if {$current_diff_side eq $ui_index} {
+       # Update the status flags.
+       if {$revert} {
+               set mi [string index $mi 0]$o
+       } elseif {$current_diff_side eq $ui_index} {
                set mi ${o}M
        } elseif {[string index $mi 0] eq {_}} {
                set mi M$o
@@ -640,9 +658,9 @@ proc apply_hunk {x y} {
        }
 }
 
-proc apply_range_or_line {x y} {
+proc apply_or_revert_range_or_line {x y revert} {
        global current_diff_path current_diff_header current_diff_side
-       global ui_diff ui_index file_states
+       global ui_diff ui_index file_states last_revert
 
        set selected [$ui_diff tag nextrange sel 0.0]
 
@@ -660,19 +678,27 @@ proc apply_range_or_line {x y} {
        if {$current_diff_path eq {} || $current_diff_header eq {}} return
        if {![lock_index apply_hunk]} return
 
-       set apply_cmd {apply --cached --whitespace=nowarn}
+       set apply_cmd {apply --whitespace=nowarn}
        set mi [lindex $file_states($current_diff_path) 0]
        if {$current_diff_side eq $ui_index} {
                set failed_msg [mc "Failed to unstage selected line."]
                set to_context {+}
-               lappend apply_cmd --reverse
+               lappend apply_cmd --reverse --cached
                if {[string index $mi 0] ne {M}} {
                        unlock_index
                        return
                }
        } else {
-               set failed_msg [mc "Failed to stage selected line."]
-               set to_context {-}
+               if {$revert} {
+                       set failed_msg [mc "Failed to revert selected line."]
+                       set to_context {+}
+                       lappend apply_cmd --reverse
+               } else {
+                       set failed_msg [mc "Failed to stage selected line."]
+                       set to_context {-}
+                       lappend apply_cmd --cached
+               }
+
                if {[string index $mi 1] ne {M}} {
                        unlock_index
                        return
@@ -829,7 +855,47 @@ proc apply_range_or_line {x y} {
                puts -nonewline $p $wholepatch
                close $p} err]} {
                error_popup "$failed_msg\n\n$err"
+               unlock_index
+               return
+       }
+
+       if {$revert} {
+               # Save a copy of this patch for undoing reverts.
+               set last_revert $current_diff_header$wholepatch
+               set last_revert_enc $enc
        }
 
        unlock_index
 }
+
+# Undo the last line/hunk reverted. When hunks and lines are reverted, a copy
+# of the diff applied is saved. Re-apply that diff to undo the revert.
+#
+# Right now, we only use a single variable to hold the copy, and not a
+# stack/deque for simplicity, so multiple undos are not possible. Maybe this
+# can be added if the need for something like this is felt in the future.
+proc undo_last_revert {} {
+       global last_revert current_diff_path current_diff_header
+       global last_revert_enc
+
+       if {$last_revert eq {}} return
+       if {![lock_index apply_hunk]} return
+
+       set apply_cmd {apply --whitespace=nowarn}
+       set failed_msg [mc "Failed to undo last revert."]
+
+       if {[catch {
+               set enc $last_revert_enc
+               set p [eval git_write $apply_cmd]
+               fconfigure $p -translation binary -encoding $enc
+               puts -nonewline $p $last_revert
+               close $p} err]} {
+               error_popup "$failed_msg\n\n$err"
+               unlock_index
+               return
+       }
+
+       set last_revert {}
+
+       unlock_index
+}
index b588db11d9fc46b6c4c33274c3c5f969dfe43e5e..e07b7a376230f50a66f2450255121798409667f8 100644 (file)
@@ -466,19 +466,19 @@ proc do_revert_selection {} {
 }
 
 proc do_select_commit_type {} {
-       global commit_type selected_commit_type
+       global commit_type commit_type_is_amend
 
-       if {$selected_commit_type eq {new}
+       if {$commit_type_is_amend == 0
                && [string match amend* $commit_type]} {
                create_new_commit
-       } elseif {$selected_commit_type eq {amend}
+       } elseif {$commit_type_is_amend == 1
                && ![string match amend* $commit_type]} {
                load_last_commit
 
                # The amend request was rejected...
                #
                if {![string match amend* $commit_type]} {
-                       set selected_commit_type new
+                       set commit_type_is_amend 0
                }
        }
 }