1import os 2 3 4def get_terminal_size(): # pragma: no cover 5 '''Get the current size of your terminal 6 7 Multiple returns are not always a good idea, but in this case it greatly 8 simplifies the code so I believe it's justified. It's not the prettiest 9 function but that's never really possible with cross-platform code. 10 11 Returns: 12 width, height: Two integers containing width and height 13 ''' 14 15 try: 16 # Default to 79 characters for IPython notebooks 17 from IPython import get_ipython 18 ipython = get_ipython() 19 from ipykernel import zmqshell 20 if isinstance(ipython, zmqshell.ZMQInteractiveShell): 21 return 79, 24 22 except Exception: # pragma: no cover 23 pass 24 25 try: 26 # This works for Python 3, but not Pypy3. Probably the best method if 27 # it's supported so let's always try 28 import shutil 29 w, h = shutil.get_terminal_size() 30 if w and h: 31 # The off by one is needed due to progressbars in some cases, for 32 # safety we'll always substract it. 33 return w - 1, h 34 except Exception: # pragma: no cover 35 pass 36 37 try: 38 w = int(os.environ.get('COLUMNS')) 39 h = int(os.environ.get('LINES')) 40 if w and h: 41 return w, h 42 except Exception: # pragma: no cover 43 pass 44 45 try: 46 import blessings 47 terminal = blessings.Terminal() 48 w = terminal.width 49 h = terminal.height 50 if w and h: 51 return w, h 52 except Exception: # pragma: no cover 53 pass 54 55 try: 56 w, h = _get_terminal_size_linux() 57 if w and h: 58 return w, h 59 except Exception: # pragma: no cover 60 pass 61 62 try: 63 # Windows detection doesn't always work, let's try anyhow 64 w, h = _get_terminal_size_windows() 65 if w and h: 66 return w, h 67 except Exception: # pragma: no cover 68 pass 69 70 try: 71 # needed for window's python in cygwin's xterm! 72 w, h = _get_terminal_size_tput() 73 if w and h: 74 return w, h 75 except Exception: # pragma: no cover 76 pass 77 78 return 79, 24 79 80 81def _get_terminal_size_windows(): # pragma: no cover 82 res = None 83 try: 84 from ctypes import windll, create_string_buffer 85 86 # stdin handle is -10 87 # stdout handle is -11 88 # stderr handle is -12 89 90 h = windll.kernel32.GetStdHandle(-12) 91 csbi = create_string_buffer(22) 92 res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) 93 except Exception: 94 return None 95 96 if res: 97 import struct 98 (_, _, _, _, _, left, top, right, bottom, _, _) = \ 99 struct.unpack("hhhhHhhhhhh", csbi.raw) 100 w = right - left 101 h = bottom - top 102 return w, h 103 else: 104 return None 105 106 107def _get_terminal_size_tput(): # pragma: no cover 108 # get terminal width src: http://stackoverflow.com/questions/263890/ 109 try: 110 import subprocess 111 proc = subprocess.Popen( 112 ['tput', 'cols'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, 113 stderr=subprocess.PIPE) 114 output = proc.communicate(input=None) 115 w = int(output[0]) 116 proc = subprocess.Popen( 117 ['tput', 'lines'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, 118 stderr=subprocess.PIPE) 119 output = proc.communicate(input=None) 120 h = int(output[0]) 121 return w, h 122 except Exception: 123 return None 124 125 126def _get_terminal_size_linux(): # pragma: no cover 127 def ioctl_GWINSZ(fd): 128 try: 129 import fcntl 130 import termios 131 import struct 132 size = struct.unpack( 133 'hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234')) 134 except Exception: 135 return None 136 return size 137 138 size = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) 139 140 if not size: 141 try: 142 fd = os.open(os.ctermid(), os.O_RDONLY) 143 size = ioctl_GWINSZ(fd) 144 os.close(fd) 145 except Exception: 146 pass 147 if not size: 148 try: 149 size = os.environ['LINES'], os.environ['COLUMNS'] 150 except Exception: 151 return None 152 153 return int(size[1]), int(size[0]) 154