3
from userinteractor import UserInteractor, UserOption
4
from errors import NoColor
10
def __init__(self, patches, color=None):
11
if color is True or color is None:
13
from colordiff import DiffWriter
14
from terminal import has_ansi_colors
16
self.diff_stream = DiffWriter(sys.stdout)
20
self.diff_stream = sys.stdout
23
raise NoBzrtoolsColor()
24
self.diff_stream = sys.stdout
26
self.diff_stream = sys.stdout
28
self.standard_options = [
29
UserOption('y', self._selected, self.strings['select_desc'],
31
UserOption('n', self._unselected, self.strings['unselect_desc']),
32
UserOption('d', UserInteractor.FINISH, 'done, skip to the end.'),
33
UserOption('i', self._invert,
34
'invert the current selection status of all hunks.'),
35
UserOption('s', self._status,
36
'show selection status of all hunks.'),
37
UserOption('q', UserInteractor.QUIT, 'quit')
41
UserOption('y', UserInteractor.FINISH, self.strings['finish_desc'],
43
UserOption('r', UserInteractor.RESTART,
44
'restart the hunk selection loop.'),
45
UserOption('s', self._status,
46
'show selection status of all hunks.'),
47
UserOption('i', self._invert,
48
'invert the current selection status of all hunks.'),
49
UserOption('q', UserInteractor.QUIT, 'quit')
7
def __init__(self, char, action, help, default=False):
10
self.default = default
14
Option('n', 'shelve', 'shelve this change for the moment.',
16
Option('y', 'keep', 'keep this change in your tree.'),
17
Option('d', 'done', 'done, skip to the end.'),
18
Option('i', 'invert', 'invert the current selection of all hunks.'),
19
Option('s', 'status', 'show status of hunks.'),
20
Option('q', 'quit', 'quit')
24
Option('y', 'continue', 'proceed to shelve selected changes.',
26
Option('r', 'restart', 'restart the hunk selection loop.'),
27
Option('s', 'status', 'show status of hunks.'),
28
Option('i', 'invert', 'invert the current selection of all hunks.'),
29
Option('q', 'quit', 'quit')
32
def __init__(self, patches):
52
33
self.patches = patches
53
34
self.total_hunks = 0
55
self.interactor = UserInteractor()
56
self.interactor.set_item_callback(self._hunk_callback)
57
self.interactor.set_start_callback(self._start_callback)
58
self.interactor.set_end_callback(self._end_callback)
60
35
for patch in patches:
61
36
for hunk in patch.hunks:
62
# everything's selected by default
37
# everything's shelved by default
63
38
hunk.selected = True
64
39
self.total_hunks += 1
65
# we need a back pointer in the callbacks
67
self.interactor.add_item(hunk)
69
# Called at the start of the main loop
70
def _start_callback(self):
71
self.last_printed = -1
72
self.interactor.set_prompt(self.strings['prompt'])
73
self.interactor.set_options(self.standard_options)
75
# Called at the end of the item loop, return False to indicate that the
76
# interaction isn't finished and the confirmation prompt should be displayed
77
def _end_callback(self):
79
self.interactor.set_prompt(self.strings['end_prompt'])
80
self.interactor.set_options(self.end_options)
83
# Called once for each hunk
84
def _hunk_callback(self, hunk, count):
85
if self.last_printed != count:
86
self.diff_stream.write(str(hunk.patch.get_header()))
87
self.diff_stream.write(str(hunk))
88
self.last_printed = count
91
self.interactor.get_option('y').default = True
92
self.interactor.get_option('n').default = False
94
self.interactor.get_option('y').default = False
95
self.interactor.get_option('n').default = True
97
# The user chooses to (un)shelve a hunk
98
def _selected(self, hunk):
102
# The user chooses to keep a hunk
103
def _unselected(self, hunk):
104
hunk.selected = False
107
# The user chooses to invert the selection
108
def _invert(self, hunk):
41
def __get_option(self, char):
42
for opt in self.standard_options:
45
raise Exception('Option "%s" not found!' % char)
47
def __select_loop(self):
49
for patch in self.patches:
52
while i < len(patch.hunks):
55
print patch.get_header(), hunk
59
prompt = 'Keep this change? (%d of %d)' \
60
% (j, self.total_hunks)
63
self.__get_option('n').default = True
64
self.__get_option('y').default = False
66
self.__get_option('n').default = False
67
self.__get_option('y').default = True
69
action = self.__ask_user(prompt, self.standard_options)
73
elif action == 'shelve':
75
elif action == 'done':
77
elif action == 'invert':
78
self.__invert_selection()
81
elif action == 'status':
84
elif action == 'quit':
91
if self.total_hunks == 0:
96
if not self.__select_loop():
101
prompt = "Shelve these changes, or restart?"
102
action = self.__ask_user(prompt, self.end_options)
104
if action == 'continue':
107
elif action == 'quit':
109
elif action == 'status':
111
elif action == 'invert':
112
self.__invert_selection()
113
elif action == 'restart':
117
for patch in self.patches:
119
for hunk in patch.hunks:
125
for patch in self.patches:
132
def __invert_selection(self):
109
133
for patch in self.patches:
110
134
for hunk in patch.hunks:
111
135
if hunk.__dict__.has_key('selected'):
112
136
hunk.selected = not hunk.selected
114
138
hunk.selected = True
118
# The user wants to see the status
119
def _status(self, hunk=None):
140
def __show_status(self):
120
141
print '\nStatus:'
121
142
for patch in self.patches:
122
143
print ' %s' % patch.oldname
125
146
for hunk in patch.hunks:
126
147
if hunk.selected:
131
print ' ', self.strings['status_selected'] % selected
132
print ' ', self.strings['status_unselected'] % unselected
152
print ' %d hunks to be shelved' % shelve
153
print ' %d hunks to be kept' % keep
135
# Tell the interactor we're not done with this item
139
if self.total_hunks == 0 or not self.interactor.interact():
140
# False from interact means they chose to quit
143
# Go through each patch and collect all selected/unselected hunks
144
for patch in self.patches:
146
patch.unselected = []
147
for hunk in patch.hunks:
149
patch.selected.append(hunk)
151
patch.unselected.append(hunk)
153
# Now build two lists, one of selected patches the other unselected
154
selected_patches = []
155
unselected_patches = []
157
for patch in self.patches:
158
if len(patch.selected):
159
tmp = copy.copy(patch)
160
tmp.hunks = tmp.selected
163
selected_patches.append(tmp)
165
if len(patch.unselected):
166
tmp = copy.copy(patch)
167
tmp.hunks = tmp.unselected
170
unselected_patches.append(tmp)
172
return (selected_patches, unselected_patches)
174
class ShelveHunkSelector(HunkSelector):
175
def __init__(self, patches, color=None):
177
self.strings['status_selected'] = '%d hunks to be shelved'
178
self.strings['status_unselected'] = '%d hunks to be kept'
179
self.strings['select_desc'] = 'shelve this change.'
180
self.strings['unselect_desc'] = 'keep this change in your tree.'
181
self.strings['finish_desc'] = 'shelve selected changes.'
182
self.strings['prompt'] = 'Shelve this change? (%(count)d of %(total)d)'
183
self.strings['end_prompt'] = 'Shelve these changes?'
184
HunkSelector.__init__(self, patches, color)
186
class UnshelveHunkSelector(HunkSelector):
187
def __init__(self, patches, color=None):
189
self.strings['status_selected'] = '%d hunks to be unshelved'
190
self.strings['status_unselected'] = '%d hunks left on shelf'
191
self.strings['select_desc'] = 'unshelve this change.'
192
self.strings['unselect_desc'] = 'leave this change on the shelf.'
193
self.strings['finish_desc'] = 'unshelve selected changes.'
194
self.strings['prompt'] = 'Unshelve this change? ' \
195
'(%(count)d of %(total)d)'
196
self.strings['end_prompt'] = 'Unshelve these changes?'
197
HunkSelector.__init__(self, patches, color)
156
if sys.platform == "win32":
159
return msvcrt.getche()
164
fd = sys.stdin.fileno()
165
settings = termios.tcgetattr(fd)
168
ch = sys.stdin.read(1)
170
termios.tcsetattr(fd, termios.TCSADRAIN, settings)
173
def __ask_user(self, prompt, options):
175
sys.stdout.write(prompt)
176
sys.stdout.write(' [')
180
sys.stdout.write(opt.char)
181
sys.stdout.write('?] (%s): ' % default.char)
183
response = self.__getchar()
185
# default, which we see as newline, is 'n'
186
if response in ['\n', '\r', '\r\n']:
187
response = default.char
189
print response # because echo is off
192
if opt.char == response:
196
print ' %s - %s' % (opt.char, opt.help)