[+] Recommended color alignments

This commit is contained in:
Azalea (on HyDEV-Daisy) 2022-06-19 22:37:27 -04:00
parent 59f5fd5651
commit d11796ef02
9 changed files with 132 additions and 48 deletions

View file

@ -2,7 +2,6 @@ from __future__ import annotations
from . import main from . import main
__version__ = main.VERSION __version__ = main.VERSION

View file

@ -1,9 +1,10 @@
from __future__ import annotations from __future__ import annotations
import numpy as np import numpy as np
from .color_util import RGB
from numpy import ndarray from numpy import ndarray
from .color_util import RGB
def create_gradient_hex(colors: list[str], resolution: int = 300) -> ndarray: def create_gradient_hex(colors: list[str], resolution: int = 300) -> ndarray:
""" """

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import colorsys import colorsys
from typing import NamedTuple from typing import NamedTuple
from typing_extensions import Literal from typing_extensions import Literal
from .constants import GLOBAL_CFG from .constants import GLOBAL_CFG
@ -184,3 +185,7 @@ class RGB(NamedTuple):
""" """
h, l, s = colorsys.rgb_to_hls(*[v / 255.0 for v in self]) h, l, s = colorsys.rgb_to_hls(*[v / 255.0 for v in self])
return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, light, s)]) return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, light, s)])
def set_min_light(self, light: float) -> 'RGB':
h, l, s = colorsys.rgb_to_hls(*[v / 255.0 for v in self])
return RGB(*[round(v * 255.0) for v in colorsys.hls_to_rgb(h, max(l, light), s)])

View file

@ -35,6 +35,7 @@ class GlobalConfig:
color_mode: str color_mode: str
override_distro: str | None override_distro: str | None
debug: bool debug: bool
is_light: bool
GLOBAL_CFG = GlobalConfig(color_mode='8bit', override_distro=None, debug=False) GLOBAL_CFG = GlobalConfig(color_mode='8bit', override_distro=None, debug=False, is_light=False)

View file

@ -5,30 +5,16 @@ import argparse
import json import json
import random import random
import re import re
from dataclasses import dataclass
from itertools import permutations from itertools import permutations
from typing import Iterable from typing import Iterable
from typing_extensions import Literal from hyfetch import presets
from .color_util import AnsiMode, printc, color, clear_screen from .color_util import printc, color, clear_screen
from .constants import CONFIG_PATH, VERSION, TERM_LEN, TEST_ASCII_WIDTH, TEST_ASCII, GLOBAL_CFG from .constants import CONFIG_PATH, VERSION, TERM_LEN, TEST_ASCII_WIDTH, TEST_ASCII, GLOBAL_CFG
from .neofetch_util import run_neofetch, get_distro_ascii, ColorAlignment, ascii_size from .models import Config
from .neofetch_util import run_neofetch, get_distro_ascii, ColorAlignment, ascii_size, color_alignments
from .presets import PRESETS from .presets import PRESETS
from .serializer import json_stringify
@dataclass
class Config:
preset: str
mode: AnsiMode
light_dark: Literal['light', 'dark'] = 'dark'
lightness: float | None = None
color_align: ColorAlignment = ColorAlignment('horizontal')
def save(self):
CONFIG_PATH.parent.mkdir(exist_ok=True, parents=True)
CONFIG_PATH.write_text(json_stringify(self), 'utf-8')
def check_config() -> Config: def check_config() -> Config:
@ -147,6 +133,7 @@ def create_config() -> Config:
light_dark = literal_input(f'3. Is your terminal in &gf(#85e7e9)light mode&r or &gf(#c471ed)dark mode&r?', light_dark = literal_input(f'3. Is your terminal in &gf(#85e7e9)light mode&r or &gf(#c471ed)dark mode&r?',
['light', 'dark'], 'dark') ['light', 'dark'], 'dark')
is_light = light_dark == 'light' is_light = light_dark == 'light'
GLOBAL_CFG.is_light = is_light
title += f'\n&e3. Light/Dark: &r{light_dark}' title += f'\n&e3. Light/Dark: &r{light_dark}'
############################# #############################
@ -265,7 +252,9 @@ def run():
parser.add_argument('--c-set-l', dest='light', help=f'Set lightness value of the colors', type=float) parser.add_argument('--c-set-l', dest='light', help=f'Set lightness value of the colors', type=float)
parser.add_argument('-V', '--version', dest='version', action='store_true', help=f'Check version') parser.add_argument('-V', '--version', dest='version', action='store_true', help=f'Check version')
parser.add_argument('--debug', action='store_true', help=color(f'Debug mode')) parser.add_argument('--debug', action='store_true', help=color(f'Debug mode'))
parser.add_argument('--test-distro', help=color(f'Test print a specific distro\'s ascii art')) parser.add_argument('--debug-list', help=color(f'Debug recommendations'))
parser.add_argument('--test-distro', help=color(f'Test for a specific distro'))
parser.add_argument('--test-print', action='store_true', help=color(f'Test print distro ascii art only'))
args = parser.parse_args() args = parser.parse_args()
@ -281,6 +270,10 @@ def run():
if args.debug: if args.debug:
GLOBAL_CFG.debug = True GLOBAL_CFG.debug = True
if args.test_print:
print(get_distro_ascii())
return
# Load config # Load config
config = check_config() config = check_config()
@ -296,6 +289,7 @@ def run():
# Override global color mode # Override global color mode
GLOBAL_CFG.color_mode = config.mode GLOBAL_CFG.color_mode = config.mode
GLOBAL_CFG.is_light = config.light_dark == 'light'
# Get preset # Get preset
preset = PRESETS.get(config.preset) preset = PRESETS.get(config.preset)
@ -308,5 +302,16 @@ def run():
if config.lightness: if config.lightness:
preset = preset.set_light(config.lightness) preset = preset.set_light(config.lightness)
# Debug recommendations
if args.debug_list:
distro = args.debug_list
ca = color_alignments[distro]
print(distro)
GLOBAL_CFG.override_distro = distro
asciis = [ca.recolor_ascii(get_distro_ascii(distro), p).split('\n') for p in list(PRESETS.values())[:3]]
[printc(' '.join(line)) for line in zip(*asciis)]
return
# Run # Run
run_neofetch(preset, config.color_align) run_neofetch(preset, config.color_align)

