Mercurial > hg
comparison mercurial/crecord.py @ 38047:dabc2237963c
crecord: fallback to text mode if diffs are too big for curses mode
crecord uses curses.newpad to create a region that we can then scroll around in
by moving the main 'screen' as a veiwport into the (probably larger than the
actual screen) pad. Internally, at least in ncurses, pads are implemented using
windows, which have their dimensions limited to a certain size. Depending on
compilation options for ncurses, this size might be pretty small: (signed)
short, or it might be larger ((signed) int).
crecord wants to have enough room to have all of the contents of the main area
of the chunkselector in the pad; this means that the full size with everything
expanded must be less than these (undocumented, afaict) limits.
It's not easy to write tests for this because the limits are platform- and
installation- dependent and undocumented / unqueryable, as far as I can tell.
Differential Revision: https://phab.mercurial-scm.org/D3577
author | Kyle Lippincott <spectral@google.com> |
---|---|
date | Thu, 17 May 2018 23:11:24 -0700 |
parents | f0b6fbea00cf |
children | 1978abdb216c |
comparison
equal
deleted
inserted
replaced
38046:ee7b6fa52d9d | 38047:dabc2237963c |
---|---|
62 curses.error | 62 curses.error |
63 except ImportError: | 63 except ImportError: |
64 # wcurses is not shipped on Windows by default, or python is not | 64 # wcurses is not shipped on Windows by default, or python is not |
65 # compiled with curses | 65 # compiled with curses |
66 curses = False | 66 curses = False |
67 | |
68 class fallbackerror(error.Abort): | |
69 """Error that indicates the client should try to fallback to text mode.""" | |
70 # Inherits from error.Abort so that existing behavior is preserved if the | |
71 # calling code does not know how to fallback. | |
67 | 72 |
68 def checkcurses(ui): | 73 def checkcurses(ui): |
69 """Return True if the user wants to use curses | 74 """Return True if the user wants to use curses |
70 | 75 |
71 This method returns True if curses is found (and that python is built with | 76 This method returns True if curses is found (and that python is built with |
527 origsigtstp = sentinel = object() | 532 origsigtstp = sentinel = object() |
528 if util.safehasattr(signal, 'SIGTSTP'): | 533 if util.safehasattr(signal, 'SIGTSTP'): |
529 origsigtstp = signal.getsignal(signal.SIGTSTP) | 534 origsigtstp = signal.getsignal(signal.SIGTSTP) |
530 try: | 535 try: |
531 curses.wrapper(chunkselector.main) | 536 curses.wrapper(chunkselector.main) |
532 if chunkselector.initerr is not None: | 537 if chunkselector.initexc is not None: |
533 raise error.Abort(chunkselector.initerr) | 538 raise chunkselector.initexc |
534 # ncurses does not restore signal handler for SIGTSTP | 539 # ncurses does not restore signal handler for SIGTSTP |
535 finally: | 540 finally: |
536 if origsigtstp is not sentinel: | 541 if origsigtstp is not sentinel: |
537 signal.signal(signal.SIGTSTP, origsigtstp) | 542 signal.signal(signal.SIGTSTP, origsigtstp) |
538 return chunkselector.opts | 543 return chunkselector.opts |
1716 | 1721 |
1717 def _main(self, stdscr): | 1722 def _main(self, stdscr): |
1718 self.stdscr = stdscr | 1723 self.stdscr = stdscr |
1719 # error during initialization, cannot be printed in the curses | 1724 # error during initialization, cannot be printed in the curses |
1720 # interface, it should be printed by the calling code | 1725 # interface, it should be printed by the calling code |
1721 self.initerr = None | 1726 self.initexc = None |
1722 self.yscreensize, self.xscreensize = self.stdscr.getmaxyx() | 1727 self.yscreensize, self.xscreensize = self.stdscr.getmaxyx() |
1723 | 1728 |
1724 curses.start_color() | 1729 curses.start_color() |
1725 try: | 1730 try: |
1726 curses.use_default_colors() | 1731 curses.use_default_colors() |
1749 self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1 | 1754 self.numpadlines = self.getnumlinesdisplayed(ignorefolding=True) + 1 |
1750 | 1755 |
1751 try: | 1756 try: |
1752 self.chunkpad = curses.newpad(self.numpadlines, self.xscreensize) | 1757 self.chunkpad = curses.newpad(self.numpadlines, self.xscreensize) |
1753 except curses.error: | 1758 except curses.error: |
1754 self.initerr = _('this diff is too large to be displayed') | 1759 self.initexc = fallbackerror( |
1760 _('this diff is too large to be displayed')) | |
1755 return | 1761 return |
1756 # initialize selecteditemendline (initial start-line is 0) | 1762 # initialize selecteditemendline (initial start-line is 0) |
1757 self.selecteditemendline = self.getnumlinesdisplayed( | 1763 self.selecteditemendline = self.getnumlinesdisplayed( |
1758 self.currentselecteditem, recursechildren=False) | 1764 self.currentselecteditem, recursechildren=False) |
1759 | 1765 |