[+] Recommended color alignments
This commit is contained in:
parent
59f5fd5651
commit
d11796ef02
9 changed files with 132 additions and 48 deletions
|
@ -2,7 +2,6 @@ from __future__ import annotations
|
|||
|
||||
from . import main
|
||||
|
||||
|
||||
__version__ = main.VERSION
|
||||
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
from .color_util import RGB
|
||||
from numpy import ndarray
|
||||
|
||||
from .color_util import RGB
|
||||
|
||||
|
||||
def create_gradient_hex(colors: list[str], resolution: int = 300) -> ndarray:
|
||||
"""
|
||||
|
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
import colorsys
|
||||
from typing import NamedTuple
|
||||
|
||||
from typing_extensions import Literal
|
||||
|
||||
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])
|
||||
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)])
|
||||
|
|
|
@ -35,6 +35,7 @@ class GlobalConfig:
|
|||
color_mode: str
|
||||
override_distro: str | None
|
||||
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)
|
||||
|
|
|
@ -5,30 +5,16 @@ import argparse
|
|||
import json
|
||||
import random
|
||||
import re
|
||||
from dataclasses import dataclass
|
||||
from itertools import permutations
|
||||
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 .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 .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:
|
||||
|
@ -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'], 'dark')
|
||||
is_light = light_dark == 'light'
|
||||
GLOBAL_CFG.is_light = is_light
|
||||
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('-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('--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()
|
||||
|
||||
|
@ -281,6 +270,10 @@ def run():
|
|||
if args.debug:
|
||||
GLOBAL_CFG.debug = True
|
||||
|
||||
if args.test_print:
|
||||
print(get_distro_ascii())
|
||||
return
|
||||
|
||||
# Load config
|
||||
config = check_config()
|
||||
|
||||
|
@ -296,6 +289,7 @@ def run():
|
|||
|
||||
# Override global color mode
|
||||
GLOBAL_CFG.color_mode = config.mode
|
||||
GLOBAL_CFG.is_light = config.light_dark == 'light'
|
||||
|
||||
# Get preset
|
||||
preset = PRESETS.get(config.preset)
|
||||
|
@ -308,5 +302,16 @@ def run():
|
|||
if 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_neofetch(preset, config.color_align)
|
||||
|
|
23
hyfetch/models.py
Normal file
23
hyfetch/models.py
Normal 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')
|
|
@ -10,13 +10,12 @@ from subprocess import check_output
|
|||
from tempfile import TemporaryDirectory
|
||||
|
||||
import pkg_resources
|
||||
from hyfetch.color_util import color
|
||||
from typing_extensions import Literal
|
||||
|
||||
from hyfetch.color_util import color
|
||||
from .constants import GLOBAL_CFG
|
||||
from .presets import ColorProfile
|
||||
|
||||
|
||||
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'))
|
||||
|
||||
|
||||
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
|
||||
class ColorAlignment:
|
||||
mode: Literal['horizontal', 'vertical', 'custom']
|
||||
|
@ -45,13 +64,35 @@ class ColorAlignment:
|
|||
# custom_colors[ascii color index] = unique color index in preset
|
||||
custom_colors: dict[int, int] = ()
|
||||
|
||||
# Foreground/background ascii color index
|
||||
fore_back: tuple[int, int] = ()
|
||||
|
||||
def recolor_ascii(self, asc: str, preset: ColorProfile) -> str:
|
||||
"""
|
||||
Use the color alignment to recolor an ascii art
|
||||
|
||||
: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
|
||||
asc = re.sub(RE_NEOFETCH_COLOR, '', asc)
|
||||
lines = asc.split('\n')
|
||||
|
@ -67,28 +108,9 @@ class ColorAlignment:
|
|||
preset = preset.unique_colors()
|
||||
|
||||
# Apply colors
|
||||
new = []
|
||||
start_color = None
|
||||
color_map = {ai: preset.colors[pi].to_ansi() for ai, pi in self.custom_colors.items()}
|
||||
for line in asc.split('\n'):
|
||||
# Line has color placeholders
|
||||
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)
|
||||
for ascii_i, c in color_map.items():
|
||||
asc = asc.replace(f'${{c{ascii_i}}}', c)
|
||||
|
||||
return asc
|
||||
|
||||
|
@ -111,8 +133,9 @@ def get_distro_ascii(distro: str | None = None) -> str:
|
|||
"""
|
||||
if not distro and GLOBAL_CFG.override_distro:
|
||||
distro = GLOBAL_CFG.override_distro
|
||||
print(distro)
|
||||
print(GLOBAL_CFG)
|
||||
if GLOBAL_CFG.debug:
|
||||
print(distro)
|
||||
print(GLOBAL_CFG)
|
||||
cmd = 'print_ascii'
|
||||
if distro:
|
||||
os.environ['CUSTOM_DISTRO'] = distro
|
||||
|
@ -148,3 +171,14 @@ def run_neofetch(preset: ColorProfile, alignment: ColorAlignment):
|
|||
# print(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'),
|
||||
}
|
||||
|
||||
|
|
|
@ -109,6 +109,9 @@ class ColorProfile:
|
|||
"""
|
||||
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:
|
||||
"""
|
||||
Create another color profile with only the unique colors
|
||||
|
|
13
neofetch
13
neofetch
|
@ -11614,4 +11614,17 @@ get_print_custom_ascii() {
|
|||
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 "$@"
|
||||
|
|
Loading…
Reference in a new issue