23
hyfetch/models.py Normal file
View file

@ -0,0 +1,23 @@
from __future__ import annotations
from dataclasses import dataclass
from typing_extensions import Literal
from .color_util import AnsiMode
from .constants import CONFIG_PATH
from .neofetch_util import ColorAlignment
from .serializer import json_stringify
@dataclass
class Config:
preset: str
mode: AnsiMode
light_dark: Literal['light', 'dark'] = 'dark'
lightness: float | None = None
color_align: ColorAlignment = ColorAlignment('horizontal')
def save(self):
CONFIG_PATH.parent.mkdir(exist_ok=True, parents=True)
CONFIG_PATH.write_text(json_stringify(self), 'utf-8')

View file

@ -10,13 +10,12 @@ from subprocess import check_output
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
import pkg_resources import pkg_resources
from hyfetch.color_util import color
from typing_extensions import Literal from typing_extensions import Literal
from hyfetch.color_util import color
from .constants import GLOBAL_CFG from .constants import GLOBAL_CFG
from .presets import ColorProfile from .presets import ColorProfile
RE_NEOFETCH_COLOR = re.compile('\\${c[0-9]}') RE_NEOFETCH_COLOR = re.compile('\\${c[0-9]}')
@ -38,6 +37,26 @@ def normalize_ascii(asc: str) -> str:
return '\n'.join(line + ' ' * (w - ascii_size(line)[0]) for line in asc.split('\n')) return '\n'.join(line + ' ' * (w - ascii_size(line)[0]) for line in asc.split('\n'))
def fill_starting(asc: str) -> str:
"""
Fill the missing starting placeholders.
E.g. "${c1}...\n..." -> "${c1}...\n${c1}..."
"""
new = []
last = ''
for line in asc.split('\n'):
new.append(last + line)
# Line has color placeholders
matches = RE_NEOFETCH_COLOR.findall(line)
if len(matches) > 0:
# Get the last placeholder for the next line
last = matches[-1]
return '\n'.join(new)
@dataclass @dataclass
class ColorAlignment: class ColorAlignment:
mode: Literal['horizontal', 'vertical', 'custom'] mode: Literal['horizontal', 'vertical', 'custom']
@ -45,13 +64,35 @@ class ColorAlignment:
# custom_colors[ascii color index] = unique color index in preset # custom_colors[ascii color index] = unique color index in preset
custom_colors: dict[int, int] = () custom_colors: dict[int, int] = ()
# Foreground/background ascii color index
fore_back: tuple[int, int] = ()
def recolor_ascii(self, asc: str, preset: ColorProfile) -> str: def recolor_ascii(self, asc: str, preset: ColorProfile) -> str:
""" """
Use the color alignment to recolor an ascii art Use the color alignment to recolor an ascii art
:return Colored ascii, Uncolored lines :return Colored ascii, Uncolored lines
""" """
if self.mode in ['horizontal', 'vertical']: asc = fill_starting(asc)
if self.fore_back and self.mode in ['horizontal', 'vertical']:
fore, back = self.fore_back
# Replace foreground colors
asc = asc.replace(f'${{c{fore}}}', color('&0' if GLOBAL_CFG.is_light else '&f'))
lines = asc.split('\n')
# Add new colors
if self.mode == 'horizontal':
colors = preset.with_length(len(lines))
asc = '\n'.join([l.replace(f'${{c{back}}}', colors[i].to_ansi()) + color('&r') for i, l in enumerate(lines)])
else:
raise NotImplementedError()
# Remove existing colors
asc = re.sub(RE_NEOFETCH_COLOR, '', asc)
elif self.mode in ['horizontal', 'vertical']:
# Remove existing colors # Remove existing colors
asc = re.sub(RE_NEOFETCH_COLOR, '', asc) asc = re.sub(RE_NEOFETCH_COLOR, '', asc)
lines = asc.split('\n') lines = asc.split('\n')
@ -67,28 +108,9 @@ class ColorAlignment:
preset = preset.unique_colors() preset = preset.unique_colors()
# Apply colors # Apply colors
new = []
start_color = None
color_map = {ai: preset.colors[pi].to_ansi() for ai, pi in self.custom_colors.items()} color_map = {ai: preset.colors[pi].to_ansi() for ai, pi in self.custom_colors.items()}
for line in asc.split('\n'): for ascii_i, c in color_map.items():
# Line has color placeholders asc = asc.replace(f'${{c{ascii_i}}}', c)
if len(RE_NEOFETCH_COLOR.findall(line)) > 0:
# Get the last placeholder for the next line
last = int(RE_NEOFETCH_COLOR.findall(line)[-1][3])
# Replace placeholders
for ascii_i, c in color_map.items():
line = line.replace(f'${{c{ascii_i}}}', c)
# Add to new ascii
new.append(f'{start_color or ""}{line}')
# Change next start color
start_color = color_map[last]
else:
new.append(f'{start_color or ""}{line}')
asc = '\n'.join(new)
return asc return asc
@ -111,8 +133,9 @@ def get_distro_ascii(distro: str | None = None) -> str:
""" """
if not distro and GLOBAL_CFG.override_distro: if not distro and GLOBAL_CFG.override_distro:
distro = GLOBAL_CFG.override_distro distro = GLOBAL_CFG.override_distro
print(distro) if GLOBAL_CFG.debug:
print(GLOBAL_CFG) print(distro)
print(GLOBAL_CFG)
cmd = 'print_ascii' cmd = 'print_ascii'
if distro: if distro:
os.environ['CUSTOM_DISTRO'] = distro os.environ['CUSTOM_DISTRO'] = distro
@ -148,3 +171,14 @@ def run_neofetch(preset: ColorProfile, alignment: ColorAlignment):
# print(full_cmd) # print(full_cmd)
subprocess.run(full_cmd) subprocess.run(full_cmd)
# Color alignment recommendations
color_alignments = {
'fedora': ColorAlignment('horizontal', fore_back=(2, 1)),
'ubuntu': ColorAlignment('horizontal', fore_back=(2, 1)),
'nixos': ColorAlignment('custom', {1: 1, 2: 0}),
# 'arch': ColorAlignment('horizontal'),
# 'centos': ColorAlignment('horizontal'),
}

View file

@ -109,6 +109,9 @@ class ColorProfile:
""" """
return ColorProfile([c.set_light(light) for c in self.colors]) return ColorProfile([c.set_light(light) for c in self.colors])
def set_min_light(self, light: float):
return ColorProfile([c.set_min_light(light) for c in self.colors])
def unique_colors(self) -> ColorProfile: def unique_colors(self) -> ColorProfile:
""" """
Create another color profile with only the unique colors Create another color profile with only the unique colors

View file

@ -11614,4 +11614,17 @@ get_print_custom_ascii() {
echo "$ascii_data" echo "$ascii_data"
} }
get_test_distro_ascii() {
# Load default config.
eval "$config"
distro="$CUSTOM_DISTRO"
ascii_distro=$distro
get_bold
get_distro_ascii
image_backend
dynamic_prompt
}
main "$@" main "$@"