~abentley/bzrtools/bzrtools.dev

« back to all changes in this revision

Viewing changes to hunk_selector.py

  • Committer: Robert Collins
  • Date: 2005-10-24 07:01:08 UTC
  • mto: (147.1.42) (364.1.3 bzrtools)
  • mto: This revision was merged to the branch mainline in revision 324.
  • Revision ID: robertc@robertcollins.net-20051024070108-f85025066b05f809
use sets and strings to optimise finding indirect merges somewhat

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)