194 lines
5.4 KiB
Python
Executable file
194 lines
5.4 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
"""
|
|
List distributions supported by neofetch
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import string
|
|
import textwrap
|
|
from pathlib import Path
|
|
|
|
import regex
|
|
import unicodedata
|
|
from hypy_utils import write
|
|
|
|
from hyfetch.distros import AsciiArt
|
|
|
|
RE_SPLIT = regex.compile('EOF[ \n]*?;;')
|
|
RE_COLORS = regex.compile("""(?<=set_colors )[\"#a-zA-Z\\d ']+(?=\n)""")
|
|
|
|
|
|
def substr(s: str, start: str, end: str | None = None):
|
|
"""
|
|
Get substring between start and end
|
|
"""
|
|
start = s.index(start) + len(start)
|
|
|
|
if end is None:
|
|
return s[start:]
|
|
|
|
return s[start:s.index(end, start)]
|
|
|
|
|
|
def parse_ascii_distros() -> list[AsciiArt]:
|
|
"""
|
|
Parse ascii distros from neofetch script
|
|
"""
|
|
nf = (Path(__file__).parent.parent / 'neofetch').read_text('utf-8').replace('\t', ' ' * 4)
|
|
|
|
# Get the content of "get_distro_ascii" function
|
|
nf = nf[nf.index('get_distro_ascii() {\n'):]
|
|
nf = nf[:nf.index('\n}\n')]
|
|
|
|
# Remove trailing spaces
|
|
while ' \n' in nf:
|
|
nf = nf.replace(' \n', '\n')
|
|
|
|
# Split by blocks
|
|
blocks = [sub.strip() for b in regex.split('case .*? in\n', nf) for sub in RE_SPLIT.split(b)]
|
|
|
|
# Parse blocks
|
|
def parse_block(block: str) -> AsciiArt:
|
|
try:
|
|
# Get ascii art
|
|
assert "'EOF'\n" in block
|
|
art = substr(block, "'EOF'\n")
|
|
|
|
# Join \
|
|
block = block.replace('\\\n', ' ')
|
|
|
|
# Get switch-case matching parameter
|
|
match = block.split('\n')[0].strip()
|
|
assert match.endswith(')')
|
|
match = match[:-1]
|
|
|
|
# Get colors
|
|
color = RE_COLORS.findall(block)[0].strip("'")
|
|
if len(color) == 0:
|
|
raise Exception(block)
|
|
|
|
return AsciiArt(match, color, art)
|
|
|
|
except AssertionError:
|
|
pass
|
|
|
|
out = [parse_block(block) for block in blocks]
|
|
return [v for v in out if v]
|
|
|
|
|
|
def wrap(text: str, max_len: int, leading: str):
|
|
length = max_len - len(leading)
|
|
lines = [line for raw in text.split('\n') for line in textwrap.wrap(raw, length) or ['']]
|
|
return '\n'.join(leading + line if line else line for line in lines)
|
|
|
|
|
|
def generate_help(max_len: int, leading: str):
|
|
distros = sorted(list({a.get_friendly_name() for a in parse_ascii_distros()}), key=str.casefold)
|
|
|
|
smalls = [d.replace('_small', '') for d in distros if d.endswith('_small')]
|
|
olds = [d.replace('_old', '') for d in distros if d.endswith('_old')]
|
|
distros = [d for d in distros if not d.endswith('_small') and not d.endswith('_old')]
|
|
|
|
out = f"NOTE: {', '.join(distros)} have ascii logos.\n\n"\
|
|
f"NOTE: {', '.join(olds)} have 'old' logo variants, use {{distro}}_old to use them.\n\n" \
|
|
f"NOTE: {', '.join(smalls)} have 'small' logo variants, use {{distro}}_small to use them."
|
|
|
|
return wrap(out, max_len, leading)
|
|
|
|
|
|
def match_condition(match: str) -> str:
|
|
"""
|
|
Convert simple glob match condition to python
|
|
"""
|
|
match = [s.strip() for s in match.split("|")]
|
|
conds = []
|
|
for m in match:
|
|
stripped = m.strip("*'\"").lower()
|
|
if '*' in stripped or '"' in stripped:
|
|
print(f"TODO: Cannot properly parse: {m}")
|
|
|
|
# Exact matches
|
|
if m.strip("*") == m:
|
|
conds.append(f"name == '{stripped}'")
|
|
continue
|
|
|
|
# Both sides are *
|
|
if m.startswith("*") and m.endswith("*"):
|
|
conds.append(f"(name.startswith('{stripped}') or name.endswith('{stripped}'))")
|
|
continue
|
|
|
|
# Ends with *
|
|
if m.endswith("*"):
|
|
conds.append(f"name.startswith('{stripped}')")
|
|
continue
|
|
|
|
# Starts with *
|
|
if m.startswith("*"):
|
|
conds.append(f"name.endswith('{stripped}')")
|
|
continue
|
|
|
|
return ' or '.join(conds)
|
|
|
|
|
|
def export_distro(d: AsciiArt) -> str:
|
|
"""
|
|
Export distro to a python script
|
|
"""
|
|
# Escape variable name
|
|
varname = d.name.lower()
|
|
for s in string.punctuation + ' ':
|
|
varname = varname.replace(s, '_')
|
|
|
|
# Remove accents
|
|
varname = unicodedata.normalize('NFKD', varname).encode('ascii', 'ignore').decode('utf-8')
|
|
|
|
# Escape/unescape ascii
|
|
ascii = d.ascii.replace("\\\\", "\\")
|
|
|
|
quotes = '"""'
|
|
if '"""' in ascii:
|
|
quotes = "'''"
|
|
if "'''" in ascii:
|
|
print(f"TODO: Cannot escape ascii because both \"\"\" and ''' exist: {ascii}")
|
|
|
|
script = f"""# This file is automatically generated. Please do not modify.
|
|
|
|
from . import AsciiArt
|
|
|
|
{varname} = AsciiArt(match=r'''{d.match}''', color='{d.color}', ascii=r{quotes}
|
|
{ascii}
|
|
{quotes})
|
|
"""
|
|
write(Path(__file__).parent.parent / f'hyfetch/distros/{varname}.py', script)
|
|
|
|
# Generate python script for identifying the distro
|
|
return f"""
|
|
if {match_condition(d.match)}:
|
|
from .{varname} import {varname}
|
|
return {varname}
|
|
"""
|
|
|
|
|
|
def export_distros():
|
|
distros = parse_ascii_distros()
|
|
# print('\n'.join(d.match for d in distros))
|
|
py = """# This file is automatically generated. Please do not modify.
|
|
|
|
from __future__ import annotations
|
|
|
|
from . import AsciiArt
|
|
|
|
def detect(name: str) -> AsciiArt | None:
|
|
if not name:
|
|
return None
|
|
name = name.lower()
|
|
"""
|
|
py += '\n'.join(export_distro(d).strip('\n') for d in distros)
|
|
write(Path(__file__).parent.parent / f'hyfetch/distros/distro_detector.py', py)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# print(generate_help(100, ' ' * 32))
|
|
# print(generate_help(100, '# '))
|
|
export_distros()
|