|
64 | 64 | # Distributed under the BSD 3-Clause license. |
65 | 65 | # |
66 | 66 |
|
67 | | -# stdlib |
68 | | -import re |
69 | | -from abc import ABC |
70 | | -from typing import List, Pattern |
71 | 67 |
|
72 | | -# 3rd party |
73 | | -from colorama import init # type: ignore |
74 | | -from typing_extensions import Final |
| 68 | +from consolekit.terminal_colours import ( |
| 69 | + CSI, |
| 70 | + OSC, |
| 71 | + BEL, |
| 72 | + code_to_chars, |
| 73 | + set_title, |
| 74 | + clear_line, |
| 75 | + Colour, |
| 76 | + AnsiCodes, |
| 77 | + AnsiCursor, |
| 78 | + AnsiFore, |
| 79 | + AnsiBack, |
| 80 | + AnsiStyle, |
| 81 | + Fore, |
| 82 | + Back, |
| 83 | + Style, |
| 84 | + Cursor, |
| 85 | + strip_ansi, |
| 86 | + fore_stack, |
| 87 | + back_stack, |
| 88 | + style_stack, |
| 89 | + ) |
75 | 90 |
|
76 | 91 | __all__ = [ |
77 | 92 | "CSI", |
|
94 | 109 | "strip_ansi", |
95 | 110 | ] |
96 | 111 |
|
97 | | -init() |
98 | | - |
99 | | -CSI: Final[str] = "\033[" |
100 | | -OSC: Final[str] = "\033]" |
101 | | -BEL: Final[str] = "\a" |
102 | | - |
103 | | -fore_stack: List[str] = [] |
104 | | -back_stack: List[str] = [] |
105 | | -style_stack: List[str] = [] |
106 | | - |
107 | | - |
108 | | -def code_to_chars(code) -> str: |
109 | | - return CSI + str(code) + 'm' |
110 | | - |
111 | | - |
112 | | -def set_title(title: str) -> str: |
113 | | - return OSC + "2;" + title + BEL |
114 | | - |
115 | 112 |
|
116 | 113 | def clear_screen(mode: int = 2) -> str: |
117 | 114 | return CSI + str(mode) + 'J' |
118 | | - |
119 | | - |
120 | | -def clear_line(mode: int = 2) -> str: |
121 | | - return CSI + str(mode) + 'K' |
122 | | - |
123 | | - |
124 | | -_ansi_re: Pattern[str] = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") |
125 | | - |
126 | | - |
127 | | -def strip_ansi(value: str) -> str: |
128 | | - """ |
129 | | - Strip ANSI colour codes from the given string to return a plaintext output. |
130 | | -
|
131 | | - :param value: |
132 | | -
|
133 | | - :rtype: |
134 | | -
|
135 | | - .. versionadded:: 1.1.0 |
136 | | - """ |
137 | | - |
138 | | - return _ansi_re.sub('', value) |
139 | | - |
140 | | - |
141 | | -class Colour(str): |
142 | | - r""" |
143 | | - An ANSI escape sequence representing a colour. |
144 | | -
|
145 | | - The colour can be used as a context manager, a string, or a function. |
146 | | -
|
147 | | - :param style: Escape sequence representing the style. |
148 | | - :type style: :class:`str` |
149 | | - :param stack: The stack to place the escape sequence on. |
150 | | - :type stack: :class:`~typing.List`\[:class:`str`\] |
151 | | - :param reset: The escape sequence to reset the style. |
152 | | - :type reset: :class:`str` |
153 | | - """ |
154 | | - |
155 | | - style: str |
156 | | - reset: str |
157 | | - stack: List[str] |
158 | | - |
159 | | - def __new__(cls, style: str, stack: List[str], reset: str) -> "Colour": # noqa D102 |
160 | | - color = super().__new__(cls, style) # type: ignore |
161 | | - color.style = style |
162 | | - color.stack = stack |
163 | | - color.reset = reset |
164 | | - |
165 | | - return color |
166 | | - |
167 | | - def __enter__(self) -> None: |
168 | | - print(self.style, end='') |
169 | | - self.stack.append(self.style) |
170 | | - |
171 | | - def __exit__(self, exc_type, exc_val, exc_tb) -> None: |
172 | | - if self.style == self.stack[-1]: |
173 | | - self.stack.pop() |
174 | | - print(self.stack[-1], end='') |
175 | | - |
176 | | - def __call__(self, text) -> str: |
177 | | - """ |
178 | | - Returns the given text in this colour. |
179 | | - """ |
180 | | - |
181 | | - return f"{self}{text}{self.reset}" |
182 | | - |
183 | | - |
184 | | -class AnsiCodes(ABC): |
185 | | - """ |
186 | | - Abstract base class for ANSI Codes. |
187 | | - """ |
188 | | - |
189 | | - _stack: List[str] |
190 | | - _reset: str |
191 | | - |
192 | | - def __init__(self) -> None: |
193 | | - """ |
194 | | - The subclasses declare class attributes which are numbers. |
195 | | -
|
196 | | - Upon instantiation we define instance attributes, which are the same |
197 | | - as the class attributes but wrapped with the ANSI escape sequence. |
198 | | - """ |
199 | | - |
200 | | - for name in dir(self): |
201 | | - if not name.startswith('_'): |
202 | | - value = getattr(self, name) |
203 | | - setattr(self, name, Colour(code_to_chars(value), self._stack, self._reset)) |
204 | | - |
205 | | - |
206 | | -class AnsiCursor: |
207 | | - |
208 | | - def UP(self, n: int = 1) -> str: |
209 | | - """ |
210 | | -
|
211 | | - :param n: |
212 | | - """ |
213 | | - |
214 | | - return f"{CSI}{str(n)}A" |
215 | | - |
216 | | - def DOWN(self, n: int = 1) -> str: |
217 | | - """ |
218 | | -
|
219 | | - :param n: |
220 | | - """ |
221 | | - |
222 | | - return f"{CSI}{str(n)}B" |
223 | | - |
224 | | - def FORWARD(self, n: int = 1) -> str: |
225 | | - """ |
226 | | -
|
227 | | - :param n: |
228 | | - """ |
229 | | - |
230 | | - return f"{CSI}{str(n)}C" |
231 | | - |
232 | | - def BACK(self, n: int = 1) -> str: |
233 | | - """ |
234 | | -
|
235 | | - :param n: |
236 | | - """ |
237 | | - |
238 | | - return f"{CSI}{str(n)}D" |
239 | | - |
240 | | - def POS(self, x: int = 1, y: int = 1) -> str: |
241 | | - """ |
242 | | -
|
243 | | - :param x: |
244 | | - :param y: |
245 | | - """ |
246 | | - |
247 | | - return f"{CSI}{str(y)};{str(x)}H" |
248 | | - |
249 | | - |
250 | | -class AnsiFore(AnsiCodes): |
251 | | - """ |
252 | | - ANSI Colour Codes for foreground colour. |
253 | | -
|
254 | | - The colours can be used as a context manager, a string, or a function. |
255 | | -
|
256 | | - Valid values are: |
257 | | -
|
258 | | - * BLACK |
259 | | - * RED |
260 | | - * GREEN |
261 | | - * YELLOW |
262 | | - * BLUE |
263 | | - * MAGENTA |
264 | | - * CYAN |
265 | | - * WHITE |
266 | | - * RESET |
267 | | - * LIGHTBLACK_EX |
268 | | - * LIGHTRED_EX |
269 | | - * LIGHTGREEN_EX |
270 | | - * LIGHTYELLOW_EX |
271 | | - * LIGHTBLUE_EX |
272 | | - * LIGHTMAGENTA_EX |
273 | | - * LIGHTCYAN_EX |
274 | | - * LIGHTWHITE_EX |
275 | | - """ |
276 | | - |
277 | | - _stack = fore_stack |
278 | | - _reset = "\033[39m" |
279 | | - |
280 | | - BLACK = 30 |
281 | | - RED = 31 |
282 | | - GREEN = 32 |
283 | | - YELLOW = 33 |
284 | | - BLUE = 34 |
285 | | - MAGENTA = 35 |
286 | | - CYAN = 36 |
287 | | - WHITE = 37 |
288 | | - RESET = 39 |
289 | | - |
290 | | - # These are fairly well supported, but not part of the standard. |
291 | | - LIGHTBLACK_EX = 90 |
292 | | - LIGHTRED_EX = 91 |
293 | | - LIGHTGREEN_EX = 92 |
294 | | - LIGHTYELLOW_EX = 93 |
295 | | - LIGHTBLUE_EX = 94 |
296 | | - LIGHTMAGENTA_EX = 95 |
297 | | - LIGHTCYAN_EX = 96 |
298 | | - LIGHTWHITE_EX = 97 |
299 | | - |
300 | | - |
301 | | -class AnsiBack(AnsiCodes): |
302 | | - """ |
303 | | - ANSI Colour Codes for background colour. |
304 | | -
|
305 | | - The colours can be used as a context manager, a string, or a function. |
306 | | -
|
307 | | - Valid values are: |
308 | | -
|
309 | | - * BLACK |
310 | | - * RED |
311 | | - * GREEN |
312 | | - * YELLOW |
313 | | - * BLUE |
314 | | - * MAGENTA |
315 | | - * CYAN |
316 | | - * WHITE |
317 | | - * RESET |
318 | | - * LIGHTBLACK_EX |
319 | | - * LIGHTRED_EX |
320 | | - * LIGHTGREEN_EX |
321 | | - * LIGHTYELLOW_EX |
322 | | - * LIGHTBLUE_EX |
323 | | - * LIGHTMAGENTA_EX |
324 | | - * LIGHTCYAN_EX |
325 | | - * LIGHTWHITE_EX |
326 | | - """ |
327 | | - |
328 | | - _stack = back_stack |
329 | | - _reset = "\033[49m" |
330 | | - |
331 | | - BLACK = 40 |
332 | | - RED = 41 |
333 | | - GREEN = 42 |
334 | | - YELLOW = 43 |
335 | | - BLUE = 44 |
336 | | - MAGENTA = 45 |
337 | | - CYAN = 46 |
338 | | - WHITE = 47 |
339 | | - RESET = 49 |
340 | | - |
341 | | - # These are fairly well supported, but not part of the standard. |
342 | | - LIGHTBLACK_EX = 100 |
343 | | - LIGHTRED_EX = 101 |
344 | | - LIGHTGREEN_EX = 102 |
345 | | - LIGHTYELLOW_EX = 103 |
346 | | - LIGHTBLUE_EX = 104 |
347 | | - LIGHTMAGENTA_EX = 105 |
348 | | - LIGHTCYAN_EX = 106 |
349 | | - LIGHTWHITE_EX = 107 |
350 | | - |
351 | | - |
352 | | -class AnsiStyle(AnsiCodes): |
353 | | - """ |
354 | | - ANSI Colour Codes for text style. |
355 | | -
|
356 | | - Valid values are: |
357 | | -
|
358 | | - * BRIGHT |
359 | | - * DIM |
360 | | - * NORMAL |
361 | | -
|
362 | | - Additionally, ``AnsiStyle.RESET_ALL`` can be used to reset the |
363 | | - foreground and background colours as well as the text style. |
364 | | - """ |
365 | | - |
366 | | - _stack = style_stack |
367 | | - _reset = "\033[22m" |
368 | | - |
369 | | - BRIGHT = 1 |
370 | | - DIM = 2 |
371 | | - NORMAL = 22 |
372 | | - RESET_ALL = 0 |
373 | | - |
374 | | - |
375 | | -Fore = AnsiFore() |
376 | | -Back = AnsiBack() |
377 | | -Style = AnsiStyle() |
378 | | -Cursor = AnsiCursor() |
379 | | - |
380 | | -fore_stack.append(Fore.RESET) |
381 | | -back_stack.append(Back.RESET) |
382 | | -style_stack.append(Style.NORMAL) |
0 commit comments