[PATCH 2 of 3] record: add an option to split hunks

Steve Losh steve at stevelosh.com
Mon Jan 4 18:44:53 CST 2010


# HG changeset patch
# User Steve Losh <steve at stevelosh.com>
# Date 1262652127 18000
# Node ID 4c11455bab391bee9fc7ae8ad9182b46468923c4
# Parent  1fa39ad1ca75699329f538aae321fcdcfbb5dfda
record: add an option to split hunks

diff --git a/hgext/record.py b/hgext/record.py
--- a/hgext/record.py
+++ b/hgext/record.py
@@ -153,7 +153,13 @@
         self.hunk = hunk
         self.added, self.removed = countchanges(self.hunk)
 
-    def write(self, fp):
+    def write(self, fp, numbered=False):
+        if numbered:
+            _b, _h, _a = self.before, self.hunk, self.after
+            nlen = len(str(len(self.hunk) + 1))
+            self.before = ["%s%s" % (' '*(nlen+2), l) for l in self.before]
+            self.hunk = ["%%%dd: %%s" % nlen % (n, l) for n, l in enumerate(self.hunk)]
+            self.after = ["%s%s" % (' '*(nlen+2), l) for l in self.after]
         delta = len(self.before) + len(self.after)
         if self.after and self.after[-1] == '\\ No newline at end of file\n':
             delta -= 1
@@ -163,6 +169,8 @@
                  (self.fromline, fromlen, self.toline, tolen,
                   self.proc and (' ' + self.proc)))
         fp.write(''.join(self.before + self.hunk + self.after))
+        if numbered:
+            self.before, self.hunk, self.after = _b, _h, _a
 
     pretty = write
 
@@ -172,6 +180,11 @@
     def __repr__(self):
         return '<hunk %r@%d>' % (self.filename(), self.fromline)
 
+def split_hunk(h, n):
+    h1 = hunk(h.header, h.fromline, h.toline, h.proc, h.before, h.hunk[:n], [])
+    h2 = hunk(h.header, h.fromline + n, h.toline + n, h.proc, [], h.hunk[n:], h.after)
+    return (h1, h2)
+
 def parsepatch(fp):
     """patch -> [] of hunks """
     class parser(object):
@@ -267,10 +280,11 @@
     resp_all = [None]   # this two are changed from inside prompt,
     resp_file = [None]  # so can't be usual variables
     applied = {}        # 'filename' -> [] of chunks
