Skip to content

Instantly share code, notes, and snippets.

@leomao
Created January 30, 2017 14:29
Show Gist options
  • Save leomao/9ceab97397e96f69b15bb769d36924fb to your computer and use it in GitHub Desktop.
Save leomao/9ceab97397e96f69b15bb769d36924fb to your computer and use it in GitHub Desktop.
ANSI style escape code
# /usr/bin/env python
# Copyright (C) 2017 Leo Mao
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import re
ESC = '\x1b['
END = 'm'
ATTRIBUTES = {
'bold': 1,
'dim': 2,
'italic': 3,
'underlined': 4,
'blink': 5,
'reverse': 7,
'conceal': 8,
'no_bold': 21,
'no_bold_dim': 22,
'no_italic': 23,
'no_underline':24,
'no_blink': 25,
'no_reverse': 27,
'no_conceal': 28,
}
ATTR_CODES = set(ATTRIBUTES.values())
COLOR_NAMES = {
'black': 0,
'red': 1,
'green': 2,
'yellow': 3,
'blue': 4,
'magenta': 5,
'cyan': 6,
'light_gray': 7,
'dark_gray': 8,
'light_red': 9,
'light_green': 10,
'light_yellow': 11,
'light_blue': 12,
'light_magenta': 13,
'light_cyan': 14,
'white': 15,
}
RESET = '{}{}{}'.format(ESC, 0, END)
HEX_RE = r'#[0-9a-f]{6}'
HEXCODE_RE = r'[0-9a-f]{2}'
def _256_code(n):
return '5;{}'.format(n)
def _tuple_code(t):
return '2;{};{};{}'.format(*t)
def validate_color(c):
try:
tp = type(c)
if tp is str:
c = c.lower()
if c in COLOR_NAMES:
return _256_code(COLOR_NAMES[c])
elif re.fullmatch(HEX_RE, c):
return _tuple_code(int(x, base=16)
for x in re.findall(HEXCODE_RE, c[1:]))
elif tp is int:
if c >= 0 and c <= 255:
return _256_code(c)
elif tp is tuple or tp is list and len(c) == 3:
if all(x >= 0 and x <= 255 for x in c):
return _tuple_code(c)
except TypeError:
pass
raise TypeError('The format of the color is incorrect.')
def fg(c):
return ''.join((ESC, '38;', validate_color(c), END))
def bg(c):
return ''.join((ESC, '48;', validate_color(c), END))
def attr(at):
if at in ATTRIBUTES:
return '{}{}{}'.format(ESC, ATTRIBUTES[at], END)
elif at in ATTR_CODES:
return '{}{}{}'.format(ESC, at, END)
else:
raise TypeError("The attribute `{}` doens't exist.".format(s))
def stylize(text, *styles, reset=True):
term = RESET if reset else ''
return '{}{}{}'.format(''.join(styles), text, term)
if __name__ == '__main__':
# simple test as example
for i in range(256):
print(stylize('TEXT', fg(i)))
print(stylize('TEXT', fg(123), bg('#AE01b2')))
print(stylize('TEXT', fg(223), bg('#0E01b2'), attr('bold')))
print(stylize('TEXT', fg(23), bg((100, 100, 100)), attr(4)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment