_get_terminal_size.py
131 lines
| 4.3 KiB
| text/x-python
|
PythonLexer
Matthias Bussonnier
|
r23688 | # vendored version of backports.get_terminal_size as nemesapece package are a | ||
Matthias Bussonnier
|
r23696 | # mess and break, especially on ubuntu. This file is under MIT Licence. | ||
Matthias Bussonnier
|
r23688 | # See https://pypi.python.org/pypi/backports.shutil_get_terminal_size | ||
Matthias Bussonnier
|
r23696 | # | ||
# commit: afc5714b1545a5a3aa44cfb5e078d39165bf76ab (Feb 20, 2016) | ||||
# from | ||||
# https://github.com/chrippa/backports.shutil_get_terminal_size | ||||
# | ||||
# The MIT License (MIT) | ||||
# | ||||
# Copyright (c) 2014 Christopher Rosell | ||||
# | ||||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
# of this software and associated documentation files (the "Software"), to deal | ||||
# in the Software without restriction, including without limitation the rights | ||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
# copies of the Software, and to permit persons to whom the Software is | ||||
# furnished to do so, subject to the following conditions: | ||||
# | ||||
# The above copyright notice and this permission notice shall be included in | ||||
# all copies or substantial portions of the Software. | ||||
# | ||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
# THE SOFTWARE. | ||||
# | ||||
Matthias Bussonnier
|
r23688 | """This is a backport of shutil.get_terminal_size from Python 3.3. | ||
The original implementation is in C, but here we use the ctypes and | ||||
fcntl modules to create a pure Python version of os.get_terminal_size. | ||||
""" | ||||
import os | ||||
import struct | ||||
import sys | ||||
from collections import namedtuple | ||||
__all__ = ["get_terminal_size"] | ||||
terminal_size = namedtuple("terminal_size", "columns lines") | ||||
try: | ||||
Matthias Bussonnier
|
r23696 | from ctypes import windll, create_string_buffer, WinError | ||
Matthias Bussonnier
|
r23688 | |||
Matthias Bussonnier
|
r23696 | _handle_ids = { | ||
0: -10, | ||||
1: -11, | ||||
2: -12, | ||||
Matthias Bussonnier
|
r23688 | } | ||
def _get_terminal_size(fd): | ||||
Matthias Bussonnier
|
r23696 | handle = windll.kernel32.GetStdHandle(_handle_ids[fd]) | ||
if handle == 0: | ||||
raise OSError('handle cannot be retrieved') | ||||
if handle == -1: | ||||
raise WinError() | ||||
csbi = create_string_buffer(22) | ||||
res = windll.kernel32.GetConsoleScreenBufferInfo(handle, csbi) | ||||
if res: | ||||
res = struct.unpack("hhhhHhhhhhh", csbi.raw) | ||||
left, top, right, bottom = res[5:9] | ||||
columns = right - left + 1 | ||||
lines = bottom - top + 1 | ||||
return terminal_size(columns, lines) | ||||
else: | ||||
raise WinError() | ||||
Matthias Bussonnier
|
r23688 | |||
except ImportError: | ||||
import fcntl | ||||
import termios | ||||
def _get_terminal_size(fd): | ||||
try: | ||||
res = fcntl.ioctl(fd, termios.TIOCGWINSZ, b"\x00" * 4) | ||||
Matthias Bussonnier
|
r23696 | except IOError as e: | ||
raise OSError(e) | ||||
lines, columns = struct.unpack("hh", res) | ||||
Matthias Bussonnier
|
r23688 | |||
return terminal_size(columns, lines) | ||||
def get_terminal_size(fallback=(80, 24)): | ||||
"""Get the size of the terminal window. | ||||
For each of the two dimensions, the environment variable, COLUMNS | ||||
and LINES respectively, is checked. If the variable is defined and | ||||
the value is a positive integer, it is used. | ||||
When COLUMNS or LINES is not defined, which is the common case, | ||||
the terminal connected to sys.__stdout__ is queried | ||||
by invoking os.get_terminal_size. | ||||
If the terminal size cannot be successfully queried, either because | ||||
the system doesn't support querying, or because we are not | ||||
connected to a terminal, the value given in fallback parameter | ||||
is used. Fallback defaults to (80, 24) which is the default | ||||
size used by many terminal emulators. | ||||
The value returned is a named tuple of type os.terminal_size. | ||||
""" | ||||
# Try the environment first | ||||
try: | ||||
columns = int(os.environ["COLUMNS"]) | ||||
except (KeyError, ValueError): | ||||
columns = 0 | ||||
try: | ||||
lines = int(os.environ["LINES"]) | ||||
except (KeyError, ValueError): | ||||
lines = 0 | ||||
# Only query if necessary | ||||
if columns <= 0 or lines <= 0: | ||||
try: | ||||
size = _get_terminal_size(sys.__stdout__.fileno()) | ||||
except (NameError, OSError): | ||||
size = terminal_size(*fallback) | ||||
if columns <= 0: | ||||
columns = size.columns | ||||
if lines <= 0: | ||||
lines = size.lines | ||||
return terminal_size(columns, lines) | ||||
Matthias Bussonnier
|
r23696 | |||