431 return getattr(self._hunk, name) |
431 return getattr(self._hunk, name) |
432 |
432 |
433 def __repr__(self): |
433 def __repr__(self): |
434 return '<hunk %r@%d>' % (self.filename(), self.fromline) |
434 return '<hunk %r@%d>' % (self.filename(), self.fromline) |
435 |
435 |
436 def filterpatch(ui, chunks, chunkselector): |
436 def filterpatch(ui, chunks, chunkselector, operation=None): |
437 """interactively filter patch chunks into applied-only chunks""" |
437 """interactively filter patch chunks into applied-only chunks""" |
438 chunks = list(chunks) |
438 chunks = list(chunks) |
439 # convert chunks list into structure suitable for displaying/modifying |
439 # convert chunks list into structure suitable for displaying/modifying |
440 # with curses. create a list of headers only. |
440 # with curses. create a list of headers only. |
441 headers = [c for c in chunks if isinstance(c, patchmod.header)] |
441 headers = [c for c in chunks if isinstance(c, patchmod.header)] |
444 if len(headers) == 0: |
444 if len(headers) == 0: |
445 return [], {} |
445 return [], {} |
446 uiheaders = [uiheader(h) for h in headers] |
446 uiheaders = [uiheader(h) for h in headers] |
447 # let user choose headers/hunks/lines, and mark their applied flags |
447 # let user choose headers/hunks/lines, and mark their applied flags |
448 # accordingly |
448 # accordingly |
449 ret = chunkselector(ui, uiheaders) |
449 ret = chunkselector(ui, uiheaders, operation=operation) |
450 appliedhunklist = [] |
450 appliedhunklist = [] |
451 for hdr in uiheaders: |
451 for hdr in uiheaders: |
452 if (hdr.applied and |
452 if (hdr.applied and |
453 (hdr.special() or len([h for h in hdr.hunks if h.applied]) > 0)): |
453 (hdr.special() or len([h for h in hdr.hunks if h.applied]) > 0)): |
454 appliedhunklist.append(hdr) |
454 appliedhunklist.append(hdr) |
464 else: |
464 else: |
465 fixoffset += hnk.removed - hnk.added |
465 fixoffset += hnk.removed - hnk.added |
466 |
466 |
467 return (appliedhunklist, ret) |
467 return (appliedhunklist, ret) |
468 |
468 |
469 def chunkselector(ui, headerlist): |
469 def chunkselector(ui, headerlist, operation=None): |
470 """ |
470 """ |
471 curses interface to get selection of chunks, and mark the applied flags |
471 curses interface to get selection of chunks, and mark the applied flags |
472 of the chosen chunks. |
472 of the chosen chunks. |
473 """ |
473 """ |
474 ui.write(_('starting interactive selection\n')) |
474 ui.write(_('starting interactive selection\n')) |
475 chunkselector = curseschunkselector(headerlist, ui) |
475 chunkselector = curseschunkselector(headerlist, ui, operation) |
476 f = signal.getsignal(signal.SIGTSTP) |
476 f = signal.getsignal(signal.SIGTSTP) |
477 curses.wrapper(chunkselector.main) |
477 curses.wrapper(chunkselector.main) |
478 if chunkselector.initerr is not None: |
478 if chunkselector.initerr is not None: |
479 raise error.Abort(chunkselector.initerr) |
479 raise error.Abort(chunkselector.initerr) |
480 # ncurses does not restore signal handler for SIGTSTP |
480 # ncurses does not restore signal handler for SIGTSTP |
484 def testdecorator(testfn, f): |
484 def testdecorator(testfn, f): |
485 def u(*args, **kwargs): |
485 def u(*args, **kwargs): |
486 return f(testfn, *args, **kwargs) |
486 return f(testfn, *args, **kwargs) |
487 return u |
487 return u |
488 |
488 |
489 def testchunkselector(testfn, ui, headerlist): |
489 def testchunkselector(testfn, ui, headerlist, operation=None): |
490 """ |
490 """ |
491 test interface to get selection of chunks, and mark the applied flags |
491 test interface to get selection of chunks, and mark the applied flags |
492 of the chosen chunks. |
492 of the chosen chunks. |
493 """ |
493 """ |
494 chunkselector = curseschunkselector(headerlist, ui) |
494 chunkselector = curseschunkselector(headerlist, ui, operation) |
495 if testfn and os.path.exists(testfn): |
495 if testfn and os.path.exists(testfn): |
496 testf = open(testfn) |
496 testf = open(testfn) |
497 testcommands = map(lambda x: x.rstrip('\n'), testf.readlines()) |
497 testcommands = map(lambda x: x.rstrip('\n'), testf.readlines()) |
498 testf.close() |
498 testf.close() |
499 while True: |
499 while True: |
500 if chunkselector.handlekeypressed(testcommands.pop(0), test=True): |
500 if chunkselector.handlekeypressed(testcommands.pop(0), test=True): |
501 break |
501 break |
502 return chunkselector.opts |
502 return chunkselector.opts |
503 |
503 |
504 class curseschunkselector(object): |
504 class curseschunkselector(object): |
505 def __init__(self, headerlist, ui): |
505 def __init__(self, headerlist, ui, operation=None): |
506 # put the headers into a patch object |
506 # put the headers into a patch object |
507 self.headerlist = patch(headerlist) |
507 self.headerlist = patch(headerlist) |
508 |
508 |
509 self.ui = ui |
509 self.ui = ui |
510 self.opts = {} |
510 self.opts = {} |
553 # stores optional text for a commit comment provided by the user |
553 # stores optional text for a commit comment provided by the user |
554 self.commenttext = "" |
554 self.commenttext = "" |
555 |
555 |
556 # if the last 'toggle all' command caused all changes to be applied |
556 # if the last 'toggle all' command caused all changes to be applied |
557 self.waslasttoggleallapplied = True |
557 self.waslasttoggleallapplied = True |
|
558 |
|
559 # affects some ui text |
|
560 self.operation = operation |
558 |
561 |
559 def uparrowevent(self): |
562 def uparrowevent(self): |
560 """ |
563 """ |
561 try to select the previous item to the current item that has the |
564 try to select the previous item to the current item that has the |
562 most-indented level. for example, if a hunk is selected, try to select |
565 most-indented level. for example, if a hunk is selected, try to select |