1# -*- coding: utf-8 -*-
2"""
3Terminal size utility
4---------------------
5"""
6from __future__ import absolute_import, division, print_function
7
8import os
9import platform
10import warnings
11from struct import Struct
12
13
14def get_terminal_size(default=(80, 25)):
15    """
16    Get width and height of console; works on linux, os x, windows and cygwin
17
18    Adapted from https://gist.github.com/jtriley/1108174
19    Originally from: http://stackoverflow.com/questions/566746/how-to-get-console-window-width-in-python
20    """
21    current_os = platform.system()
22    if current_os == "Windows":  # pragma: no cover
23        size = _get_terminal_size_windows()
24        if not size:
25            # needed for window's python in cygwin's xterm!
26            size = _get_terminal_size_tput()
27    elif current_os in ("Linux", "Darwin", "FreeBSD", "SunOS") or current_os.startswith(
28        "CYGWIN"
29    ):
30        size = _get_terminal_size_linux()
31
32    else:  # pragma: no cover
33        warnings.warn(
34            "Plumbum does not know the type of the current OS for term size, defaulting to UNIX"
35        )
36        size = _get_terminal_size_linux()
37
38    if (
39        size is None
40    ):  # we'll assume the standard 80x25 if for any reason we don't know the terminal size
41        size = default
42    return size
43
44
45def _get_terminal_size_windows():  # pragma: no cover
46    try:
47        from ctypes import create_string_buffer, windll
48
49        STDERR_HANDLE = -12
50        h = windll.kernel32.GetStdHandle(STDERR_HANDLE)
51        csbi_struct = Struct("hhhhHhhhhhh")
52        csbi = create_string_buffer(csbi_struct.size)
53        res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi)
54        if res:
55            _, _, _, _, _, left, top, right, bottom, _, _ = csbi_struct.unpack(csbi.raw)
56            return right - left + 1, bottom - top + 1
57        return None
58    except Exception:
59        return None
60
61
62def _get_terminal_size_tput():  # pragma: no cover
63    # get terminal width
64    # src: http://stackoverflow.com/questions/263890/how-do-i-find-the-width-height-of-a-terminal-window
65    try:
66        tput = local["tput"]
67        cols = int(tput("cols"))
68        rows = int(tput("lines"))
69        return (cols, rows)
70    except Exception:
71        return None
72
73
74def _ioctl_GWINSZ(fd):
75    yx = Struct("hh")
76    try:
77        import fcntl
78        import termios
79
80        return yx.unpack(fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234"))
81    except Exception:
82        return None
83
84
85def _get_terminal_size_linux():
86    cr = _ioctl_GWINSZ(0) or _ioctl_GWINSZ(1) or _ioctl_GWINSZ(2)
87    if not cr:
88        try:
89            fd = os.open(os.ctermid(), os.O_RDONLY)
90            cr = _ioctl_GWINSZ(fd)
91            os.close(fd)
92        except Exception:
93            pass
94    if not cr:
95        try:
96            cr = (int(os.environ["LINES"]), int(os.environ["COLUMNS"]))
97        except Exception:
98            return None
99    return cr[1], cr[0]
100