Coding Style.

- Move the eris source into a subdirectory.
  - Including the setup.py and requirements files.
- This repo will hold more than one python project.
This commit is contained in:
Andrew Hamilton 2021-11-04 21:18:44 +10:00
parent 09ec5fb009
commit 31d8cbf4e3
18 changed files with 1 additions and 1 deletions

View file

@ -1,128 +0,0 @@
# This is from https://github.com/broadinstitute/xtermcolor
# Copyright (C) 2012 The Broad Institute
# 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.
class TerminalColorMapException(Exception):
pass
def _rgb(color):
return ((color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff)
def _diff(color1, color2):
(r1, g1, b1) = _rgb(color1)
(r2, g2, b2) = _rgb(color2)
return abs(r1 - r2) + abs(g1 - g2) + abs(b1 - b2)
class TerminalColorMap:
def getColors(self, order='rgb'):
return self.colors
def convert(self, hexcolor):
diffs = {}
for xterm, rgb in self.colors.items():
diffs[_diff(rgb, hexcolor)] = xterm
minDiffAnsi = diffs[min(diffs.keys())]
return (minDiffAnsi, self.colors[minDiffAnsi])
def colorize(self, string, rgb=None, ansi=None, bg=None, ansi_bg=None):
'''Returns the colored string'''
if not isinstance(string, str):
string = str(string)
if rgb is None and ansi is None:
raise TerminalColorMapException(
'colorize: must specify one named parameter: rgb or ansi')
if rgb is not None and ansi is not None:
raise TerminalColorMapException(
'colorize: must specify only one named parameter: rgb or ansi')
if bg is not None and ansi_bg is not None:
raise TerminalColorMapException(
'colorize: must specify only one named parameter: bg or ansi_bg')
if rgb is not None:
(closestAnsi, closestRgb) = self.convert(rgb)
elif ansi is not None:
(closestAnsi, closestRgb) = (ansi, self.colors[ansi])
if bg is None and ansi_bg is None:
return "\033[38;5;{ansiCode:d}m{string:s}\033[0m".format(ansiCode=closestAnsi, string=string)
if bg is not None:
(closestBgAnsi, unused) = self.convert(bg)
elif ansi_bg is not None:
(closestBgAnsi, unused) = (ansi_bg, self.colors[ansi_bg])
return "\033[38;5;{ansiCode:d}m\033[48;5;{bf:d}m{string:s}\033[0m".format(ansiCode=closestAnsi, bf=closestBgAnsi, string=string)
class VT100ColorMap(TerminalColorMap):
primary = [
0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0
]
bright = [
0x808080, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff
]
def __init__(self):
self.colors = dict()
self._compute()
def _compute(self):
for index, color in enumerate(self.primary + self.bright):
self.colors[index] = color
class XTermColorMap(VT100ColorMap):
grayscale_start = 0x08
grayscale_end = 0xf8
grayscale_step = 10
intensities = [
0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF
]
def _compute(self):
for index, color in enumerate(self.primary + self.bright):
self.colors[index] = color
c = 16
for i in self.intensities:
color = i << 16
for j in self.intensities:
color &= ~(0xff << 8)
color |= j << 8
for k in self.intensities:
color &= ~0xff
color |= k
self.colors[c] = color
c += 1
c = 232
for hex in list(range(self.grayscale_start, self.grayscale_end, self.grayscale_step)):
color = (hex << 16) | (hex << 8) | hex
self.colors[c] = color
c += 1

View file

@ -1,399 +0,0 @@
import collections
import functools
import html
import itertools
import os
import weakref
import pygments.formatters.terminal256
import cwcwidth
import termstr.ColorMap
ESC = "\x1b"
NORMAL = "[m"
BOLD = "[1m"
ITALIC = "[3m"
UNDERLINE = "[4m"
xterm_colormap = termstr.ColorMap.XTermColorMap()
def color(color_number, is_foreground):
return f"[{'38' if is_foreground else '48'};5;{color_number:d}m"
def rgb_color(rgb, is_foreground):
return f"[{'38' if is_foreground else '48'};2;" + "%i;%i;%im" % rgb
@functools.lru_cache()
def xterm_color_to_rgb(color_index):
return termstr.ColorMap._rgb(xterm_colormap.colors[color_index])
class Color:
# https://en.wikipedia.org/wiki/Natural_Color_System
black = (0, 0, 0)
white = (255, 255, 255)
red = (196, 2, 51)
green = (0, 159, 107)
dark_green = (0, 119, 80)
blue = (0, 135, 189)
lime = (0, 255, 0)
yellow = (255, 211, 0)
grey_30 = (30, 30, 30)
grey_50 = (50, 50, 50)
grey_80 = (80, 80, 80)
grey_100 = (100, 100, 100)
grey_150 = (150, 150, 150)
grey_200 = (200, 200, 200)
light_blue = (173, 216, 230)
purple = (200, 0, 200)
brown = (150, 75, 0)
orange = (255, 153, 0)
class CharStyle:
_POOL = weakref.WeakValueDictionary()
_TERMINAL256_FORMATTER = \
pygments.formatters.terminal256.Terminal256Formatter()
def __new__(cls, fg_color=None, bg_color=None, is_bold=False,
is_italic=False, is_underlined=False):
if fg_color is None:
fg_color = Color.white
if bg_color is None:
bg_color = Color.black
key = (fg_color, bg_color, is_bold, is_italic, is_underlined)
try:
return CharStyle._POOL[key]
except KeyError:
obj = object.__new__(cls)
obj.fg_color, obj.bg_color, obj.is_bold, obj.is_italic, \
obj.is_underlined = key
return CharStyle._POOL.setdefault(key, obj)
def __getnewargs__(self):
return (self.fg_color, self.bg_color, self.is_bold, self.is_italic,
self.is_underlined)
def __getstate__(self):
state = self.__dict__.copy()
if "_cache" in state:
del state["_cache"]
return state
def __setstate__(self, state):
self.__dict__ = state
def __repr__(self):
attributes = []
if self.is_bold:
attributes.append("b")
if self.is_italic:
attributes.append("i")
if self.is_underlined:
attributes.append("u")
return (f"<CharStyle: fg:{self.fg_color} bg:{self.bg_color}"
f" attr:{','.join(attributes)}>")
def _color_code(self, color_, is_foreground):
if isinstance(color_, int):
return color(color_, is_foreground)
else: # true color
if os.environ.get("TERM", None) == "xterm":
closest_color = self._TERMINAL256_FORMATTER._closest_color(
*color_)
return color(closest_color, is_foreground)
else:
return rgb_color(color_, is_foreground)
@functools.cached_property
def code_for_term(self):
fg_termcode = ESC + self._color_code(self.fg_color, True)
bg_termcode = ESC + self._color_code(self.bg_color, False)
bold_code = (ESC + BOLD) if self.is_bold else ""
italic_code = ((ESC + ITALIC) if self.is_italic else "")
underline_code = ((ESC + UNDERLINE) if self.is_underlined else "")
return "".join([ESC, NORMAL, fg_termcode, bg_termcode, bold_code,
italic_code, underline_code])
def as_html(self):
bold_code = "font-weight:bold; " if self.is_bold else ""
italic_code = "font-style:italic; " if self.is_italic else ""
underline_code = ("text-decoration:underline; "
if self.is_underlined else "")
fg_color = (self.fg_color if type(self.fg_color) == tuple
else xterm_color_to_rgb(self.fg_color))
bg_color = (self.bg_color if type(self.bg_color) == tuple
else xterm_color_to_rgb(self.bg_color))
return (f"<style>.S{id(self)} {{font-size:80%%; color:rgb{fg_color!r};"
f" background-color:rgb{bg_color!r}; "
f"{bold_code}{italic_code}{underline_code}}}</style>")
def _join_lists(lists):
return list(itertools.chain.from_iterable(lists))
_ZERO_WIDTH_SPACE = "\u200b"
def _pad_wide_chars(str_):
return "".join(f"{char}{_ZERO_WIDTH_SPACE}"
if cwcwidth.wcwidth(char) == 2 else char for char in str_)
class TermStr(collections.UserString):
def __init__(self, data, style=CharStyle()):
if isinstance(style, tuple):
self.data = data
self.style = style
else:
try:
self.data, self.style = data.data, data.style
except AttributeError:
self.data = _pad_wide_chars(data)
self.style = (style,) * len(self.data)
@classmethod
def from_term(cls, data):
data = data.expandtabs(tabsize=4)
parts = data.split(ESC)
fg_color, bg_color = None, None
is_bold, is_italic, is_underlined = False, False, False
result_parts = [parts[0]]
for part in parts[1:]:
if part.startswith("[K"):
end_index = part.index("K")
codes = []
else:
try:
end_index = part.index("m")
except ValueError:
continue
codes = part[1:end_index].split(";")
previous_code = None
for index, code in enumerate(codes):
try:
code_int = int(code)
except ValueError:
code_int = None
if code in ["", "0", "00"]: # Normal
is_bold, is_italic, is_underlined = False, False, False
fg_color, bg_color = None, None
elif code in ["01", "1"]: # bold
is_bold = True
elif code in ["03", "3"]: # italic
is_italic = True
elif code in ["04", "4"]: # underline
is_underlined = True
elif code_int and 30 <= code_int <= 37 : # dim fg color
fg_color = int(code[1])
elif code_int and 40 <= code_int <= 47: # dim bg color
bg_color = int(code[1])
elif code_int and 90 <= code_int <= 97: # high fg color
fg_color = int(code[1]) + 8
elif code_int and 100 <= code_int <= 107: # high bg color
bg_color = int(code[2]) + 8
elif code == "5" and previous_code == "38": # simple fg color
fg_color = int(codes[index+1])
codes[index+1:index+2] = []
elif code == "5" and previous_code == "48": # simple bg color
bg_color = int(codes[index+1])
codes[index+1:index+2] = []
elif code == "2" and previous_code == "38": # rgb fg color
fg_color = tuple(int(component)
for component in codes[index+1:index+4])
codes[index+1:index+4] = []
elif code == "2" and previous_code == "48": # rgb bg color
bg_color = tuple(int(component)
for component in codes[index+1:index+4])
codes[index+1:index+4] = []
previous_code = code
result_parts.append(cls(part[end_index+1:],
CharStyle(fg_color, bg_color, is_bold,
is_italic, is_underlined)))
return cls("").join(result_parts)
def __eq__(self, other):
return (self is other or
(isinstance(other, self.__class__) and
self.data == other.data and self.style == other.style))
def __ne__(self, other):
return not self.__eq__(other)
def __hash__(self):
return hash((self.data, self.style))
@functools.cached_property
def _partition_style(self):
if self.data == "":
return []
last_style, last_index = None, 0
result = []
for index, style in enumerate(self.style):
if style != last_style:
if last_style is not None:
result.append((last_style, last_index, index))
last_style, last_index = style, index
result.append((last_style, last_index, len(self.style)))
return result
def __str__(self):
return "".join(_join_lists(
[style.code_for_term, self.data[start_index:end_index]]
for style, start_index, end_index in self._partition_style) +
[ESC + NORMAL])
def __repr__(self):
return f"<TermStr: {self.data!r}>"
def __add__(self, other):
if isinstance(other, str):
other = TermStr(other)
return self.__class__(self.data + other.data, self.style + other.style)
def __radd__(self, other):
if isinstance(other, str):
other = TermStr(other)
return self.__class__(other.data + self.data, other.style + self.style)
def __mul__(self, n):
return self.__class__(self.data*n, self.style*n)
__rmul__ = __mul__
def __getitem__(self, index):
data = self.data[index]
if len(data) == 0:
result = ""
else:
first_char = " " if data[0] == _ZERO_WIDTH_SPACE else data[0]
if len(data) == 1:
result = first_char
else:
end_char = " " if cwcwidth.wcwidth(data[-1]) == 2 else data[-1]
result = first_char + data[1:-1] + end_char
return self.__class__(result, self.style[index])
def join(self, parts):
parts = [TermStr(part) if isinstance(part, str) else part
for part in parts]
joined_style = _join_lists(self.style + part.style for part in parts)
return self.__class__(self.data.join(part.data for part in parts),
tuple(joined_style[len(self.style):]))
def _split_style(self, parts, sep_length):
result = []
cursor = 0
for part in parts:
style_part = self.style[cursor:cursor+len(part)]
result.append(self.__class__(part, style_part))
cursor += (len(part) + sep_length)
return result
def split(self, sep=None, maxsplit=-1):
return self._split_style(self.data.split(sep, maxsplit), len(sep))
def splitlines(self, keepends=0):
result = []
cursor = 0
for line in self.data.splitlines(keepends=True):
result_line = line if keepends else line.rstrip("\r\n")
style_part = self.style[cursor:cursor+len(result_line)]
result.append(self.__class__(result_line, style_part))
cursor += len(line)
return result
def capitalize(self):
return self.__class__(self.data.capitalize(), self.style)
def lower(self):
return self.__class__(self.data.lower(), self.style)
def swapcase(self):
return self.__class__(self.data.swapcase(), self.style)
def title(self):
return self.__class__(self.data.title(), self.style)
def upper(self):
return self.__class__(self.data.upper(), self.style)
def ljust(self, width, fillchar=" "):
return self + self.__class__(fillchar * (width - len(self.data)))
def rjust(self, width, fillchar=" "):
return self.__class__(fillchar * (width - len(self.data))) + self
def center(self, width, fillchar=" "):
left_width = (width - len(self.data)) // 2
if left_width < 1:
return self
return (self.__class__(fillchar * left_width) + self +
self.__class__(fillchar *
(width - left_width - len(self.data))))
# Below are extra methods useful for termstrs.
def transform_style(self, transform_func):
new_style = tuple(_join_lists(
[transform_func(style)] * (end_index - start_index)
for style, start_index, end_index in self._partition_style))
return self.__class__(self.data, new_style)
def bold(self):
def make_bold(style):
return CharStyle(style.fg_color, style.bg_color, is_bold=True,
is_italic=style.is_italic,
is_underlined=style.is_underlined)
return self.transform_style(make_bold)
def underline(self):
def make_underlined(style):
return CharStyle(style.fg_color, style.bg_color,
is_bold=style.is_bold, is_italic=style.is_italic,
is_underlined=True)
return self.transform_style(make_underlined)
def italic(self):
def make_italic(style):
return CharStyle(style.fg_color, style.bg_color,
is_bold=style.is_bold, is_italic=True,
is_underlined=style.is_underlined)
return self.transform_style(make_italic)
def fg_color(self, fg_color):
def set_fgcolor(style):
return CharStyle(fg_color, style.bg_color, is_bold=style.is_bold,
is_italic=style.is_italic,
is_underlined=style.is_underlined)
return self.transform_style(set_fgcolor)
def bg_color(self, bg_color):
def set_bgcolor(style):
return CharStyle(style.fg_color, bg_color, is_bold=style.is_bold,
is_italic=style.is_italic,
is_underlined=style.is_underlined)
return self.transform_style(set_bgcolor)
def as_html(self):
result = []
styles = set()
for style, start_index, end_index in self._partition_style:
styles.add(style)
encoded = str(html.escape(self.data[start_index:end_index]).encode(
"ascii", "xmlcharrefreplace"))[2:-1]
encoded = encoded.replace("\\\\", "\\")
result.append(f'<span class="S{id(style):d}">{encoded}</span>')
return "".join(result), styles