Skip to content

Commit 1df7ee2

Browse files
committed
Add _cli.util.colour
1 parent 56fee01 commit 1df7ee2

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed

sphinx/_cli/util/colour.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
"""Format coloured console output."""
2+
3+
from __future__ import annotations
4+
5+
import os
6+
import sys
7+
from collections.abc import Callable # NoQA: TCH003
8+
9+
if sys.platform == 'win32':
10+
import colorama
11+
12+
13+
_COLOURING_DISABLED = True
14+
15+
16+
def terminal_supports_colour() -> bool:
17+
"""Return True if coloured terminal output is supported."""
18+
if 'NO_COLOUR' in os.environ or 'NO_COLOR' in os.environ:
19+
return False
20+
if 'FORCE_COLOUR' in os.environ or 'FORCE_COLOR' in os.environ:
21+
return True
22+
23+
try:
24+
if not sys.stdout.isatty():
25+
return False
26+
except (AttributeError, ValueError):
27+
# Handle cases where .isatty() is not defined, or where e.g.
28+
# "ValueError: I/O operation on closed file" is raised
29+
return False
30+
31+
# Do not colour output if on a dumb terminal
32+
return os.environ.get('TERM', 'unknown').lower() not in {'dumb', 'unknown'}
33+
34+
35+
def disable_colour() -> None:
36+
global _COLOURING_DISABLED
37+
_COLOURING_DISABLED = True
38+
if sys.platform == 'win32':
39+
colorama.deinit()
40+
41+
42+
def enable_colour() -> None:
43+
global _COLOURING_DISABLED
44+
_COLOURING_DISABLED = False
45+
if sys.platform == 'win32':
46+
colorama.init()
47+
48+
49+
def colourise(colour_name: str, text: str, /) -> str:
50+
if _COLOURING_DISABLED:
51+
return text
52+
return globals()[colour_name](text)
53+
54+
55+
def _create_colour_func(escape_code: str, /) -> Callable[[str], str]:
56+
def inner(text: str) -> str:
57+
if _COLOURING_DISABLED:
58+
return text
59+
return f'\x1b[{escape_code}m{text}\x1b[39;49;00m'
60+
return inner
61+
62+
63+
# Wrap escape sequence with ``\1`` and ``\2`` to let readline know
64+
# that the colour escape codes are non-printable characters
65+
# [ https://tiswww.case.edu/php/chet/readline/readline.html ]
66+
#
67+
# Note: This does not work well in Windows
68+
# (see https://github.com/sphinx-doc/sphinx/pull/5059)
69+
if sys.platform == 'win32':
70+
_create_input_mode_colour_func = _create_colour_func
71+
else:
72+
def _create_input_mode_colour_func(escape_code: str, /) -> Callable[[str], str]:
73+
def inner(text: str) -> str:
74+
if _COLOURING_DISABLED:
75+
return text
76+
return f'\x01\x1b[{escape_code}m\x02{text}\x01\x1b[39;49;00m\x02'
77+
return inner
78+
79+
80+
reset = _create_colour_func('39;49;00')
81+
bold = _create_colour_func('01')
82+
faint = _create_colour_func('02')
83+
standout = _create_colour_func('03')
84+
underline = _create_colour_func('04')
85+
blink = _create_colour_func('05')
86+
87+
black = _create_colour_func('30')
88+
darkred = _create_colour_func('31')
89+
darkgreen = _create_colour_func('32')
90+
brown = _create_colour_func('33')
91+
darkblue = _create_colour_func('34')
92+
purple = _create_colour_func('35')
93+
turquoise = _create_colour_func('36')
94+
lightgray = _create_colour_func('37')
95+
96+
darkgray = _create_colour_func('90')
97+
red = _create_colour_func('91')
98+
green = _create_colour_func('92')
99+
yellow = _create_colour_func('93')
100+
blue = _create_colour_func('94')
101+
fuchsia = _create_colour_func('95')
102+
teal = _create_colour_func('96')
103+
white = _create_colour_func('97')

0 commit comments

Comments
 (0)