~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to hunk_selector.py

  • Committer: Aaron Bentley
  • Date: 2008-01-11 03:01:54 UTC
  • Revision ID: aaron.bentley@utoronto.ca-20080111030154-apm50v0b0tu93prh
Support branch6 formats in rspush

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import sys
 
2
 
 
3
from userinteractor import UserInteractor, UserOption
 
4
from errors import NoColor
 
5
import copy
 
6
 
 
7
class HunkSelector:
 
8
    strings = {}
 
9
 
 
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():
 
16
                    self.diff_stream = DiffWriter(sys.stdout,
 
17
                                                  check_style=False)
 
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()
 
25
                self.diff_stream = sys.stdout
 
26
        else:
 
27
            self.diff_stream = sys.stdout
 
28
 
 
29
        self.standard_options = [
 
30
            UserOption('y', self._selected, self.strings['select_desc'],
 
31
                default=True),
 
32
            UserOption('n', self._unselected, self.strings['unselect_desc']),
 
33
            UserOption('d', UserInteractor.FINISH, 'done, skip to the end.'),
 
34
            UserOption('i', self._invert,
 
35
                'invert the current selection status of all hunks.'),
 
36
            UserOption('s', self._status,
 
37
                'show selection status of all hunks.'),
 
38
            UserOption('q', UserInteractor.QUIT, 'quit')
 
39
        ]
 
40
 
 
41
        self.end_options = [
 
42
            UserOption('y', UserInteractor.FINISH, self.strings['finish_desc'],
 
43
                default=True),
 
44
            UserOption('r', UserInteractor.RESTART,
 
45
                'restart the hunk selection loop.'),
 
46
            UserOption('s', self._status,
 
47
                'show selection status of all hunks.'),
 
48
            UserOption('i', self._invert,
 
49
                'invert the current selection status of all hunks.'),
 
50
            UserOption('q', UserInteractor.QUIT, 'quit')
 
51
        ]
 
52
 
 
53
        self.patches = patches
 
54
        self.total_hunks = 0
 
55
 
 
56
        self.interactor = UserInteractor()
 
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)
 
60
 
 
61
        for patch in patches:
 
62
            for hunk in patch.hunks:
 
63
                # everything's selected by default
 
64
                hunk.selected = True
 
65
                self.total_hunks += 1
 
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
 
71
    def _start_callback(self):
 
72
        self.last_printed = -1
 
73
        self.interactor.set_prompt(self.strings['prompt'])
 
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
 
78
    def _end_callback(self):
 
79
        self._status()
 
80
        self.interactor.set_prompt(self.strings['end_prompt'])
 
81
        self.interactor.set_options(self.end_options)
 
82
        return False
 
83
 
 
84
    # Called once for each hunk
 
85
    def _hunk_callback(self, hunk, count):
 
86
        if self.last_printed != count:
 
87
            self.diff_stream.write(str(hunk.patch.get_header()))
 
88
            self.diff_stream.write(str(hunk))
 
89
            self.last_printed = count
 
90
 
 
91
        if hunk.selected:
 
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
 
96
            self.interactor.get_option('n').default = True
 
97
 
 
98
    # The user chooses to (un)shelve a hunk
 
99
    def _selected(self, hunk):
 
100
        hunk.selected = True
 
101
        return True
 
102
 
 
103
    # The user chooses to keep a hunk
 
104
    def _unselected(self, hunk):
 
105
        hunk.selected = False
 
106
        return True
 
107
 
 
108
    # The user chooses to invert the selection
 
109
    def _invert(self, hunk):
 
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
 
116
        self._status()
 
117
        return False
 
118
 
 
119
    # The user wants to see the status
 
120
    def _status(self, hunk=None):
 
121
        print '\nStatus:'
 
122
        for patch in self.patches:
 
123
            print '  %s' % patch.oldname
 
124
            selected = 0
 
125
            unselected = 0
 
126
            for hunk in patch.hunks:
 
127
                if hunk.selected:
 
128
                    selected += 1
 
129
                else:
 
130
                    unselected += 1
 
131
 
 
132
            print '  ', self.strings['status_selected'] % selected
 
133
            print '  ', self.strings['status_unselected'] % unselected
 
134
            print
 
135
 
 
136
        # Tell the interactor we're not done with this item
 
137
        return False
 
138
 
 
139
    def select(self):
 
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
 
145
        for patch in self.patches:
 
146
            patch.selected = []
 
147
            patch.unselected = []
 
148
            for hunk in patch.hunks:
 
149
                if hunk.selected:
 
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
 
 
158
        for patch in self.patches:
 
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)
 
174
 
 
175
class ShelveHunkSelector(HunkSelector):
 
176
    def __init__(self, patches, color=None):
 
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?'
 
185
        HunkSelector.__init__(self, patches, color)
 
186
 
 
187
class UnshelveHunkSelector(HunkSelector):
 
188
    def __init__(self, patches, color=None):
 
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?'
 
198
        HunkSelector.__init__(self, patches, color)