git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Johannes Schindelin <Johannes.Schindelin@gmx.de>
To: Jason Sewall <jasonsewall@gmail.com>
Cc: "Shawn O. Pearce" <spearce@spearce.org>, David <davvid@gmail.com>,
	Marco Costalba <mcostalba@gmail.com>,
	Andy Parkins <andyparkins@gmail.com>,
	git@vger.kernel.org
Subject: [PATCH] Teach git-gui to split hunks
Date: Wed, 12 Dec 2007 19:37:45 +0000 (GMT)	[thread overview]
Message-ID: <Pine.LNX.4.64.0712121931050.27959@racer.site> (raw)
In-Reply-To: <31e9dd080712121050i45981ed5u845b71f0e73aa8e2@mail.gmail.com>


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@gmx.de>
---

	On Wed, 12 Dec 2007, Jason Sewall wrote:

	> On Dec 12, 2007 1:15 PM, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
	> >
	> > I had a patch for splitting hunks in git-gui in August, but 
	> > there were some issues that I did not yet resolve.  If you 
	> > want to work on it, I'll gladly share that patch with you.
	> 
	> Sure, send it along. I'm not going to make any promises, but I 
	> could probably find time poke around in there.

	This was the next step that I did not yet quite complete:

+proc get_context_lines {line_number context_count direction variable} {
+       global ui_diff
+       upvar result $variable
+
+       set count 0
+       set result ""
+       for {set i $line_number} {$count < $context_count} {incr i $direction} {
+               switch -exact -- [$ui_diff get $i.0] {
+                       " " {
+                               append result [$ui_diff get $i.0 "$i.lineend"]
+                               incr count
+                       }
+                       "-" {
+                               append result [$ui_diff get $i.0 "$i.lineend"]
+                               incr count
+                       }
+                       "@" {
+                               return $count
+                       }
+                       "" {
+                               return $count
+                       }
+               }
+       }
+}

	Of course, this function would be used to add some context 
	to the new hunk boundaries (if needed), and to adjust the contexts
	of the remaining hunks whenever some hunk was applied.

	... and then get rid of that ugly unidiff-zero option.

 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 1fca11f..0798d41 100755
--- a/git-gui.sh
+++ b/git-gui.sh
@@ -2567,6 +2567,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 [mc "Decrease Font Size"] \
diff --git a/lib/diff.tcl b/lib/diff.tcl
index 43565e4..0c3f790 100644
--- a/lib/diff.tcl
+++ b/lib/diff.tcl
@@ -289,6 +289,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
@@ -296,7 +369,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 failed_msg [mc "Failed to unstage selected hunk."]
-- 
1.5.3.7.2250.g3893

  reply	other threads:[~2007-12-12 19:38 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-12-11 13:48 [ANNOUNCE] ugit: a pyqt-based git gui // was: Re: If you would write git from scratch now, what would you change? David
2007-12-11 18:20 ` Marco Costalba
2007-12-11 19:14   ` Jason Sewall
2007-12-11 19:33     ` Marco Costalba
2007-12-11 20:54       ` David
2007-12-11 21:29         ` Jason Sewall
2007-12-12  4:10           ` Shawn O. Pearce
2007-12-12  5:13             ` Jason Sewall
2007-12-12  5:23               ` Shawn O. Pearce
2007-12-12 15:02                 ` Jason Sewall
2007-12-12 18:15                   ` Johannes Schindelin
2007-12-12 18:50                     ` Jason Sewall
2007-12-12 19:37                       ` Johannes Schindelin [this message]
2007-12-12 20:18                         ` [PATCH] Teach git-gui to split hunks Junio C Hamano
2007-12-12 20:39                           ` Johannes Schindelin
2007-12-12 20:50                           ` Jean-François Veillette
2007-12-12 22:54                             ` Junio C Hamano
2007-12-12 23:02                           ` Wincent Colaiuta
2007-12-13  7:35                         ` Johannes Sixt
2007-12-13  7:48                           ` Shawn O. Pearce
2007-12-13 12:25                           ` Johannes Schindelin
2007-12-13  8:45                         ` Junio C Hamano
2007-12-13  9:41                           ` Johannes Sixt
2007-12-13 12:49                           ` Johannes Schindelin
2007-12-13 14:03                             ` Johannes Sixt
2007-12-13 14:18                               ` Johannes Schindelin
2007-12-13 14:39                                 ` [PATCH] git-gui: Move frequently used commands to the top of the context menu Johannes Sixt
2007-12-14  6:32                                   ` Shawn O. Pearce
2007-12-11 22:37 ` [ANNOUNCE] ugit: a pyqt-based git gui // was: Re: If you would write git from scratch now, what would you change? Alex Riesen
2007-12-11 23:08   ` Steffen Prohaska
2007-12-12  0:11 ` Jakub Narebski
  -- strict thread matches above, loose matches on Subject: below --
2007-07-26  5:32 [PATCH] Teach git-gui to split hunks Johannes Schindelin
2007-07-26  5:48 ` David Kastrup
2007-07-26  7:07   ` Shawn O. Pearce
2007-07-26 14:34     ` Johannes Schindelin
2007-07-26  7:32 ` Johannes Sixt
2007-07-26 14:26   ` Johannes Schindelin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Pine.LNX.4.64.0712121931050.27959@racer.site \
    --to=johannes.schindelin@gmx.de \
    --cc=andyparkins@gmail.com \
    --cc=davvid@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=jasonsewall@gmail.com \
    --cc=mcostalba@gmail.com \
    --cc=spearce@spearce.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).