~abentley/bzrtools/bzrtools.dev

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