Coding style.
- Add xterm colors, and func for finding closest color, to termstr.py. - Remove termstr's dependencies on pygments and ColorMap.py.
This commit is contained in:
parent
b62afb5e69
commit
27fc9a433c
5 changed files with 35 additions and 150 deletions
|
|
@ -1,2 +1 @@
|
|||
pygments==2.10.0
|
||||
cwcwidth==0.1.5
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -7,11 +7,8 @@ import itertools
|
|||
import os
|
||||
import weakref
|
||||
|
||||
import pygments.formatters.terminal256
|
||||
import cwcwidth
|
||||
|
||||
import termstr.ColorMap
|
||||
|
||||
|
||||
ESC = "\x1b"
|
||||
|
||||
|
|
@ -21,9 +18,6 @@ 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"
|
||||
|
||||
|
|
@ -32,11 +26,6 @@ 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
|
||||
|
|
@ -60,11 +49,38 @@ class Color:
|
|||
orange = (255, 153, 0)
|
||||
|
||||
|
||||
def _xterm_colors():
|
||||
result = [
|
||||
(0x00, 0x00, 0x00), (0xcd, 0x00, 0x00), (0x00, 0xcd, 0x00),
|
||||
(0xcd, 0xcd, 0x00), (0x00, 0x00, 0xee), (0xcd, 0x00, 0xcd),
|
||||
(0x00, 0xcd, 0xcd), (0xe5, 0xe5, 0xe5), (0x7f, 0x7f, 0x7f),
|
||||
(0xff, 0x00, 0x00), (0x00, 0xff, 0x00), (0xff, 0xff, 0x00),
|
||||
(0x5c, 0x5c, 0xff), (0xff, 0x00, 0xff), (0x00, 0xff, 0xff),
|
||||
(0xff, 0xff, 0xff)]
|
||||
intensities = [0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
|
||||
result.extend([(intensities[(i // 36) % 6], intensities[(i // 6) % 6],
|
||||
intensities[i % 6]) for i in range(216)])
|
||||
result.extend([(8 + i * 10, 8 + i * 10, 8 + i * 10) for i in range(24)])
|
||||
return result
|
||||
|
||||
|
||||
XTERM_COLORS = _xterm_colors()
|
||||
|
||||
|
||||
def closest_color_index(color, colors):
|
||||
r, g, b = color
|
||||
closest_distance = 3 * (256*256) + 1
|
||||
for index, (r_, g_, b_) in enumerate(colors):
|
||||
distance = (r_ - r) ** 2 + (g_ - g) ** 2 + (b_ - b) ** 2
|
||||
if distance < closest_distance:
|
||||
closest_distance = distance
|
||||
color_index = index
|
||||
return color_index
|
||||
|
||||
|
||||
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):
|
||||
|
|
@ -110,9 +126,8 @@ class CharStyle:
|
|||
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)
|
||||
color_index = closest_color_index(color_, XTERM_COLORS)
|
||||
return color(color_index, is_foreground)
|
||||
else:
|
||||
return rgb_color(color_, is_foreground)
|
||||
|
||||
|
|
@ -132,9 +147,9 @@ class CharStyle:
|
|||
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))
|
||||
else xterm_colors[self.fg_color])
|
||||
bg_color = (self.bg_color if type(self.bg_color) == tuple
|
||||
else xterm_color_to_rgb(self.bg_color))
|
||||
else xterm_colors[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>")
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import os
|
|||
import pickle
|
||||
import unittest
|
||||
|
||||
os.environ["TERM"] = "xterm-256color"
|
||||
|
||||
import fill3.terminal as terminal
|
||||
import termstr
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue