Skip to content

Instantly share code, notes, and snippets.

@jancajthaml
Last active April 16, 2016 19:37
Show Gist options
  • Save jancajthaml/e0a7ee2c064ff4038f2c3e14139807f6 to your computer and use it in GitHub Desktop.
Save jancajthaml/e0a7ee2c064ff4038f2c3e14139807f6 to your computer and use it in GitHub Desktop.
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import signal
import os
import fcntl
import termios
import struct
class ExitException(Exception):
pass
def exit(signum, frame):
raise ExitException, "ESC key detected"
signal.signal(signal.SIGALRM, exit)
block = os.O_NONBLOCK if 'O_NONBLOCK' in dir(os) else (
os.NOBLOCK if 'NONBLOCK' in dir(os) else None)
r = sys.stdin.fileno()
w = sys.stdout.fileno()
r_flags = fcntl.fcntl(r, fcntl.F_GETFL)
if r_flags & block:
fcntl.fcntl(r, fcntl.F_SETFL, r_flags & ~block)
w_flags = fcntl.fcntl(w, fcntl.F_GETFL)
if w_flags & block:
fcntl.fcntl(w, fcntl.F_SETFL, w_flags | block)
y = 0
width = 0
height = 0
data = []
for i in range(0, 201, 1):
data.append(' line: {0}'.format(i + 1))
def render_scroll():
w = globals()['width']
h = globals()['height']
y = globals()['y']
data = globals()['data']
workingHeight = h - 6
start = max(0, min(
len(data) - workingHeight, len(data) - (workingHeight / 2) - y))
end = min(len(data), start + workingHeight)
cursor = (len(data) - y - 1) - start
view = []
pointer = 0
for i in range(start, end, 1):
line = '\033[2K' + data[i] + (' ' * w)[:-len(data[i])]
if pointer == cursor:
view.append('\x1B[47m{0}\x1B[0m'.format(line))
else:
view.append(line)
pointer += 1
if len(view) < h:
body = '\n'.join(view) + ((' ' * w) * (workingHeight - len(view)))
else:
body = '\n'.join(view)
return body
def render():
w = globals()['width']
header = (u'┌' + (u'─' * (w - 2)) + u'┐') + '\n' \
+ (u'│' + (' ' * (w - 2)) + u'│') + '\n' \
+ (u'└' + (u'─' * (w - 2)) + u'┘')
body = render_scroll()
footer = (u'┌' + (u'─' * (w - 2)) + u'┐') + '\n' \
+ (u'│' + (' ' * (w - 2)) + u'│') + '\n' \
+ (u'└' + (u'─' * (w - 2)) + u'┘')
screen = header + '\n' + body + '\n' + footer
sys.stdout.write(u'\033[0;0H' + screen)
def resize(*args):
h, w, hp, wp = struct.unpack('HHHH', fcntl.ioctl(0, termios.TIOCGWINSZ, struct.pack('HHHH', 0, 0, 0, 0))) # noqa
globals()['width'] = w
globals()['height'] = h
sys.stdout.write(u'\033[2J')
render()
def scroll(direction):
newY = min(len(globals()['data']) - 1, max(0, globals()['y'] + direction)) # noqa
if newY != globals()['y']:
globals()['y'] = newY
render()
def main():
signal.signal(signal.SIGWINCH, resize)
try:
sys.stdout.write('\033[?1049h\033[?25l')
resize()
r_old = termios.tcgetattr(r)
r_new = termios.tcgetattr(r)
r_new[3] = r_new[3] & ~termios.ICANON & ~termios.ECHO
termios.tcsetattr(r, termios.TCSANOW, r_new)
try:
while 1:
try:
a = sys.stdin.read(1)
if a == chr(27):
signal.setitimer(signal.ITIMER_REAL, 0.01, 0.01)
b = sys.stdin.read(1)
signal.setitimer(signal.ITIMER_REAL, 0)
if b == '[':
c = sys.stdin.read(1)
if c == 'A':
scroll(1)
elif c == 'B':
scroll(-1)
else:
break
continue
except IOError:
pass
except ExitException:
break
finally:
termios.tcsetattr(r, termios.TCSAFLUSH, r_old)
except KeyboardInterrupt:
pass
finally:
fcntl.fcntl(r, fcntl.F_SETFL, r_flags)
fcntl.fcntl(w, fcntl.F_SETFL, w_flags)
sys.stdout.write('\033[?1049l\033[?25h')
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment