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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
"""
sphinx.util.console
~~~~~~~~~~~~~~~~~~~
Format colored console output.
:copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import os
import re
import sys
try:
# check if colorama is installed to support color on Windows
import colorama
except ImportError:
colorama = None
if False:
# For type annotation
from typing import Dict # NOQA
_ansi_re = re.compile('\x1b\\[(\\d\\d;){0,2}\\d\\dm')
codes = {} # type: Dict[str, str]
def get_terminal_width():
# type: () -> int
"""Borrowed from the py lib."""
try:
import termios
import fcntl
import struct
call = fcntl.ioctl(0, termios.TIOCGWINSZ,
struct.pack('hhhh', 0, 0, 0, 0))
height, width = struct.unpack('hhhh', call)[:2]
terminal_width = width
except Exception:
# FALLBACK
terminal_width = int(os.environ.get('COLUMNS', "80")) - 1
return terminal_width
_tw = get_terminal_width()
def term_width_line(text):
# type: (str) -> str
if not codes:
# if no coloring, don't output fancy backspaces
return text + '\n'
else:
# codes are not displayed, this must be taken into account
return text.ljust(_tw + len(text) - len(_ansi_re.sub('', text))) + '\r'
def color_terminal():
# type: () -> bool
if sys.platform == 'win32' and colorama is not None:
colorama.init()
return True
if not hasattr(sys.stdout, 'isatty'):
return False
if not sys.stdout.isatty():
return False
if 'COLORTERM' in os.environ:
return True
term = os.environ.get('TERM', 'dumb').lower()
if term in ('xterm', 'linux') or 'color' in term:
return True
return False
def nocolor():
# type: () -> None
if sys.platform == 'win32' and colorama is not None:
colorama.deinit()
codes.clear()
def coloron():
# type: () -> None
codes.update(_orig_codes)
def colorize(name, text, input_mode=False):
# type: (str, str, bool) -> str
def escseq(name):
# Wrap escape sequence with ``\1`` and ``\2`` to let readline know
# it is non-printable characters
# ref: https://tiswww.case.edu/php/chet/readline/readline.html
#
# Note: This hack does not work well in Windows (see #5059)
escape = codes.get(name, '')
if input_mode and escape and sys.platform != 'win32':
return '\1' + escape + '\2'
else:
return escape
return escseq(name) + text + escseq('reset')
def strip_colors(s):
# type: (str) -> str
return re.compile('\x1b.*?m').sub('', s)
def create_color_func(name):
# type: (str) -> None
def inner(text):
# type: (str) -> str
return colorize(name, text)
globals()[name] = inner
_attrs = {
'reset': '39;49;00m',
'bold': '01m',
'faint': '02m',
'standout': '03m',
'underline': '04m',
'blink': '05m',
}
for _name, _value in _attrs.items():
codes[_name] = '\x1b[' + _value
_colors = [
('black', 'darkgray'),
('darkred', 'red'),
('darkgreen', 'green'),
('brown', 'yellow'),
('darkblue', 'blue'),
('purple', 'fuchsia'),
('turquoise', 'teal'),
('lightgray', 'white'),
]
for i, (dark, light) in enumerate(_colors):
codes[dark] = '\x1b[%im' % (i + 30)
codes[light] = '\x1b[%i;01m' % (i + 30)
_orig_codes = codes.copy()
for _name in codes:
create_color_func(_name)
|