-    def prompt(query):
+    def prompt(query, at_hunk=False):
         """prompt query, and process base inputs
 
         - y/n for the rest of file
+        - p to split the hunk (if at_hunk is True)
         - y/n for the rest
         - ? (help)
         - q (quit)
@@ -287,6 +301,7 @@
             all_choices = {
                 'yes': _('&Yes, record this change'),
                 'no': _('&No, skip this change'),
+                'split': _('S&plit this hunk'),
                 'skip': _('&Skip remaining changes to this file'),
                 'file': _('Record remaining changes to this &file'),
                 'done': _('&Done, skip remaining changes and files'),
@@ -294,14 +309,17 @@
                 'quit': _('&Quit, recording no changes'),
                 'help': _('&?'),
             }
-            choices = (all_choices['yes'],
+            choices = [all_choices['yes'],
                     all_choices['no'],
                     all_choices['skip'],
                     all_choices['file'],
                     all_choices['done'],
                     all_choices['all'],
                     all_choices['quit'],
-                    all_choices['help'],)
+                    all_choices['help'],]
+            if at_hunk:
+                choices.insert(2, all_choices['split'])
+                resps = _('[Ynpsfdaq?]')
             r = ui.promptchoice("%s %s" % (query, resps), choices)
             choice = [k for k in all_choices if all_choices[k] == choices[r]][0]
             if choice == 'help':
@@ -309,9 +327,10 @@
                 c = doc.find(_('y - record this change'))
                 doc_lines = doc[c:].splitlines()
                 if not at_hunk:
-                    doc_lines = [l for l in doc_lines if not l.startswith('p - split')]
+                    doc_lines = [l for l in doc_lines
+                                 if not l.strip().startswith('p - split')]
                 else:
-                    doc_lines = filter(
+                    doc_lines = map(
                         lambda l: l.replace('(if you are currently at a hunk)', ''),
                         doc_lines
                     )
@@ -322,6 +341,8 @@
                 ret = True
             elif choice == 'no':
                 ret = False
+            elif choice == 'split':
+                ret = 'split'
             elif choice == 'skip':
                 ret = resp_file[0] = False
             elif choice == 'file':
@@ -361,10 +382,26 @@
             if resp_file[0] is None and resp_all[0] is None:
                 chunk.pretty(ui)
             r = total == 1 and prompt(_('record this change to %r?') %
-                                      chunk.filename()) \
+                                      chunk.filename(), at_hunk=True) \
                            or  prompt(_('record change %d/%d to %r?') %
-                                      (pos, total, chunk.filename()))
-            if r:
+                                      (pos, total, chunk.filename()),
+                                      at_hunk=True)
+            if r == 'split':
+                chunk.pretty(ui, numbered=True)
+                ns = [int(n) for n in raw_input('line numbers? 0 ').split(' ') if n]
+                ns = sorted(list(set(ns)), reverse=True)
+                invalid_ns = map(str, filter(lambda n: n >= len(chunk.hunk) or n < 0, ns))
+                if invalid_ns:
+                    ui.write(_('invalid line number: %s\n') % ' '.join(invalid_ns))
+                    chunks.append(chunk)
+                    continue
+                for n in ns:
+                    h1, h2 = split_hunk(chunk, n)
+                    chunks.append(h2)
+                    chunk = h1
+                    total += 1
+                chunks.append(chunk)
+            elif r:
                 if fixoffset:
                     chunk = copy.copy(chunk)
                     chunk.toline += fixoffset
diff --git a/tests/test-record.out b/tests/test-record.out
--- a/tests/test-record.out
+++ b/tests/test-record.out
@@ -184,7 +184,7 @@
  9
  10
 +11
-record this change to 'plain'? [Ynsfdaq?] % modify end of plain file, no EOL
+record this change to 'plain'? [Ynpsfdaq?] % modify end of plain file, no EOL
 diff --git a/plain b/plain
 1 hunks, 1 lines changed
 examine changes to 'plain'? [Ynsfdaq?] @@ -9,3 +9,4 @@
@@ -193,7 +193,7 @@
  11
 +cf81a2760718a74d44c0c2eecb72f659e63a69c5
 \ No newline at end of file
-record this change to 'plain'? [Ynsfdaq?] % modify end of plain file, add EOL
+record this change to 'plain'? [Ynpsfdaq?] % modify end of plain file, add EOL
 diff --git a/plain b/plain
 1 hunks, 2 lines changed
 examine changes to 'plain'? [Ynsfdaq?] @@ -9,4 +9,4 @@
@@ -203,7 +203,7 @@
 -cf81a2760718a74d44c0c2eecb72f659e63a69c5
 \ No newline at end of file
 +cf81a2760718a74d44c0c2eecb72f659e63a69c5
-record this change to 'plain'? [Ynsfdaq?] % modify beginning, trim end, record both
+record this change to 'plain'? [Ynpsfdaq?] % modify beginning, trim end, record both
 diff --git a/plain b/plain
 2 hunks, 4 lines changed
 examine changes to 'plain'? [Ynsfdaq?] @@ -1,4 +1,4 @@
@@ -212,13 +212,13 @@
  2
  3
  4
-record change 1/2 to 'plain'? [Ynsfdaq?] @@ -8,5 +8,3 @@
+record change 1/2 to 'plain'? [Ynpsfdaq?] @@ -8,5 +8,3 @@
  8
  9
  10
 -11
 -cf81a2760718a74d44c0c2eecb72f659e63a69c5
-record change 2/2 to 'plain'? [Ynsfdaq?] 
+record change 2/2 to 'plain'? [Ynpsfdaq?] 
 changeset:   11:d09ab1967dab
 tag:         tip
 user:        test
@@ -255,7 +255,7 @@
  7
  8
  9
-record change 1/2 to 'plain'? [Ynsfdaq?] @@ -4,7 +1,7 @@
+record change 1/2 to 'plain'? [Ynpsfdaq?] @@ -4,7 +1,7 @@
  4
  5
  6
@@ -264,7 +264,7 @@
  9
 -10
 +10.new
-record change 2/2 to 'plain'? [Ynsfdaq?] 
+record change 2/2 to 'plain'? [Ynpsfdaq?] 
 changeset:   12:44516c9708ae
 tag:         tip
 user:        test
@@ -291,7 +291,7 @@
  4
  5
  6
-record this change to 'plain'? [Ynsfdaq?] 
+record this change to 'plain'? [Ynpsfdaq?] 
 changeset:   13:3ebbace64a8d
 tag:         tip
 user:        test
@@ -323,7 +323,7 @@
  7
  8
  9
-record change 1/2 to 'plain'? [Ynsfdaq?] @@ -1,7 +4,6 @@
+record change 1/2 to 'plain'? [Ynpsfdaq?] @@ -1,7 +4,6 @@
  4
  5
  6
@@ -331,7 +331,7 @@
  8
  9
 -10.new
-record change 2/2 to 'plain'? [Ynsfdaq?] % add to beginning, middle, end
+record change 2/2 to 'plain'? [Ynpsfdaq?] % add to beginning, middle, end
 % record beginning, middle
 diff --git a/plain b/plain
 3 hunks, 7 lines changed
@@ -341,7 +341,7 @@
 +3
  4
  5
-record change 1/3 to 'plain'? [Ynsfdaq?] @@ -1,6 +4,8 @@
+record change 1/3 to 'plain'? [Ynpsfdaq?] @@ -1,6 +4,8 @@
  4
  5
 +5.new
@@ -350,14 +350,14 @@
  7
  8
  9
-record change 2/3 to 'plain'? [Ynsfdaq?] @@ -3,4 +8,6 @@
+record change 2/3 to 'plain'? [Ynpsfdaq?] @@ -3,4 +8,6 @@
  6
  7
  8
  9
 +10
 +11
-record change 3/3 to 'plain'? [Ynsfdaq?] 
+record change 3/3 to 'plain'? [Ynpsfdaq?] 
 changeset:   15:c1c639d8b268
 tag:         tip
 user:        test
@@ -388,7 +388,7 @@
  9
 +10
 +11
-record this change to 'plain'? [Ynsfdaq?] 
+record this change to 'plain'? [Ynpsfdaq?] 
 changeset:   16:80b74bbc7808
 tag:         tip
 user:        test
@@ -411,7 +411,7 @@
 examine changes to 'subdir/a'? [Ynsfdaq?] @@ -1,1 +1,2 @@
  a
 +a
-record this change to 'subdir/a'? [Ynsfdaq?] 
+record this change to 'subdir/a'? [Ynpsfdaq?] 
 changeset:   18:33ff5c4fb017
 tag:         tip
 user:        test
@@ -500,7 +500,7 @@
  a
  a
 +a
-record this change to 'subdir/f1'? [Ynsfdaq?] 
+record this change to 'subdir/f1'? [Ynpsfdaq?] 
 changeset:   22:a891589cb933
 tag:         tip
 user:        test
@@ -525,7 +525,7 @@
  a
  a
 +b
-record this change to 'subdir/f1'? [Ynsfdaq?] 
+record this change to 'subdir/f1'? [Ynpsfdaq?] 
 changeset:   23:befa0dae6201
 tag:         tip
 user:        test
@@ -551,7 +551,7 @@
  a
  b
 +c
-record this change to 'subdir/f1'? [Ynsfdaq?] 
+record this change to 'subdir/f1'? [Ynpsfdaq?] 
 changeset:   24:8fd83ff53ce6
 tag:         tip
 user:        test
@@ -577,7 +577,7 @@
  b
  c
 +d
-record this change to 'subdir/f1'? [Ynsfdaq?] 
+record this change to 'subdir/f1'? [Ynpsfdaq?] 
 changeset:   25:49b3838dc9e7
 tag:         tip
 user:        test


More information about the Mercurial-devel mailing list