When you select the context menu item "Split Hunk" in the diff area, git-gui will now split the current hunk so that a new hunk starts at the current position. For this to work, apply has to be called with --unidiff-zero, since the new hunks can start or stop with a "-" or "+" line. Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> --- No more complaining from me about the lack of that feature. And I did not even need a C compiler to do that. git-gui.sh | 4 +++ lib/diff.tcl | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletions(-) diff --git a/git-gui.sh b/git-gui.sh index a38293a..a0f7617 100755 --- a/git-gui.sh +++ b/git-gui.sh @@ -2400,6 +2400,10 @@ $ctxm add command \ -command {apply_hunk $cursorX $cursorY} set ui_diff_applyhunk [$ctxm index last] lappend diff_actions [list $ctxm entryconf $ui_diff_applyhunk -state] +$ctxm add command \ + -label [mc "Split Hunk"] \ + -command {split_hunk $cursorX $cursorY} +lappend diff_actions [list $ctxm entryconf [$ctxm index last] -state] $ctxm add separator $ctxm add command \ -label {Decrease Font Size} \ diff --git a/lib/diff.tcl b/lib/diff.tcl index e09e125..88ec8f3 100644 --- a/lib/diff.tcl +++ b/lib/diff.tcl @@ -265,6 +265,79 @@ proc read_diff {fd} { } } +proc split_hunk {x y} { + global current_diff_path current_diff_header current_diff_side + global ui_diff ui_index file_states + + if {$current_diff_path eq {} || $current_diff_header eq {}} return + if {![lock_index apply_hunk]} return + + set c_lno [lindex [split [$ui_diff index @$x,$y] .] 0] + set s_idx [$ui_diff search -backwards -regexp ^@@ $c_lno.0 0.0] + if {$s_idx eq {} || $s_idx >= [expr $c_lno - 1]} { + unlock_index + return + } + set s_lno [lindex [split $s_idx .] 0] + + # the first hunk will look like this: @@ -$m1,$m2 +$p1,$p2 @@ + # the second hunk will look like this: @@ -$m3,$m4 +$p3,$p4 @@ + + # get original hunk numbers + set hunk_line [$ui_diff get $s_idx "$s_idx lineend"] + set re "@@ +-(\[0-9\]+)(,(\[0-9\]+))? +\\+(\[0-9\]+)(,(\[0-9\]+))? *@@" + if {![regexp $re $hunk_line dummy m1 dummy m4 p1 dummy p4] || + $m1 == 0 || $p1 == 0} { # create/delete file + unlock_index + return + } + if {$m4 == ""} { + set m4 1 + } + if {$p4 == ""} { + set p4 1 + } + + # count changes + set m2 0 + set p2 0 + for {set l [expr $s_lno + 1]} {$l < $c_lno} {incr l} { + switch -exact -- [$ui_diff get $l.0] { + " " { + incr m2 + incr p2 + } + "+" { + incr p2 + } + "-" { + incr m2 + } + } + } + + # We could check if {$m2 == $p2 && $m2 == [expr $c_lno - $s_lno]} + # and just remove the hunk. But let's not be too clever here. + + set m3 [expr $m1 + $m2] + set m4 [expr $m4 - $m2] + set p3 [expr $p1 + $p2] + set p4 [expr $p4 - $p2] + + if {$m4 == 0 && $p4 == 0} { + index_unlock + return + } + + $ui_diff configure -state normal + $ui_diff delete $s_idx "$s_idx lineend" + $ui_diff insert $s_idx "@@ -$m1,$m2 +$p1,$p2 @@" d_@ + $ui_diff insert $c_lno.0 "@@ -$m3,$m4 +$p3,$p4 @@\n" d_@ + $ui_diff configure -state disabled + + unlock_index +} + proc apply_hunk {x y} { global current_diff_path current_diff_header current_diff_side global ui_diff ui_index file_states @@ -272,7 +345,7 @@ proc apply_hunk {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 --cached --whitespace=nowarn --unidiff-zero} set mi [lindex $file_states($current_diff_path) 0] if {$current_diff_side eq $ui_index} { set mode unstage -- 1.5.3.rc2.42.gda8d-dirty - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html