scripts: Fixed most flickering issues in RingIO
Two new tricks: 1. Hide the cursor while redrawing the ring buffer. 2. Build up the entire redraw in RAM first, and render everything in a single write call. These _mostly_ get rid of the cursor flickering issues in rapidly updating scripts.
This commit is contained in:
+34
-11
@@ -88,6 +88,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
self.add_watch(path, flags)
|
self.add_watch(path, flags)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -140,7 +141,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -158,24 +161,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
def iself(path):
|
def iself(path):
|
||||||
|
|||||||
+34
-11
@@ -3644,6 +3644,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
self.add_watch(path, flags)
|
self.add_watch(path, flags)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -3696,7 +3697,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -3714,24 +3717,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
# a representation of optionally key-mapped attrs
|
# a representation of optionally key-mapped attrs
|
||||||
|
|||||||
+34
-11
@@ -137,6 +137,7 @@ def rbydaddr(s):
|
|||||||
return tuple(addr)
|
return tuple(addr)
|
||||||
|
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -189,7 +190,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -207,24 +210,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
# a representation of optionally key-mapped attrs
|
# a representation of optionally key-mapped attrs
|
||||||
|
|||||||
+34
-11
@@ -171,6 +171,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
self.add_watch(path, flags)
|
self.add_watch(path, flags)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -223,7 +224,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -241,24 +244,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+34
-11
@@ -34,6 +34,7 @@ def openio(path, mode='r', buffering=-1):
|
|||||||
else:
|
else:
|
||||||
return open(path, mode, buffering)
|
return open(path, mode, buffering)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -86,7 +87,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -104,24 +107,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+34
-11
@@ -81,6 +81,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
self.add_watch(path, flags)
|
self.add_watch(path, flags)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -133,7 +134,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -151,24 +154,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
# parse different data representations
|
# parse different data representations
|
||||||
|
|||||||
+34
-11
@@ -72,6 +72,7 @@ else:
|
|||||||
else:
|
else:
|
||||||
self.add_watch(path, flags)
|
self.add_watch(path, flags)
|
||||||
|
|
||||||
|
# a pseudo-stdout ring buffer
|
||||||
class RingIO:
|
class RingIO:
|
||||||
def __init__(self, maxlen=None, head=False):
|
def __init__(self, maxlen=None, head=False):
|
||||||
self.maxlen = maxlen
|
self.maxlen = maxlen
|
||||||
@@ -124,7 +125,9 @@ class RingIO:
|
|||||||
if lines[-1]:
|
if lines[-1]:
|
||||||
self.tail.write(lines[-1])
|
self.tail.write(lines[-1])
|
||||||
|
|
||||||
|
# keep track of maximum drawn canvas
|
||||||
canvas_lines = 1
|
canvas_lines = 1
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
# did terminal size change?
|
# did terminal size change?
|
||||||
self.resize(self.maxlen)
|
self.resize(self.maxlen)
|
||||||
@@ -142,24 +145,44 @@ class RingIO:
|
|||||||
else:
|
else:
|
||||||
lines.popleft()
|
lines.popleft()
|
||||||
|
|
||||||
# first thing first, give ourself a canvas
|
# build up the redraw in memory first and render in a single
|
||||||
|
# write call, this minimizes flickering caused by the cursor
|
||||||
|
# jumping around
|
||||||
|
canvas = []
|
||||||
|
|
||||||
|
# hide the cursor
|
||||||
|
canvas.append('\x1b[?25l')
|
||||||
|
|
||||||
|
# give ourself a canvas
|
||||||
while RingIO.canvas_lines < len(lines):
|
while RingIO.canvas_lines < len(lines):
|
||||||
sys.stdout.write('\n')
|
canvas.append('\n')
|
||||||
RingIO.canvas_lines += 1
|
RingIO.canvas_lines += 1
|
||||||
|
|
||||||
# write lines from top to bottom so later lines overwrite earlier
|
# write lines from top to bottom so later lines overwrite earlier
|
||||||
# lines, note [xA/[xB stop at terminal boundaries
|
# lines, note xA/xB stop at terminal boundaries
|
||||||
for i, line in enumerate(lines):
|
for i, line in enumerate(lines):
|
||||||
# move cursor, clear line, disable/reenable line wrapping
|
# move to col 0
|
||||||
sys.stdout.write('\r')
|
canvas.append('\r')
|
||||||
|
# move up to line
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dA' % (len(lines)-1-i))
|
canvas.append('\x1b[%dA' % (len(lines)-1-i))
|
||||||
sys.stdout.write('\x1b[K')
|
# clear line
|
||||||
sys.stdout.write('\x1b[?7l')
|
canvas.append('\x1b[K')
|
||||||
sys.stdout.write(line)
|
# disable line wrap
|
||||||
sys.stdout.write('\x1b[?7h')
|
canvas.append('\x1b[?7l')
|
||||||
|
# print the line
|
||||||
|
canvas.append(line)
|
||||||
|
# enable line wrap
|
||||||
|
canvas.append('\x1b[?7h') # enable line wrap
|
||||||
|
# move back down
|
||||||
if len(lines)-1-i > 0:
|
if len(lines)-1-i > 0:
|
||||||
sys.stdout.write('\x1b[%dB' % (len(lines)-1-i))
|
canvas.append('\x1b[%dB' % (len(lines)-1-i))
|
||||||
|
|
||||||
|
# show the cursor again
|
||||||
|
canvas.append('\x1b[?25h')
|
||||||
|
|
||||||
|
# write to stdout and flush
|
||||||
|
sys.stdout.write(''.join(canvas))
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user