mercurial/crecord.py
changeset 28579 f571ea254f75
parent 28543 f7874de435c5
child 28580 8b41ad798fb7
equal deleted inserted replaced
28578:66d085e55ecd 28579:f571ea254f75
    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