XZise has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/210908

Change subject: [FEAT] PatchManager: Review like git --patch
......................................................................

[FEAT] PatchManager: Review like git --patch

Reviewing diffs is with this patch similar to git's --patch option in
git checkout for example. It uses context and allows to split two
adjacent hunks and to move freely through the hunks.

Change-Id: I14065ab892a05284f92a5cce0fb4dc40bc7c42d7
---
M pywikibot/diff.py
1 file changed, 123 insertions(+), 40 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core 
refs/changes/08/210908/1

diff --git a/pywikibot/diff.py b/pywikibot/diff.py
index fb5667f..e09becf 100644
--- a/pywikibot/diff.py
+++ b/pywikibot/diff.py
@@ -11,6 +11,7 @@
 
 
 import difflib
+import math
 import sys
 
 from collections import Sequence
@@ -358,53 +359,135 @@
 
     def review_hunks(self):
         """Review hunks."""
-        help_msg = ['y -> accept this hunk',
-                    'n -> do not accept this hunk',
-                    's -> do not accept this hunk and stop reviewing',
-                    'a -> accept this hunk and all other pending',
-                    'r -> review later',
-                    'h -> help',
-                    ]
+        def find_pending(start, end):
+            step = -1 if start > end else +1
+            for pending in range(start, end, step):
+                if super_hunks[pending].reviewed == Hunk.PENDING:
+                    return pending
 
-        question = 'Accept this hunk?'
-        answers = [('yes', 'y'), ('no', 'n'), ('stop', 's'), ('all', 'a'),
-                   ('review', 'r'), ('help', 'h')]
-        actions = {'y': Hunk.APPR,
-                   'n': Hunk.NOT_APPR,
-                   's': Hunk.NOT_APPR,
-                   'a': Hunk.APPR,
-                   'r': Hunk.PENDING,
-                   }
+        help_msg = {'y': 'accept this hunk',
+                    'n': 'do not accept this hunk',
+                    'q': 'do not accept this hunk and quit reviewing',
+                    'a': 'accept this hunk and all other pending',
+                    'd': 'do not apply this hunk or any of the later hunks in 
the file',
+                    'g': 'select a hunk to go to',
+                    #'/': 'search for a hunk matching the given regex',
+                    'j': 'leave this hunk undecided, see next undecided hunk',
+                    'J': 'leave this hunk undecided, see next hunk',
+                    'k': 'leave this hunk undecided, see previous undecided 
hunk',
+                    'K': 'leave this hunk undecided, see previous hunk',
+                    's': 'split this hunk into smaller ones',
+                    '?': 'help',
+                    }
 
-        pending = [h for h in self.hunks if h.reviewed == h.PENDING]
+        super_hunks = self._generate_super_hunks(h for h in self.hunks if 
h.reviewed == Hunk.PENDING)
+        position = 0
 
-        while pending:
+        while any(any(hunk.reviewed == Hunk.PENDING for hunk in super_hunk)
+                  for super_hunk in super_hunks):
 
-            hunk = pending.pop(0)
+            super_hunk = super_hunks[position]
 
-            pywikibot.output(self._generate_diff([hunk]))
-            choice = pywikibot.input_choice(question, answers, default='r',
-                                            automatic_quit=False)
+            next_pending = find_pending(position + 1, len(super_hunks))
+            prev_pending = find_pending(position - 1, -1)
 
-            if choice in actions.keys():
-                hunk.reviewed = actions[choice]
-            if choice == 's':
-                while pending:
-                    hunk = pending.pop(0)
-                    hunk.reviewed = hunk.NOT_APPR
-                break
-            elif choice == 'a':
-                while pending:
-                    hunk = pending.pop(0)
-                    hunk.reviewed = hunk.APPR
-                break
-            elif choice == 'h':
-                pywikibot.output(u'\03{purple}%s\03{default}' % 
u'\n'.join(help_msg))
-                pending.insert(0, hunk)
-            elif choice == 'r':
-                pending.append(hunk)
+            answers = ['y', 'n', 'q', 'a', 'd', 'g']
+            if next_pending is not None:
+                answers += ['j']
+            if position < len(super_hunks) - 1:
+                answers += ['J']
+            if prev_pending is not None:
+                answers += ['k']
+            if position > 0:
+                answers += ['K']
+            if len(super_hunk) > 1:
+                answers += ['s']
+            answers += ['?']
 
-        return
+            pywikibot.output(self._generate_diff(super_hunk))
+            choice = pywikibot.input('Accept this hunk [' + ','.join(answers) 
+ ']?')
+            if choice not in answers:
+                choice = '?'
+
+            if choice == 'y' or choice == 'n':
+                super_hunk.reviewed = Hunk.APPR if choice == 'y' else 
Hunk.NOT_APPR
+                if next_pending is not None:
+                    position = next_pending
+                else:
+                    position = find_pending(0, position)
+            elif choice == 'q':
+                for super_hunk in super_hunks:
+                    for hunk in super_hunk:
+                        if hunk.reviewed == Hunk.PENDING:
+                            hunk.reviewed = Hunk.NOT_APPR
+            elif choice == 'a' or choice == 'd':
+                for super_hunk in super_hunks[position:]:
+                    for hunk in super_hunk:
+                        if hunk.reviewed == Hunk.PENDING:
+                            hunk.reviewed = Hunk.APPR if choice == 'a' else 
Hunk.NOT_APPR
+                position = find_pending(0, position)
+            elif choice == 'g':
+                hunk_list = []
+                rng_width = 18
+                for index, super_hunk in enumerate(super_hunks, start=1):
+                    if super_hunk.reviewed == Hunk.PENDING:
+                        status = ' '
+                    elif super_hunk.reviewed == Hunk.APPR:
+                        status = '+'
+                    elif super_hunk.reviewed == Hunk.NOT_APPR:
+                        status = '-'
+                    else:
+                        assert(False)
+                    if super_hunk[0].a_rng[1] - super_hunk[0].a_rng[0] > 0:
+                        mode = '-'
+                        first = self.a[super_hunk[0].a_rng[0]]
+                    else:
+                        mode = '+'
+                        first = self.b[super_hunk[0].b_rng[0]]
+                    hunk_list += [(status, index,
+                                   format_range_unified(*super_hunk.a_ctx) +
+                                   format_range_unified(*super_hunk.b_ctx),
+                                   mode, first)]
+                    rng_width = max(len(hunk_list[-1][2]), rng_width)
+                line_template = ('{0}{1} {2: >' +
+                                 str(int(math.log10(len(super_hunks)) + 1)) +
+                                 '}:  {3: <' + str(rng_width) + '}  {4}{5}')
+                hunk_list = ''.join(
+                    line_template.format(
+                        '*' if hunk_entry[1] == position + 1 else ' ', 
*hunk_entry)
+                    for hunk_entry in hunk_list)
+                if not hunk_list.endswith('\n'):
+                    hunk_list += '\n'
+                next_hunk = pywikibot.input(hunk_list + 'Go to which hunk?')
+                try:
+                    next_hunk_position = int(next_hunk) - 1
+                except ValueError:
+                    next_hunk_position = False
+                if (next_hunk_position is False or
+                        not 0 <= next_hunk_position < len(super_hunks)):
+                    pywikibot.output('Invalid hunk number 
"{0}"'.format(next_hunk))
+                else:
+                    position = next_hunk_position
+            elif choice == 'j':
+                position = next_pending
+            elif choice == 'J':
+                position += 1
+            elif choice == 'k':
+                position = prev_pending
+            elif choice == 'K':
+                position -= 1
+            elif choice == 's':
+                pywikibot.output('Split into {0} 
chunks'.format(len(super_hunk._hunks)))
+                super_hunks = (super_hunks[:position] +
+                               super_hunks[position].split() +
+                               super_hunks[position + 1:])
+            elif choice == '?':
+                pywikibot.output(
+                    '\03{purple}%s\03{default}' % '\n'.join(
+                        '{0} -> {1}'.format(answer, help_msg[answer])
+                        for answer in answers))
+            else:
+                assert(False)
 
     def apply(self):
         """Apply changes. If there are undecided changes, ask to review."""

-- 
To view, visit https://gerrit.wikimedia.org/r/210908
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I14065ab892a05284f92a5cce0fb4dc40bc7c42d7
Gerrit-PatchSet: 1
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <commodorefabia...@gmx.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to