"""Terminals and colors."""
from __future__ import annotations
import base64
import os
import platform
import sys
from functools import reduce
__all__ = ( 'colored' ,)
from typing import Any
BLACK , RED , GREEN , YELLOW , BLUE , MAGENTA , CYAN , WHITE = range ( 8 )
OP_SEQ = ' \033 [ %d m'
RESET_SEQ = ' \033 [0m'
COLOR_SEQ = ' \033 [1; %d m'
IS_WINDOWS = platform . system () == 'Windows'
ITERM_PROFILE = os . environ . get ( 'ITERM_PROFILE' )
TERM = os . environ . get ( 'TERM' )
TERM_IS_SCREEN = TERM and TERM . startswith ( 'screen' )
# tmux requires unrecognized OSC sequences to be wrapped with DCS tmux;
# <sequence> ST, and for all ESCs in <sequence> to be replaced with ESC ESC.
# It only accepts ESC backslash for ST.
_IMG_PRE = ' \033 Ptmux; \033\033 ]' if TERM_IS_SCREEN else ' \033 ]'
_IMG_POST = ' \a\033\\ ' if TERM_IS_SCREEN else ' \a '
def fg ( s : int ) -> str :
return COLOR_SEQ % s
[文档]
class colored :
"""Terminal colored text.
Example:
>>> c = colored(enabled=True)
>>> print(str(c.red('the quick '), c.blue('brown ', c.bold('fox ')),
... c.magenta(c.underline('jumps over')),
... c.yellow(' the lazy '),
... c.green('dog ')))
"""
def __init__ ( self , * s : object , ** kwargs : Any ) -> None :
self . s : tuple [ object , ... ] = s
self . enabled : bool = not IS_WINDOWS and kwargs . get ( 'enabled' , True )
self . op : str = kwargs . get ( 'op' , '' )
self . names : dict [ str , Any ] = {
'black' : self . black ,
'red' : self . red ,
'green' : self . green ,
'yellow' : self . yellow ,
'blue' : self . blue ,
'magenta' : self . magenta ,
'cyan' : self . cyan ,
'white' : self . white ,
}
def _add ( self , a : object , b : object ) -> str :
return f " { a }{ b } "
def _fold_no_color ( self , a : Any , b : Any ) -> str :
try :
A = a . no_color ()
except AttributeError :
A = str ( a )
try :
B = b . no_color ()
except AttributeError :
B = str ( b )
return f " { A }{ B } "
[文档]
def no_color ( self ) -> str :
if self . s :
return str ( reduce ( self . _fold_no_color , self . s ))
return ''
[文档]
def embed ( self ) -> str :
prefix = ''
if self . enabled :
prefix = self . op
return f " { prefix }{ reduce ( self . _add , self . s ) } "
def __str__ ( self ) -> str :
suffix = ''
if self . enabled :
suffix = RESET_SEQ
return f " { self . embed () }{ suffix } "
[文档]
def node ( self , s : tuple [ object , ... ], op : str ) -> colored :
return self . __class__ ( enabled = self . enabled , op = op , * s )
[文档]
def black ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + BLACK ))
[文档]
def red ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + RED ))
[文档]
def green ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + GREEN ))
[文档]
def yellow ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + YELLOW ))
[文档]
def blue ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + BLUE ))
[文档]
def magenta ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + MAGENTA ))
[文档]
def cyan ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + CYAN ))
[文档]
def white ( self , * s : object ) -> colored :
return self . node ( s , fg ( 30 + WHITE ))
def __repr__ ( self ) -> str :
return repr ( self . no_color ())
[文档]
def bold ( self , * s : object ) -> colored :
return self . node ( s , OP_SEQ % 1 )
[文档]
def underline ( self , * s : object ) -> colored :
return self . node ( s , OP_SEQ % 4 )
[文档]
def blink ( self , * s : object ) -> colored :
return self . node ( s , OP_SEQ % 5 )
[文档]
def reverse ( self , * s : object ) -> colored :
return self . node ( s , OP_SEQ % 7 )
[文档]
def bright ( self , * s : object ) -> colored :
return self . node ( s , OP_SEQ % 8 )
[文档]
def ired ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + RED ))
[文档]
def igreen ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + GREEN ))
[文档]
def iyellow ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + YELLOW ))
[文档]
def iblue ( self , * s : colored ) -> colored :
return self . node ( s , fg ( 40 + BLUE ))
[文档]
def imagenta ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + MAGENTA ))
[文档]
def icyan ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + CYAN ))
[文档]
def iwhite ( self , * s : object ) -> colored :
return self . node ( s , fg ( 40 + WHITE ))
[文档]
def reset ( self , * s : object ) -> colored :
return self . node ( s or ( '' ,), RESET_SEQ )
def __add__ ( self , other : object ) -> str :
return f " { self }{ other } "
def supports_images () -> bool :
try :
return sys . stdin . isatty () and bool ( os . environ . get ( 'ITERM_PROFILE' ))
except AttributeError :
return False
def _read_as_base64 ( path : str ) -> str :
with open ( path , mode = 'rb' ) as fh :
encoded = base64 . b64encode ( fh . read ())
return encoded . decode ( 'ascii' )
def imgcat ( path : str , inline : int = 1 , preserve_aspect_ratio : int = 0 , ** kwargs : Any ) -> str :
return ' \n %s 1337;File=inline= %d ;preserveAspectRatio= %d : %s%s ' % (
_IMG_PRE , inline , preserve_aspect_ratio ,
_read_as_base64 ( path ), _IMG_POST )
复制到剪贴板