40
class UseEditor(Exception):
41
"""Use an editor instead of selecting hunks."""
38
44
class ShelfReporter(object):
40
46
vocab = {'add file': 'Shelve adding file "%(path)s"?',
143
149
if reporter is None:
144
150
reporter = ShelfReporter()
145
151
self.reporter = reporter
152
config = self.work_tree.branch.get_config()
153
self.change_editor = config.get_change_editor(target_tree, work_tree)
154
self.work_tree.lock_tree_write()
148
157
def from_args(klass, diff_writer, revision=None, all=False, file_list=None,
168
177
target_tree = builtins._get_one_revision_tree('shelf2', revision,
169
178
tree.branch, tree)
170
179
files = builtins.safe_relpath_files(tree, file_list)
180
return klass(tree, target_tree, diff_writer, all, all, files,
174
return klass(tree, target_tree, diff_writer, all, all, files, message,
178
186
"""Interactively shelve the changes."""
211
219
shutil.rmtree(self.tempdir)
212
220
creator.finalize()
223
if self.change_editor is not None:
224
self.change_editor.finish()
225
self.work_tree.unlock()
214
228
def get_parsed_patch(self, file_id, invert=False):
215
229
"""Return a parsed version of a file's patch.
245
259
sys.stdout.flush()
248
def prompt_bool(self, question, long=False):
262
def prompt_bool(self, question, long=False, allow_editor=False):
249
263
"""Prompt the user with a yes/no question.
251
265
This may be overridden by self.auto. It may also *set* self.auto. It
259
prompt = ' [(y)es, (N)o, (f)inish, or (q)uit]'
275
editor_string = '(E)dit manually, '
276
prompt = ' [(y)es, (N)o, %s(f)inish, or (q)uit]' % editor_string
280
prompt = ' [yN%sfq?]' % editor_string
262
281
char = self.prompt(question + prompt)
284
elif char == 'e' and allow_editor:
265
286
elif char == 'f':
275
296
def handle_modify_text(self, creator, file_id):
297
"""Handle modified text, by using hunk selection or file editing.
299
:param creator: A ShelfCreator.
300
:param file_id: The id of the file that was modified.
301
:return: The number of changes.
303
work_tree_lines = self.work_tree.get_file_lines(file_id)
305
lines, change_count = self._select_hunks(creator, file_id,
308
lines, change_count = self._edit_file(file_id, work_tree_lines)
309
if change_count != 0:
310
creator.shelve_lines(file_id, lines)
313
def _select_hunks(self, creator, file_id, work_tree_lines):
276
314
"""Provide diff hunk selection for modified text.
278
316
If self.reporter.invert_diff is True, the diff is inverted so that
281
319
:param creator: a ShelfCreator
282
320
:param file_id: The id of the file to shelve.
321
:param work_tree_lines: Line contents of the file in the working tree.
283
322
:return: number of shelved hunks.
285
324
if self.reporter.invert_diff:
286
target_lines = self.work_tree.get_file_lines(file_id)
325
target_lines = work_tree_lines
288
327
target_lines = self.target_tree.get_file_lines(file_id)
289
textfile.check_text_lines(self.work_tree.get_file_lines(file_id))
328
textfile.check_text_lines(work_tree_lines)
290
329
textfile.check_text_lines(target_lines)
291
330
parsed = self.get_parsed_patch(file_id, self.reporter.invert_diff)
295
334
self.diff_writer.write(parsed.get_header())
296
335
for hunk in parsed.hunks:
297
336
self.diff_writer.write(str(hunk))
298
selected = self.prompt_bool(self.reporter.vocab['hunk'])
337
selected = self.prompt_bool(self.reporter.vocab['hunk'],
338
allow_editor=(self.change_editor
299
340
if not self.reporter.invert_diff:
300
341
selected = (not selected)
305
346
offset -= (hunk.mod_range - hunk.orig_range)
306
347
sys.stdout.flush()
307
if not self.reporter.invert_diff and (
308
len(parsed.hunks) == len(final_hunks)):
310
if self.reporter.invert_diff and len(final_hunks) == 0:
312
patched = patches.iter_patched_from_hunks(target_lines, final_hunks)
313
creator.shelve_lines(file_id, list(patched))
314
348
if self.reporter.invert_diff:
315
return len(final_hunks)
316
return len(parsed.hunks) - len(final_hunks)
349
change_count = len(final_hunks)
351
change_count = len(parsed.hunks) - len(final_hunks)
352
patched = patches.iter_patched_from_hunks(target_lines,
354
lines = list(patched)
355
return lines, change_count
357
def _edit_file(self, file_id, work_tree_lines):
359
:param file_id: id of the file to edit.
360
:param work_tree_lines: Line contents of the file in the working tree.
361
:return: (lines, change_region_count), where lines is the new line
362
content of the file, and change_region_count is the number of
365
lines = osutils.split_lines(self.change_editor.edit_file(file_id))
366
return lines, self._count_changed_regions(work_tree_lines, lines)
369
def _count_changed_regions(old_lines, new_lines):
370
matcher = patiencediff.PatienceSequenceMatcher(None, old_lines,
372
blocks = matcher.get_matching_blocks()
373
return len(blocks) - 2
319
376
class Unshelver(object):