-
Notifications
You must be signed in to change notification settings - Fork 115
/
termsize
executable file
·101 lines (74 loc) · 2.78 KB
/
termsize
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python
# Get the current size of the terminal window, and set stty size accordingly.
# A replacement for xterm's resize program, with no X dependency.
# Useful when logged in over a serial line.
# Copyright 2013,2017 by Akkana Peck. Share and enjoy under the GPL v2 or later.
# In the unlikely event you ever need to *set* the terminal size, check out:
# https://github.com/zerorax/pyresize/blob/master/resize.py
import os, sys
import fcntl
import struct
import time
import re
import tty
import termios
import select
try:
import curses
except:
pass
# python3 has get_terminal size, but it doesn't actually query
# the terminal, just trusts current stty settings, which isn't
# useful here. But 3 has different open() characteristics so we
# have to detect version, not just features.
if (sys.version_info < (3, 0)):
ttyfd = open('/dev/tty', 'r+')
else:
# Python3 needs extra flags set, which requires a 2-step open process:
fd = os.open('/dev/tty', os.O_RDWR|os.O_NOCTTY)
ttyfd = open(fd, 'wb+', buffering=0)
def get_terminal_size_curses():
stdscr = curses.initscr()
rows, cols = stdscr.getmaxyx()
curses.endwin()
return rows, cols
def get_terminal_size_noncurses():
# The non-curses version works well under xterm, but in urxvt,
# the terminal echoes back the rows and columns, but in a way
# that makes it see those characters as input. I haven't
# found a way around that.
# Save the terminal state
fileno = sys.stdin.fileno()
stty_sav = termios.tcgetattr(sys.stdin)
fc_sav = fcntl.fcntl(fileno, fcntl.F_GETFL)
# Turn off echo.
stty_new = termios.tcgetattr(sys.stdin)
stty_new[3] = stty_new[3] & ~termios.ECHO
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, stty_new)
ttyfd.write(b'\033[7\033[r\033[999;999H\033[6n')
ttyfd.flush()
# Put stdin into cbreak mode.
# Python2 can use fd here, but in Python3 we have to get sys.stdin.fileno.
tty.setcbreak(sys.stdin)
# Nonblocking mode.
fcntl.fcntl(fileno, fcntl.F_SETFL, fc_sav | os.O_NONBLOCK)
try:
while True:
r, w, e = select.select([ttyfd], [], [])
if r:
output = sys.stdin.read()
break
finally:
# Reset the terminal back to normal cooked mode
termios.tcsetattr(fileno, termios.TCSAFLUSH, stty_sav)
fcntl.fcntl(fileno, fcntl.F_SETFL, fc_sav)
rows, cols = list(map(int, re.findall(r'\d+', output)))
return rows, cols
if __name__ == '__main__':
try:
rows, cols = get_terminal_size_curses()
except:
rows, cols = get_terminal_size_noncurses()
fcntl.ioctl(ttyfd, termios.TIOCSWINSZ,
struct.pack("HHHH", rows, cols, 0, 0))
print("Reset the terminal to %d rows, %d cols" % (rows, cols))