summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHelmut Grohne <helmut@subdivi.de>2016-12-09 11:54:25 +0100
committerHelmut Grohne <helmut@subdivi.de>2016-12-09 11:54:25 +0100
commitf6f8d6d50b7823266684807eb4cad1db3e74c0d9 (patch)
tree1ca6bc1647ae74f267c19afed0b25df042024ef5
parentc285a5ff7665f41684a1f100679b6361ad6383af (diff)
downloadtcvt-f6f8d6d50b7823266684807eb4cad1db3e74c0d9.tar.gz
push the refresh logic into the Terminal class
One advantage of doing so is that the main function becomes simpler. Another advantage is that the Terminal class has better knowledge of when refreshes are actually needed. It also means that one more refresh call can be coalesced into the logic. The major downside is that it requires annotating all screen operations.
-rwxr-xr-xtcvt.py66
1 files changed, 50 insertions, 16 deletions
diff --git a/tcvt.py b/tcvt.py
index edb102f..3831a83 100755
--- a/tcvt.py
+++ b/tcvt.py
@@ -315,13 +315,14 @@ class Terminal:
self.lastchar = ord(b' ')
self.columns = columns
self.reverse = reverse
+ self.need_refresh = None
def switchmode(self):
if isinstance(self.screen, Columns):
self.screen = Simple(self.realscreen)
else:
self.screen = Columns(self.realscreen, self.columns)
- self.screen.refresh()
+ self.request_refresh()
def resized(self):
# The refresh call causes curses to notice the new dimensions.
@@ -332,15 +333,32 @@ class Terminal:
reverse=self.reverse)
except BadWidth:
self.screen = Simple(self.realscreen)
+ self.request_refresh()
def resizepty(self, ptyfd):
ym, xm = self.screen.getmaxyx()
fcntl.ioctl(ptyfd, termios.TIOCSWINSZ,
struct.pack("HHHH", ym, xm, 0, 0))
+ def refresh_needed(self):
+ return self.need_refresh is not None
+
+ def request_refresh(self):
+ if self.need_refresh is None:
+ self.need_refresh = time.time()
+
+ def refresh(self, minwait=0):
+ if self.need_refresh is None:
+ return
+ if minwait > 0 and self.need_refresh + minwait > time.time():
+ return
+ self.screen.refresh()
+ self.need_refresh = None
+
def addch(self, char):
self.lastchar = char
self.screen.addch(char)
+ self.request_refresh()
def __enter__(self):
self.realscreen = curses.initscr()
@@ -371,27 +389,32 @@ class Terminal:
def do_cr(self):
self.screen.relmove(0, -9999)
+ self.request_refresh()
def do_cub(self, n):
self.screen.relmove(0, -n)
+ self.request_refresh()
def do_cub1(self):
self.do_cub(1)
def do_cud(self, n):
self.screen.relmove(n, 0)
+ self.request_refresh()
def do_cud1(self):
self.do_cud(1)
def do_cuf(self, n):
self.screen.relmove(0, n)
+ self.request_refresh()
def do_cuf1(self):
self.do_cuf(1)
def do_cuu(self, n):
self.screen.relmove(-n, 0)
+ self.request_refresh()
def do_cuu1(self):
self.do_cuu(1)
@@ -399,6 +422,7 @@ class Terminal:
def do_dch(self, n):
for _ in range(n):
self.screen.delch()
+ self.request_refresh()
def do_dch1(self):
self.do_dch(1)
@@ -406,6 +430,7 @@ class Terminal:
def do_dl(self, n):
for _ in range(n):
self.screen.deleteln()
+ self.request_refresh()
def do_dl1(self):
self.do_dl(1)
@@ -413,39 +438,49 @@ class Terminal:
def do_ech(self, n):
for _ in range(n):
self.screen.addch(ord(b' '))
+ self.request_refresh()
def do_ed(self):
self.screen.clrtobot()
+ self.request_refresh()
def do_el(self):
self.screen.clrtoeol()
+ self.request_refresh()
def do_el1(self):
y, x = self.screen.getyx()
- self.screen.move(y, 0)
- for _ in range(x):
- self.screen.addch(ord(b' '))
+ if x > 0:
+ self.screen.move(y, 0)
+ for _ in range(x):
+ self.screen.addch(ord(b' '))
+ self.request_refresh()
def do_home(self):
self.screen.move(0, 0)
+ self.request_refresh()
def do_hpa(self, n):
y, _ = self.screen.getyx()
self.screen.move(y, n)
+ self.request_refresh()
def do_ht(self):
y, x = self.screen.getyx()
_, xm = self.screen.getmaxyx()
x = min(x + 8 - x % 8, xm - 1)
self.screen.move(y, x)
+ self.request_refresh()
def do_ich(self, n):
for _ in range(n):
self.screen.insch(ord(b' '))
+ self.request_refresh()
def do_il(self, n):
for _ in range(n):
self.screen.insertln()
+ self.request_refresh()
def do_il1(self):
self.do_il(1)
@@ -458,6 +493,7 @@ class Terminal:
self.screen.move(y, 0)
else:
self.screen.move(y+1, 0)
+ self.request_refresh()
def do_invis(self):
self.screen.attron(curses.A_INVIS)
@@ -468,6 +504,7 @@ class Terminal:
def do_vpa(self, n):
_, x = self.screen.getyx()
self.screen.move(n, x)
+ self.request_refresh()
def feed_reset(self):
if self.graphics_font:
@@ -595,14 +632,17 @@ class Terminal:
if len(parts) != 2:
raise ValueError("feed esc [ %r H" % parts)
self.screen.move(*map((-1).__add__, map(int, parts)))
+ self.request_refresh()
elif prev == bytearray(b'2') and char == ord(b'J'):
self.screen.move(0, 0)
self.screen.clrtobot()
+ self.request_refresh()
elif char == ord(b'd') and prev.isdigit():
self.do_vpa(int(prev) - 1)
elif char == ord(b'b') and prev.isdigit():
for _ in range(int(prev)):
self.screen.addch(self.lastchar)
+ self.request_refresh()
elif char == ord(b'G') and prev.isdigit():
self.do_hpa(int(prev) - 1)
elif char == ord(b'K') and prev == b'1':
@@ -705,11 +745,10 @@ def main():
with process as masterfd:
with Terminal(acsc, options.columns, reverse=options.reverse) as t:
t.resizepty(masterfd)
- refreshpending = None
while True:
+ timeout = 0 if t.refresh_needed() else None
try:
- res, _, _ = select.select([0, masterfd], [], [],
- refreshpending and 0)
+ res = select.select([0, masterfd], [], [], timeout)[0]
except select.error as err:
if err.args[0] == errno.EINTR:
t.resized()
@@ -731,6 +770,7 @@ def main():
else:
if "TCVT_DEVEL" in os.environ:
raise ValueError("getch returned %d" % key)
+ t.refresh(0.1)
elif masterfd in res:
try:
data = os.read(masterfd, 1024)
@@ -746,15 +786,9 @@ def main():
t.feed(char)
except ValueError:
t.feed_reset()
- if refreshpending is None:
- refreshpending = time.time() + 0.1
- elif refreshpending is not None:
- t.screen.refresh()
- refreshpending = None
- if refreshpending is not None and \
- refreshpending < time.time():
- t.screen.refresh()
- refreshpending = None
+ t.refresh(0.1)
+ else:
+ t.refresh()
except ExecutionError as err:
print(str(err))
sys.exit(255)