~abentley/bzrtools/bzrtools.dev

0.1.18 by Michael Ellerman
Split out HunkSelector class.
1
#!/usr/bin/python
2
0.1.48 by Michael Ellerman
Move UserInteractor into a seperate file.
3
from userinteractor import UserInteractor, UserOption
0.1.58 by Michael Ellerman
Unshelve --pick was broken, because we deleted the whole patch, even when only
4
import copy
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
5
0.1.18 by Michael Ellerman
Split out HunkSelector class.
6
class HunkSelector:
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
7
    strings = {}
8
0.1.18 by Michael Ellerman
Split out HunkSelector class.
9
    def __init__(self, patches):
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
10
        self.standard_options = [
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
11
            UserOption('y', self._selected, self.strings['select_desc'],
12
                default=True),
13
            UserOption('n', self._unselected, self.strings['unselect_desc']),
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
14
            UserOption('d', UserInteractor.FINISH, 'done, skip to the end.'),
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
15
            UserOption('i', self._invert,
0.1.49 by Michael Ellerman
Ask "shelve this change" instead of "keep this change", which is hopefully
16
                'invert the current selection status of all hunks.'),
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
17
            UserOption('s', self._status,
18
                'show selection status of all hunks.'),
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
19
            UserOption('q', UserInteractor.QUIT, 'quit')
20
        ]
21
22
        self.end_options = [
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
23
            UserOption('y', UserInteractor.FINISH, self.strings['finish_desc'],
24
                default=True),
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
25
            UserOption('r', UserInteractor.RESTART,
26
                'restart the hunk selection loop.'),
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
27
            UserOption('s', self._status,
28
                'show selection status of all hunks.'),
29
            UserOption('i', self._invert,
0.1.49 by Michael Ellerman
Ask "shelve this change" instead of "keep this change", which is hopefully
30
                'invert the current selection status of all hunks.'),
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
31
            UserOption('q', UserInteractor.QUIT, 'quit')
32
        ]
33
0.1.18 by Michael Ellerman
Split out HunkSelector class.
34
        self.patches = patches
35
        self.total_hunks = 0
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
36
37
        self.interactor = UserInteractor()
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
38
        self.interactor.set_item_callback(self._hunk_callback)
39
        self.interactor.set_start_callback(self._start_callback)
40
        self.interactor.set_end_callback(self._end_callback)
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
41
0.1.18 by Michael Ellerman
Split out HunkSelector class.
42
        for patch in patches:
43
            for hunk in patch.hunks:
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
44
                # everything's selected by default
0.1.18 by Michael Ellerman
Split out HunkSelector class.
45
                hunk.selected = True
46
                self.total_hunks += 1
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
47
                # we need a back pointer in the callbacks
48
                hunk.patch = patch
49
                self.interactor.add_item(hunk)
50
51
    # Called at the start of the main loop
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
52
    def _start_callback(self):
0.1.51 by Michael Ellerman
Restart after a done was broken, and we weren't resetting the print logic at
53
        self.last_printed = -1
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
54
        self.interactor.set_prompt(self.strings['prompt'])
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
55
        self.interactor.set_options(self.standard_options)
56
57
    # Called at the end of the item loop, return False to indicate that the
58
    # interaction isn't finished and the confirmation prompt should be displayed
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
59
    def _end_callback(self):
60
        self._status()
61
        self.interactor.set_prompt(self.strings['end_prompt'])
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
62
        self.interactor.set_options(self.end_options)
63
        return False
64
65
    # Called once for each hunk
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
66
    def _hunk_callback(self, hunk, count):
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
67
        if self.last_printed != count:
68
            print hunk.patch.get_header(), hunk
69
            self.last_printed = count
70
71
        if hunk.selected:
0.1.49 by Michael Ellerman
Ask "shelve this change" instead of "keep this change", which is hopefully
72
            self.interactor.get_option('y').default = True
73
            self.interactor.get_option('n').default = False
74
        else:
75
            self.interactor.get_option('y').default = False
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
76
            self.interactor.get_option('n').default = True
77
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
78
    # The user chooses to (un)shelve a hunk
79
    def _selected(self, hunk):
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
80
        hunk.selected = True
81
        return True
82
83
    # The user chooses to keep a hunk
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
84
    def _unselected(self, hunk):
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
85
        hunk.selected = False
86
        return True
87
88
    # The user chooses to invert the selection
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
89
    def _invert(self, hunk):
0.1.18 by Michael Ellerman
Split out HunkSelector class.
90
        for patch in self.patches:
91
            for hunk in patch.hunks:
92
                if hunk.__dict__.has_key('selected'):
93
                    hunk.selected = not hunk.selected
94
                else:
95
                    hunk.selected = True
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
96
        self._status()
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
97
        return False
0.1.18 by Michael Ellerman
Split out HunkSelector class.
98
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
99
    # The user wants to see the status
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
100
    def _status(self, hunk=None):
0.1.18 by Michael Ellerman
Split out HunkSelector class.
101
        print '\nStatus:'
102
        for patch in self.patches:
103
            print '  %s' % patch.oldname
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
104
            selected = 0
105
            unselected = 0
0.1.18 by Michael Ellerman
Split out HunkSelector class.
106
            for hunk in patch.hunks:
107
                if hunk.selected:
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
108
                    selected += 1
0.1.18 by Michael Ellerman
Split out HunkSelector class.
109
                else:
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
110
                    unselected += 1
0.1.18 by Michael Ellerman
Split out HunkSelector class.
111
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
112
            print '  ', self.strings['status_selected'] % selected
113
            print '  ', self.strings['status_unselected'] % unselected
0.1.18 by Michael Ellerman
Split out HunkSelector class.
114
            print
115
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
116
        # Tell the interactor we're not done with this item
117
        return False
118
119
    def select(self):
0.1.58 by Michael Ellerman
Unshelve --pick was broken, because we deleted the whole patch, even when only
120
        if self.total_hunks == 0 or not self.interactor.interact():
121
            # False from interact means they chose to quit
122
            return ([], [])
123
124
        # Go through each patch and collect all selected/unselected hunks
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
125
        for patch in self.patches:
0.1.58 by Michael Ellerman
Unshelve --pick was broken, because we deleted the whole patch, even when only
126
            patch.selected = []
127
            patch.unselected = []
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
128
            for hunk in patch.hunks:
129
                if hunk.selected:
0.1.58 by Michael Ellerman
Unshelve --pick was broken, because we deleted the whole patch, even when only
130
                    patch.selected.append(hunk)
131
                else:
132
                    patch.unselected.append(hunk)
133
134
        # Now build two lists, one of selected patches the other unselected
135
        selected_patches = []
136
        unselected_patches = []
137
0.1.47 by Michael Ellerman
Refactored HunkSelector heavily to split out a UserInteractor class.
138
        for patch in self.patches:
0.1.58 by Michael Ellerman
Unshelve --pick was broken, because we deleted the whole patch, even when only
139
            if len(patch.selected):
140
                tmp = copy.copy(patch)
141
                tmp.hunks = tmp.selected
142
                del tmp.selected
143
                del tmp.unselected
144
                selected_patches.append(tmp)
145
146
            if len(patch.unselected):
147
                tmp = copy.copy(patch)
148
                tmp.hunks = tmp.unselected
149
                del tmp.selected
150
                del tmp.unselected
151
                unselected_patches.append(tmp)
152
153
        return (selected_patches, unselected_patches)
0.1.56 by Michael Ellerman
Make HunkSelector agnostic as to whether it's selecting for shelving or
154
155
class ShelveHunkSelector(HunkSelector):
156
    def __init__(self, patches):
157
        self.strings = {}
158
        self.strings['status_selected'] = '%d hunks to be shelved'
159
        self.strings['status_unselected'] = '%d hunks to be kept'
160
        self.strings['select_desc'] = 'shelve this change.'
161
        self.strings['unselect_desc'] = 'keep this change in your tree.'
162
        self.strings['finish_desc'] = 'shelve selected changes.'
163
        self.strings['prompt'] = 'Shelve this change? (%(count)d of %(total)d)'
164
        self.strings['end_prompt'] = 'Shelve these changes?'
165
        HunkSelector.__init__(self, patches)
166
167
class UnshelveHunkSelector(HunkSelector):
168
    def __init__(self, patches):
169
        self.strings = {}
170
        self.strings['status_selected'] = '%d hunks to be unshelved'
171
        self.strings['status_unselected'] = '%d hunks left on shelf'
172
        self.strings['select_desc'] = 'unshelve this change.'
173
        self.strings['unselect_desc'] = 'leave this change on the shelf.'
174
        self.strings['finish_desc'] = 'unshelve selected changes.'
175
        self.strings['prompt'] = 'Unshelve this change? ' \
176
            '(%(count)d of %(total)d)'
177
        self.strings['end_prompt'] = 'Unshelve these changes?'
178
        HunkSelector.__init__(self, patches)