Merge branch 'py/revert-hunks-lines'
authorPratyush Yadav <me@yadavpratyush.com>
Wed, 11 Sep 2019 21:11:12 +0000 (02:41 +0530)
committerPratyush Yadav <me@yadavpratyush.com>
Wed, 11 Sep 2019 21:11:12 +0000 (02:41 +0530)
git-gui learned to revert selected lines and hunks, just like it can
stage selected lines and hunks. To provide a safety net for accidental
revert, the most recent revert can be undone.

* py/revert-hunks-lines:
git-gui: allow undoing last revert
git-gui: return early when patch fails to apply
git-gui: allow reverting selected hunk
git-gui: allow reverting selected lines

1  2 
git-gui.sh
diff --combined git-gui.sh
index 5dae8da64ff0e792891b51d1aee193dc088e40de,e03a2d2c28d7170ab18b9751f10ebb624ad67499..ac258d0dcfb64e262cfca2c67e132b9684a96d34
@@@ -1350,6 -1350,8 +1350,8 @@@ set is_submodule_diff 
  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"
@@@ -2495,7 -2497,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
        $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]
@@@ -2642,26 -2642,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
@@@ -3604,15 -3584,31 +3606,31 @@@ set ctxm .vpane.lower.diff.body.ctx
  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
@@@ -3691,7 -3687,7 +3709,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)]} {
                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
                        || [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
        }
  }
@@@ -3874,14 -3903,6 +3925,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]