summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2017-01-05 20:26:13 +0100
committerHelmut Grohne <helmut@subdivi.de>2017-01-05 20:26:13 +0100
commita39db1ed4fc8b6e66779f9ae5b9341763c9d4c1f (patch)
treea4704c7c7f4f92037e19dd109b383ee570173d83
parentb8fb407411a4e5c0ed52ec33dc3c52e68837e341 (diff)
downloadtcvt-a39db1ed4fc8b6e66779f9ae5b9341763c9d4c1f.tar.gz
improve corner cases related to resizing and mode switching
A few operations would previously fail unexpectedly: * Running tcvt with many columns and a small terminal width would crash instead of falling back to a simple screen. * After switching the mode, column ordering would be lost. * Switching the mode from simple to columns after resizing could result in a crash. Instead of collecting the screen options and passing them down individually, the Terminal class now asks for a preconfigured screen factory. This should eliminate future potential for similar mistakes.
-rwxr-xr-xtcvt.py35
1 files changed, 18 insertions, 17 deletions
diff --git a/tcvt.py b/tcvt.py
index 3cdb957..c30f4e0 100755
--- a/tcvt.py
+++ b/tcvt.py
@@ -305,35 +305,34 @@ simple_characters = bytearray(
b'\xb4\xb6\xb7\xc3\xc4\xd6\xdc\xe4\xe9\xfc\xf6')
class Terminal:
- def __init__(self, acsc, columns, reverse=False):
+ def __init__(self, acsc, screenfactory):
self.mode = (self.feed_simple,)
self.realscreen = None
self.screen = None
self.fg = self.bg = 0
self.graphics_font = False
- self.graphics_chars = acsc # really initialized after
+ self.graphics_chars = acsc # really initialized in __enter__
self.lastchar = ord(b' ')
- self.columns = columns
- self.reverse = reverse
+ self.screenfactory = screenfactory
self.need_refresh = None
- def switchmode(self):
- if isinstance(self.screen, Columns):
+ def makescreen(self, switch=False):
+ try:
+ if isinstance(self.screen, Simple) ^ switch:
+ raise BadWidth("use simple screen")
+ self.screen = self.screenfactory(self.realscreen)
+ except BadWidth:
self.screen = Simple(self.realscreen)
- else:
- self.screen = Columns(self.realscreen, self.columns)
self.request_refresh()
+ def switchmode(self):
+ self.makescreen(True)
+
def resized(self):
# The refresh call causes curses to notice the new dimensions.
self.realscreen.refresh()
self.realscreen.clear()
- try:
- self.screen = Columns(self.realscreen, self.columns,
- reverse=self.reverse)
- except BadWidth:
- self.screen = Simple(self.realscreen)
- self.request_refresh()
+ self.makescreen()
def resizepty(self, ptyfd):
ym, xm = self.screen.getmaxyx()
@@ -366,8 +365,7 @@ class Terminal:
self.realscreen.keypad(1)
curses.start_color()
init_color_pairs()
- self.screen = Columns(self.realscreen, self.columns,
- reverse=self.reverse)
+ self.makescreen()
curses.noecho()
curses.raw()
self.graphics_chars = compose_dicts(self.graphics_chars, acs_map())
@@ -804,10 +802,13 @@ def main():
options, args = parser.parse_args()
keymapping, acsc = compute_keymap(symbolic_keymapping)
+ def screenfactory(realscreen):
+ return Columns(realscreen, options.columns, reverse=options.reverse)
+
process = ForkPty(args or [os.environ["SHELL"]], dict(TERM="ansi"))
try:
with process as masterfd:
- with Terminal(acsc, options.columns, reverse=options.reverse) as t:
+ with Terminal(acsc, screenfactory) as t:
t.resizepty(masterfd)
process.start()
while True: