Skip to content

Instantly share code, notes, and snippets.

@gunchev
Forked from jtriley/terminalsize.py
Last active December 8, 2021 14:23
Show Gist options
  • Save gunchev/c73af70357ff8bcfc3250ee6c84e164d to your computer and use it in GitHub Desktop.
Save gunchev/c73af70357ff8bcfc3250ee6c84e164d to your computer and use it in GitHub Desktop.
Get current terminal size on Linux, Mac, and Windows
#!/usr/bin/python
'''
Get width and height of console
works on Linux, OS X, Windows, Cygwin(Windows) originally retrieved from:
http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python
updated by Doncho Nikolaev Gunchev <dgunchev@gmail.com> to work with python 2 and 3, make pylint happy.
shutil.get_terminal_size() should do fine, however this worked a decade before it and demonstrates various
techniques to interact with the OS...
'''
from __future__ import absolute_import, print_function, division, unicode_literals
import os
import platform
import struct
import subprocess
def get_terminal_size():
"""Get width and height of console"""
current_os = platform.system()
if current_os in ['Linux', 'Darwin'] or current_os.startswith('CYGWIN'):
width_height = get_terminal_size_linux()
if current_os == 'Windows':
width_height = get_terminal_size_windows()
if width_height is None:
# needed for window's python in cygwin's xterm!
width_height = get_terminal_size_tput()
return width_height if width_height is not None else (80, 25)
def get_terminal_size_windows():
'''Return terminal size in Windows OS or None'''
try: # https://pycodequ.al/docs/pylint-messages/c0415-import-outside-toplevel.html
from ctypes import windll, create_string_buffer # pylint: disable=import-outside-toplevel
# stdin, stdout and stderr handles are -10, -11, -12
handle = windll.kernel32.GetStdHandle(-12)
csbi = create_string_buffer(22)
res = windll.kernel32.GetConsoleScreenBufferInfo(handle, csbi)
if res:
# bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, maxy
left, top, right, bottom = struct.unpack("hhhhHhhhhhh", csbi.raw)[5:9]
return right - left + 1, bottom - top + 1
except ImportError:
pass
return None
def get_terminal_size_tput():
'''Return terminal size using tput or None'''
# get terminal width
# src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
try:
cols = int(subprocess.check_output(('tput', 'cols')))
rows = int(subprocess.check_output(('tput', 'lines')))
return cols, rows
except (EnvironmentError, ValueError):
return None
def get_terminal_size_stty():
'''Return terminal size using stty or None
Should be better than get_terminal_size_tput (calls one external command instead of two, "coreutils" vs "ncurses"
'''
try:
height, width = subprocess.check_output(['stty', 'size']).decode('utf-8').strip().split(' ', 1)
return int(width), int(height)
except (EnvironmentError, ValueError):
return None
def ioctl_gwinsz(fd_):
'''Get terminal size from a file descriptor using termios.TIOCGWINSZ'''
try: # https://pycodequ.al/docs/pylint-messages/c0415-import-outside-toplevel.html
import fcntl # pylint: disable=import-outside-toplevel
import termios # pylint: disable=import-outside-toplevel
return struct.unpack('hh', fcntl.ioctl(fd_, termios.TIOCGWINSZ, '1234'))
except (ImportError, EnvironmentError):
return None
def get_terminal_size_linux():
'''Get terminal size in Linux or None'''
width_height = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2)
if not width_height:
try:
fd_ = os.open(os.ctermid(), os.O_RDONLY)
width_height = ioctl_gwinsz(fd_)
os.close(fd_)
except EnvironmentError:
pass
if width_height:
return width_height
try:
return int(os.environ['COLUMNS']), int(os.environ['LINES'])
except (KeyError, ValueError):
return None
def print_terminal_size():
'''Terminal test function, prints the size'''
width, height = get_terminal_size()
print('width =', width, 'height =', height)
print(get_terminal_size_tput())
print(get_terminal_size_stty())
print(ioctl_gwinsz(1))
if __name__ == "__main__":
print_terminal_size()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment