75 def nextsibling(self): |
75 def nextsibling(self): |
76 """ |
76 """ |
77 Return the closest next item of the same type where there are no items |
77 Return the closest next item of the same type where there are no items |
78 of different types between the current item and this closest item. |
78 of different types between the current item and this closest item. |
79 If no such item exists, return None. |
79 If no such item exists, return None. |
80 |
|
81 """ |
80 """ |
82 raise NotImplementedError("method must be implemented by subclass") |
81 raise NotImplementedError("method must be implemented by subclass") |
83 |
82 |
84 def prevsibling(self): |
83 def prevsibling(self): |
85 """ |
84 """ |
86 Return the closest previous item of the same type where there are no |
85 Return the closest previous item of the same type where there are no |
87 items of different types between the current item and this closest item. |
86 items of different types between the current item and this closest item. |
88 If no such item exists, return None. |
87 If no such item exists, return None. |
89 |
|
90 """ |
88 """ |
91 raise NotImplementedError("method must be implemented by subclass") |
89 raise NotImplementedError("method must be implemented by subclass") |
92 |
90 |
93 def parentitem(self): |
91 def parentitem(self): |
94 raise NotImplementedError("method must be implemented by subclass") |
92 raise NotImplementedError("method must be implemented by subclass") |
107 If skipFolded == True, and the current item is folded, then the child |
105 If skipFolded == True, and the current item is folded, then the child |
108 items that are hidden due to folding will be skipped when determining |
106 items that are hidden due to folding will be skipped when determining |
109 the next item. |
107 the next item. |
110 |
108 |
111 If it is not possible to get the next item, return None. |
109 If it is not possible to get the next item, return None. |
112 |
|
113 """ |
110 """ |
114 try: |
111 try: |
115 itemfolded = self.folded |
112 itemfolded = self.folded |
116 except AttributeError: |
113 except AttributeError: |
117 itemfolded = False |
114 itemfolded = False |
161 If skipFolded == True, and the current item is folded, then the items |
158 If skipFolded == True, and the current item is folded, then the items |
162 that are hidden due to folding will be skipped when determining the |
159 that are hidden due to folding will be skipped when determining the |
163 next item. |
160 next item. |
164 |
161 |
165 If it is not possible to get the previous item, return None. |
162 If it is not possible to get the previous item, return None. |
166 |
|
167 """ |
163 """ |
168 if constrainlevel: |
164 if constrainlevel: |
169 return self.prevsibling() |
165 return self.prevsibling() |
170 else: |
166 else: |
171 # try previous sibling's last child's last child, |
167 # try previous sibling's last child's last child, |
188 return self.parentitem() |
184 return self.parentitem() |
189 |
185 |
190 class patch(patchnode, list): # todo: rename patchroot |
186 class patch(patchnode, list): # todo: rename patchroot |
191 """ |
187 """ |
192 list of header objects representing the patch. |
188 list of header objects representing the patch. |
193 |
|
194 """ |
189 """ |
195 def __init__(self, headerlist): |
190 def __init__(self, headerlist): |
196 self.extend(headerlist) |
191 self.extend(headerlist) |
197 # add parent patch object reference to each header |
192 # add parent patch object reference to each header |
198 for header in self: |
193 for header in self: |
485 magically get the current height and width of the window (without initscr) |
480 magically get the current height and width of the window (without initscr) |
486 |
481 |
487 this is a rip-off of a rip-off - taken from the bpython code. it is |
482 this is a rip-off of a rip-off - taken from the bpython code. it is |
488 useful / necessary because otherwise curses.initscr() must be called, |
483 useful / necessary because otherwise curses.initscr() must be called, |
489 which can leave the terminal in a nasty state after exiting. |
484 which can leave the terminal in a nasty state after exiting. |
490 |
|
491 """ |
485 """ |
492 h, w = struct.unpack( |
486 h, w = struct.unpack( |
493 "hhhh", fcntl.ioctl(_origstdout, termios.TIOCGWINSZ, "\000"*8))[0:2] |
487 "hhhh", fcntl.ioctl(_origstdout, termios.TIOCGWINSZ, "\000"*8))[0:2] |
494 return h, w |
488 return h, w |
495 |
489 |
496 def chunkselector(ui, headerlist): |
490 def chunkselector(ui, headerlist): |
497 """ |
491 """ |
498 curses interface to get selection of chunks, and mark the applied flags |
492 curses interface to get selection of chunks, and mark the applied flags |
499 of the chosen chunks. |
493 of the chosen chunks. |
500 |
|
501 """ |
494 """ |
502 ui.write(_('starting interactive selection\n')) |
495 ui.write(_('starting interactive selection\n')) |
503 chunkselector = curseschunkselector(headerlist, ui) |
496 chunkselector = curseschunkselector(headerlist, ui) |
504 f = signal.getsignal(signal.SIGTSTP) |
497 f = signal.getsignal(signal.SIGTSTP) |
505 curses.wrapper(chunkselector.main) |
498 curses.wrapper(chunkselector.main) |
516 |
509 |
517 def testchunkselector(testfn, ui, headerlist): |
510 def testchunkselector(testfn, ui, headerlist): |
518 """ |
511 """ |
519 test interface to get selection of chunks, and mark the applied flags |
512 test interface to get selection of chunks, and mark the applied flags |
520 of the chosen chunks. |
513 of the chosen chunks. |
521 |
|
522 """ |
514 """ |
523 chunkselector = curseschunkselector(headerlist, ui) |
515 chunkselector = curseschunkselector(headerlist, ui) |
524 if testfn and os.path.exists(testfn): |
516 if testfn and os.path.exists(testfn): |
525 testf = open(testfn) |
517 testf = open(testfn) |
526 testcommands = map(lambda x: x.rstrip('\n'), testf.readlines()) |
518 testcommands = map(lambda x: x.rstrip('\n'), testf.readlines()) |
593 the first hunkline of a hunk is currently selected, then select the |
585 the first hunkline of a hunk is currently selected, then select the |
594 hunk itself. |
586 hunk itself. |
595 |
587 |
596 if the currently selected item is already at the top of the screen, |
588 if the currently selected item is already at the top of the screen, |
597 scroll the screen down to show the new-selected item. |
589 scroll the screen down to show the new-selected item. |
598 |
|
599 """ |
590 """ |
600 currentitem = self.currentselecteditem |
591 currentitem = self.currentselecteditem |
601 |
592 |
602 nextitem = currentitem.previtem(constrainlevel=False) |
593 nextitem = currentitem.previtem(constrainlevel=False) |
603 |
594 |
614 currently selected item. otherwise, select (if possible) the |
605 currently selected item. otherwise, select (if possible) the |
615 parent-item of the currently selected item. |
606 parent-item of the currently selected item. |
616 |
607 |
617 if the currently selected item is already at the top of the screen, |
608 if the currently selected item is already at the top of the screen, |
618 scroll the screen down to show the new-selected item. |
609 scroll the screen down to show the new-selected item. |
619 |
|
620 """ |
610 """ |
621 currentitem = self.currentselecteditem |
611 currentitem = self.currentselecteditem |
622 nextitem = currentitem.previtem() |
612 nextitem = currentitem.previtem() |
623 # if there's no previous item on this level, try choosing the parent |
613 # if there's no previous item on this level, try choosing the parent |
624 if nextitem is None: |
614 if nextitem is None: |
638 a hunk is currently selected, then select the next hunk, if one exists, |
628 a hunk is currently selected, then select the next hunk, if one exists, |
639 or if not, the next header if one exists. |
629 or if not, the next header if one exists. |
640 |
630 |
641 if the currently selected item is already at the bottom of the screen, |
631 if the currently selected item is already at the bottom of the screen, |
642 scroll the screen up to show the new-selected item. |
632 scroll the screen up to show the new-selected item. |
643 |
|
644 """ |
633 """ |
645 #self.startprintline += 1 #debug |
634 #self.startprintline += 1 #debug |
646 currentitem = self.currentselecteditem |
635 currentitem = self.currentselecteditem |
647 |
636 |
648 nextitem = currentitem.nextitem(constrainlevel=False) |
637 nextitem = currentitem.nextitem(constrainlevel=False) |
655 def downarrowshiftevent(self): |
644 def downarrowshiftevent(self): |
656 """ |
645 """ |
657 if the cursor is already at the bottom chunk, scroll the screen up and |
646 if the cursor is already at the bottom chunk, scroll the screen up and |
658 move the cursor-position to the subsequent chunk. otherwise, only move |
647 move the cursor-position to the subsequent chunk. otherwise, only move |
659 the cursor position down one chunk. |
648 the cursor position down one chunk. |
660 |
|
661 """ |
649 """ |
662 # todo: update docstring |
650 # todo: update docstring |
663 |
651 |
664 currentitem = self.currentselecteditem |
652 currentitem = self.currentselecteditem |
665 nextitem = currentitem.nextitem() |
653 nextitem = currentitem.nextitem() |
678 self.currentselecteditem = nextitem |
666 self.currentselecteditem = nextitem |
679 |
667 |
680 def rightarrowevent(self): |
668 def rightarrowevent(self): |
681 """ |
669 """ |
682 select (if possible) the first of this item's child-items. |
670 select (if possible) the first of this item's child-items. |
683 |
|
684 """ |
671 """ |
685 currentitem = self.currentselecteditem |
672 currentitem = self.currentselecteditem |
686 nextitem = currentitem.firstchild() |
673 nextitem = currentitem.firstchild() |
687 |
674 |
688 # turn off folding if we want to show a child-item |
675 # turn off folding if we want to show a child-item |
698 def leftarrowevent(self): |
685 def leftarrowevent(self): |
699 """ |
686 """ |
700 if the current item can be folded (i.e. it is an unfolded header or |
687 if the current item can be folded (i.e. it is an unfolded header or |
701 hunk), then fold it. otherwise try select (if possible) the parent |
688 hunk), then fold it. otherwise try select (if possible) the parent |
702 of this item. |
689 of this item. |
703 |
|
704 """ |
690 """ |
705 currentitem = self.currentselecteditem |
691 currentitem = self.currentselecteditem |
706 |
692 |
707 # try to fold the item |
693 # try to fold the item |
708 if not isinstance(currentitem, uihunkline): |
694 if not isinstance(currentitem, uihunkline): |
723 |
709 |
724 def leftarrowshiftevent(self): |
710 def leftarrowshiftevent(self): |
725 """ |
711 """ |
726 select the header of the current item (or fold current item if the |
712 select the header of the current item (or fold current item if the |
727 current item is already a header). |
713 current item is already a header). |
728 |
|
729 """ |
714 """ |
730 currentitem = self.currentselecteditem |
715 currentitem = self.currentselecteditem |
731 |
716 |
732 if isinstance(currentitem, uiheader): |
717 if isinstance(currentitem, uiheader): |
733 if not currentitem.folded: |
718 if not currentitem.folded: |
773 |
758 |
774 def toggleapply(self, item=None): |
759 def toggleapply(self, item=None): |
775 """ |
760 """ |
776 toggle the applied flag of the specified item. if no item is specified, |
761 toggle the applied flag of the specified item. if no item is specified, |
777 toggle the flag of the currently selected item. |
762 toggle the flag of the currently selected item. |
778 |
|
779 """ |
763 """ |
780 if item is None: |
764 if item is None: |
781 item = self.currentselecteditem |
765 item = self.currentselecteditem |
782 |
766 |
783 item.applied = not item.applied |
767 item.applied = not item.applied |
896 """ |
880 """ |
897 add whitespace to the end of a string in order to make it fill |
881 add whitespace to the end of a string in order to make it fill |
898 the screen in the x direction. the current cursor position is |
882 the screen in the x direction. the current cursor position is |
899 taken into account when making this calculation. the string can span |
883 taken into account when making this calculation. the string can span |
900 multiple lines. |
884 multiple lines. |
901 |
|
902 """ |
885 """ |
903 y, xstart = window.getyx() |
886 y, xstart = window.getyx() |
904 width = self.xscreensize |
887 width = self.xscreensize |
905 # turn tabs into spaces |
888 # turn tabs into spaces |
906 instr = instr.expandtabs(4) |
889 instr = instr.expandtabs(4) |
925 |
908 |
926 if align == True, whitespace is added to the printed string such that |
909 if align == True, whitespace is added to the printed string such that |
927 the string stretches to the right border of the window. |
910 the string stretches to the right border of the window. |
928 |
911 |
929 if showwhtspc == True, trailing whitespace of a string is highlighted. |
912 if showwhtspc == True, trailing whitespace of a string is highlighted. |
930 |
|
931 """ |
913 """ |
932 # preprocess the text, converting tabs to spaces |
914 # preprocess the text, converting tabs to spaces |
933 text = text.expandtabs(4) |
915 text = text.expandtabs(4) |
934 # strip \n, and convert control characters to ^[char] representation |
916 # strip \n, and convert control characters to ^[char] representation |
935 text = re.sub(r'[\x00-\x08\x0a-\x1f]', |
917 text = re.sub(r'[\x00-\x08\x0a-\x1f]', |
1040 |
1022 |
1041 def getstatusprefixstring(self, item): |
1023 def getstatusprefixstring(self, item): |
1042 """ |
1024 """ |
1043 create a string to prefix a line with which indicates whether 'item' |
1025 create a string to prefix a line with which indicates whether 'item' |
1044 is applied and/or folded. |
1026 is applied and/or folded. |
1045 |
1027 """ |
1046 """ |
1028 |
1047 # create checkbox string |
1029 # create checkbox string |
1048 if item.applied: |
1030 if item.applied: |
1049 if not isinstance(item, uihunkline) and item.partial: |
1031 if not isinstance(item, uihunkline) and item.partial: |
1050 checkbox = "[~]" |
1032 checkbox = "[~]" |
1051 else: |
1033 else: |
1074 def printheader(self, header, selected=False, towin=True, |
1056 def printheader(self, header, selected=False, towin=True, |
1075 ignorefolding=False): |
1057 ignorefolding=False): |
1076 """ |
1058 """ |
1077 print the header to the pad. if countlines is True, don't print |
1059 print the header to the pad. if countlines is True, don't print |
1078 anything, but just count the number of lines which would be printed. |
1060 anything, but just count the number of lines which would be printed. |
1079 |
1061 """ |
1080 """ |
1062 |
1081 outstr = "" |
1063 outstr = "" |
1082 text = header.prettystr() |
1064 text = header.prettystr() |
1083 chunkindex = self.chunklist.index(header) |
1065 chunkindex = self.chunklist.index(header) |
1084 |
1066 |
1085 if chunkindex != 0 and not header.folded: |
1067 if chunkindex != 0 and not header.folded: |
1190 """ |
1172 """ |
1191 use __printitem() to print the the specified item.applied. |
1173 use __printitem() to print the the specified item.applied. |
1192 if item is not specified, then print the entire patch. |
1174 if item is not specified, then print the entire patch. |
1193 (hiding folded elements, etc. -- see __printitem() docstring) |
1175 (hiding folded elements, etc. -- see __printitem() docstring) |
1194 """ |
1176 """ |
|
1177 |
1195 if item is None: |
1178 if item is None: |
1196 item = self.headerlist |
1179 item = self.headerlist |
1197 if recursechildren: |
1180 if recursechildren: |
1198 self.linesprintedtopadsofar = 0 |
1181 self.linesprintedtopadsofar = 0 |
1199 |
1182 |
1231 |
1214 |
1232 if ignorefolding is True, then folded items are printed out. |
1215 if ignorefolding is True, then folded items are printed out. |
1233 |
1216 |
1234 if recursechildren is False, then only print the item without its |
1217 if recursechildren is False, then only print the item without its |
1235 child items. |
1218 child items. |
1236 |
1219 """ |
1237 """ |
1220 |
1238 if towin and self.outofdisplayedarea(): |
1221 if towin and self.outofdisplayedarea(): |
1239 return |
1222 return |
1240 |
1223 |
1241 selected = self.handleselection(item, recursechildren) |
1224 selected = self.handleselection(item, recursechildren) |
1242 |
1225 |
1279 to be printed to the display. the item will not be printed to the |
1262 to be printed to the display. the item will not be printed to the |
1280 display (pad). |
1263 display (pad). |
1281 if no item is given, assume the entire patch. |
1264 if no item is given, assume the entire patch. |
1282 if ignorefolding is True, folded items will be unfolded when counting |
1265 if ignorefolding is True, folded items will be unfolded when counting |
1283 the number of lines. |
1266 the number of lines. |
1284 |
1267 """ |
1285 """ |
1268 |
1286 # temporarily disable printing to windows by printstring |
1269 # temporarily disable printing to windows by printstring |
1287 patchdisplaystring = self.printitem(item, ignorefolding, |
1270 patchdisplaystring = self.printitem(item, ignorefolding, |
1288 recursechildren, towin=False) |
1271 recursechildren, towin=False) |
1289 numlines = len(patchdisplaystring) / self.xscreensize |
1272 numlines = len(patchdisplaystring) / self.xscreensize |
1290 return numlines |
1273 return numlines |
1314 initializing color pairs, and not curses.init_pair(). |
1297 initializing color pairs, and not curses.init_pair(). |
1315 |
1298 |
1316 attrlist is used to 'flavor' the returned color-pair. this information |
1299 attrlist is used to 'flavor' the returned color-pair. this information |
1317 is not stored in self.colorpairs. it contains attribute values like |
1300 is not stored in self.colorpairs. it contains attribute values like |
1318 curses.A_BOLD. |
1301 curses.A_BOLD. |
1319 |
1302 """ |
1320 """ |
1303 |
1321 if (name is not None) and name in self.colorpairnames: |
1304 if (name is not None) and name in self.colorpairnames: |
1322 # then get the associated color pair and return it |
1305 # then get the associated color pair and return it |
1323 colorpair = self.colorpairnames[name] |
1306 colorpair = self.colorpairnames[name] |
1324 else: |
1307 else: |
1325 if fgcolor is None: |
1308 if fgcolor is None: |
1446 """Toggle the amend flag. |
1429 """Toggle the amend flag. |
1447 |
1430 |
1448 When the amend flag is set, a commit will modify the most recently |
1431 When the amend flag is set, a commit will modify the most recently |
1449 committed changeset, instead of creating a new changeset. Otherwise, a |
1432 committed changeset, instead of creating a new changeset. Otherwise, a |
1450 new changeset will be created (the normal commit behavior). |
1433 new changeset will be created (the normal commit behavior). |
1451 |
1434 """ |
1452 """ |
1435 |
1453 try: |
1436 try: |
1454 ver = float(util.version()[:3]) |
1437 ver = float(util.version()[:3]) |
1455 except ValueError: |
1438 except ValueError: |
1456 ver = 1 |
1439 ver = 1 |
1457 if ver < 2.19: |
1440 if ver < 2.19: |
1639 self.stdscr.refresh() |
1622 self.stdscr.refresh() |
1640 |
1623 |
1641 def main(self, stdscr): |
1624 def main(self, stdscr): |
1642 """ |
1625 """ |
1643 method to be wrapped by curses.wrapper() for selecting chunks. |
1626 method to be wrapped by curses.wrapper() for selecting chunks. |
1644 |
1627 """ |
1645 """ |
1628 |
1646 signal.signal(signal.SIGWINCH, self.sigwinchhandler) |
1629 signal.signal(signal.SIGWINCH, self.sigwinchhandler) |
1647 self.stdscr = stdscr |
1630 self.stdscr = stdscr |
1648 # error during initialization, cannot be printed in the curses |
1631 # error during initialization, cannot be printed in the curses |
1649 # interface, it should be printed by the calling code |
1632 # interface, it should be printed by the calling code |
1650 self.initerr = None |
1633 self.initerr = None |