refactor: restructure dist/ and implement aggregated Zed theme

- Updated build.py to support app-centric directory structure (dist/<app>/).
- Modified build.py to allow aggregated multi-scheme rendering (for Zed).
- Refactored Zed template to include both Neon and Aeon variants in a single JSON.
- Standardized theme file naming in dist/.
This commit is contained in:
s0wlz (Matthias Puchstein)
2025-12-30 06:12:20 +01:00
parent b4b7316d52
commit b92c501fde
2 changed files with 377 additions and 31 deletions

View File

@@ -6,7 +6,7 @@ from jinja2 import Environment, FileSystemLoader
SRC_DIR = 'src'
TEMPLATES_DIR = 'templates'
DIST_DIR = 'dist'
SCHEMES = ['neon.yaml', 'aeon.yaml']
SCHEME_FILES = ['neon.yaml', 'aeon.yaml']
def load_scheme(filename):
with open(os.path.join(SRC_DIR, filename), 'r') as f:
@@ -18,47 +18,72 @@ def render_template(template_path, context):
return template.render(context)
def build():
# Load all schemes first
schemes = []
for f in SCHEME_FILES:
schemes.append(load_scheme(f))
# Ensure dist directory exists
if not os.path.exists(DIST_DIR):
os.makedirs(DIST_DIR)
for scheme_file in SCHEMES:
scheme_data = load_scheme(scheme_file)
scheme_name_slug = scheme_data['scheme'].lower().replace(' ', '-')
print(f"Building {scheme_data['scheme']}...")
# Walk through templates
for root, dirs, files in os.walk(TEMPLATES_DIR):
for file in files:
if not file.endswith('.j2'):
continue
# Find all templates
for root, dirs, files in os.walk(TEMPLATES_DIR):
for file in files:
if file.endswith('.j2'):
# Calculate relative path to mirror structure in dist
rel_path = os.path.relpath(root, TEMPLATES_DIR)
template_rel_path = os.path.join(rel_path, file)
rel_path = os.path.relpath(root, TEMPLATES_DIR)
app_name = rel_path # e.g., 'nvim', 'zed', 'kitty'
template_rel_path = os.path.join(rel_path, file)
output_filename_base = file.replace('.j2', '')
# Create app directory in dist
app_dist_dir = os.path.join(DIST_DIR, app_name)
if not os.path.exists(app_dist_dir):
os.makedirs(app_dist_dir)
print(f"Processing template: {template_rel_path}")
# Special case for Zed: Aggregated output (single JSON for all themes)
if app_name == 'zed':
context = {'schemes': schemes}
rendered_content = render_template(template_rel_path, context)
# Output file: dist/zed/apex.json (matches base name)
output_path = os.path.join(app_dist_dir, output_filename_base)
with open(output_path, 'w') as f:
f.write(rendered_content)
print(f" -> {output_path} (Aggregated)")
# Default behavior: Per-scheme output
else:
for scheme in schemes:
scheme_slug = scheme['scheme'].lower().replace(' ', '-')
# Prepare output path
output_filename = file.replace('.j2', '')
# If the template is generic (apex.lua), rename it to the scheme name (apex-neon.lua)
if 'apex' in output_filename:
output_filename = output_filename.replace('apex', scheme_name_slug)
# Rename output file: e.g., apex.conf -> apex-neon.conf
# or apex.lua -> apex-neon.lua
# If filename is generic 'apex', replace with slug.
# If filename is 'apex.lua', result 'apex-neon.lua'
output_dir = os.path.join(DIST_DIR, scheme_name_slug, rel_path)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
if 'apex' in output_filename_base:
final_filename = output_filename_base.replace('apex', f"apex-{scheme_slug.replace('apex-', '')}")
else:
final_filename = f"{scheme_slug}-{output_filename_base}"
# Clean up double prefixes if any (e.g. apex-apex-neon)
final_filename = final_filename.replace('apex-apex-', 'apex-')
output_path = os.path.join(app_dist_dir, final_filename)
output_path = os.path.join(output_dir, output_filename)
# Render and write
# We pass template_rel_path because jinja loader is rooted at TEMPLATES_DIR
# But os.walk returns paths relative to CWD usually, but we constructed it.
# Actually Environment loader is correct. We just need the path relative to templates dir.
template_name_for_jinja = template_rel_path
rendered_content = render_template(template_name_for_jinja, scheme_data)
rendered_content = render_template(template_rel_path, scheme)
with open(output_path, 'w') as f:
f.write(rendered_content)
print(f" -> {output_path}")
print(f" -> {output_path} ({scheme['scheme']})")
if __name__ == '__main__':
build()

321
templates/zed/apex.json.j2 Normal file
View File

@@ -0,0 +1,321 @@
{
"$schema": "https://zed.dev/schema/themes/v0.2.0.json",
"name": "Apex",
"author": "S0wlz (Owlibou)",
"themes": [
{% for s in schemes %}
{
"name": "{{ s.scheme }}",
"appearance": "{{ s.type }}",
"style": {
"background": "{{ s.palette.background }}",
"background.appearance": "opaque",
"surface.background": "{{ s.ui.panel }}",
"elevated_surface.background": "{% if s.type == 'dark' %}{{ s.ui.panel }}{% else %}#ffffff{% endif %}",
"panel.background": "{{ s.ui.panel }}",
"panel.focused_border": "{{ s.palette.cursor }}",
"panel.indent_guide": "{{ s.ui.border }}66",
"panel.indent_guide_active": "{{ s.ui.dim }}aa",
"panel.indent_guide_hover": "{{ s.ui.dim }}cc",
"tab_bar.background": "{% if s.type == 'dark' %}{{ s.ui.panel }}{% else %}{{ s.ui.panel }}{% endif %}",
"tab.inactive_background": "{{ s.ui.panel }}",
"tab.active_background": "{{ s.palette.background }}",
"title_bar.background": "{{ s.palette.background }}",
"title_bar.inactive_background": "{{ s.ui.panel }}",
"toolbar.background": "{{ s.ui.panel }}",
"status_bar.background": "{{ s.ui.panel }}",
"border": "{{ s.ui.border }}",
"border.variant": "{% if s.type == 'dark' %}{{ s.ui.panel }}{% else %}{{ s.ui.stealth }}{% endif %}",
"border.focused": "{{ s.palette.cursor }}",
"border.selected": "{{ s.palette.cursor }}",
"border.disabled": "{% if s.type == 'dark' %}{{ s.ui.panel }}{% else %}{{ s.ui.stealth }}{% endif %}",
"border.transparent": "transparent",
"text": "{{ s.palette.foreground }}",
"text.muted": "{{ s.ui.dim }}",
"text.placeholder": "{{ s.ui.dim }}",
"text.disabled": "{% if s.type == 'dark' %}{{ s.ui.dim }}{% else %}{{ s.ui.stealth }}{% endif %}",
"text.accent": "{{ s.palette.info }}",
"icon": "{{ s.palette.foreground }}",
"icon.muted": "{{ s.ui.dim }}",
"icon.placeholder": "{{ s.ui.dim }}",
"icon.disabled": "{% if s.type == 'dark' %}{{ s.ui.dim }}{% else %}{{ s.ui.stealth }}{% endif %}",
"icon.accent": "{{ s.palette.info }}",
"accents": [
"{{ s.palette.cursor }}",
"{{ s.palette.info }}",
"{{ s.palette.special }}",
"{{ s.palette.success }}",
"{{ s.palette.warning }}"
],
"element.background": "{% if s.type == 'dark' %}{{ s.ui.panel }}{% else %}#ffffff{% endif %}",
"element.hover": "{{ s.ui.border }}",
"element.active": "{{ s.ui.border }}",
"element.selected": "{{ s.ui.border }}",
"element.disabled": "{{ s.ui.panel }}",
"ghost_element.background": null,
"ghost_element.hover": "{{ s.ui.border }}66",
"ghost_element.active": "{{ s.ui.border }}88",
"ghost_element.selected": "{{ s.ui.border }}66",
"ghost_element.disabled": null,
"drop_target.background": "{% if s.type == 'dark' %}{{ s.palette.info }}22{% else %}{{ s.ansi.bright.cyan }}22{% endif %}",
"editor.background": "{{ s.palette.background }}",
"editor.foreground": "{{ s.palette.foreground }}",
"editor.gutter.background": "{{ s.palette.background }}",
"editor.subheader.background": "{{ s.ui.panel }}",
"editor.active_line.background": "{{ s.ui.panel }}",
"editor.highlighted_line.background": "{{ s.ui.panel }}",
"editor.line_number": "{{ s.ui.dim }}",
"editor.active_line_number": "{{ s.palette.cursor }}",
"editor.wrap_guide": "{{ s.ui.border }}",
"editor.active_wrap_guide": "{{ s.ui.dim }}",
"editor.indent_guide": "{{ s.ui.border }}66",
"editor.indent_guide_active": "{{ s.ui.dim }}aa",
"editor.invisible": "{{ s.ui.border }}88",
"editor.document_highlight.read_background": "{{ s.palette.info }}{% if s.type == 'dark' %}22{% else %}1a{% endif %}",
"editor.document_highlight.write_background": "{{ s.palette.cursor }}{% if s.type == 'dark' %}22{% else %}1a{% endif %}",
"editor.document_highlight.bracket_background": "{{ s.ui.border }}66",
"search.match_background": "{% if s.type == 'dark' %}{{ s.palette.info }}33{% else %}{{ s.ansi.bright.cyan }}44{% endif %}",
"scrollbar.track.background": "{{ s.palette.background }}",
"scrollbar.track.border": "{{ s.palette.background }}",
"scrollbar.thumb.background": "{% if s.type == 'dark' %}{{ s.ui.border }}aa{% else %}{{ s.ui.stealth }}aa{% endif %}",
"scrollbar.thumb.hover_background": "{% if s.type == 'dark' %}{{ s.ui.stealth }}{% else %}{{ s.ui.dim }}{% endif %}",
"scrollbar.thumb.border": "transparent",
"pane.focused_border": "{{ s.palette.cursor }}",
"pane_group.border": "{% if s.type == 'dark' %}{{ s.ui.border }}{% else %}{{ s.ui.stealth }}{% endif %}",
"link_text.hover": "{% if s.type == 'dark' %}{{ s.ansi.bright.blue }}{% else %}{{ s.ansi.bright.blue }}{% endif %}",
"success": "{{ s.palette.success }}",
"success.background": "{{ s.palette.success }}1a",
"success.border": "{{ s.palette.success }}",
"warning": "{{ s.palette.warning }}",
"warning.background": "{{ s.palette.warning }}1a",
"warning.border": "{{ s.palette.warning }}",
"error": "{{ s.ansi.bright.red }}",
"error.background": "{{ s.ansi.bright.red }}1a",
"error.border": "{{ s.ansi.bright.red }}",
"info": "{{ s.palette.info }}",
"info.background": "{{ s.palette.info }}1a",
"info.border": "{{ s.palette.info }}",
"hint": "{{ s.palette.azure }}",
"hint.background": "{{ s.palette.azure }}1a",
"hint.border": "{{ s.palette.azure }}",
"predictive": "{% if s.type == 'dark' %}{{ s.palette.azure }}{% else %}{{ s.palette.azure }}{% endif %}",
"predictive.background": "{{ s.palette.azure }}1a",
"predictive.border": "{{ s.palette.azure }}",
"unreachable": "{{ s.palette.special }}",
"unreachable.background": "{{ s.palette.special }}1a",
"unreachable.border": "{{ s.palette.special }}",
"created": "{{ s.palette.success }}",
"created.background": "{{ s.palette.success }}1a",
"created.border": "{{ s.palette.success }}",
"modified": "{{ s.palette.warning }}",
"modified.background": "{{ s.palette.warning }}1a",
"modified.border": "{{ s.palette.warning }}",
"deleted": "{{ s.ansi.bright.red }}",
"deleted.background": "{{ s.ansi.bright.red }}1a",
"deleted.border": "{{ s.ansi.bright.red }}",
"renamed": "{{ s.palette.info }}",
"renamed.background": "{{ s.palette.info }}1a",
"renamed.border": "{{ s.palette.info }}",
"conflict": "{{ s.ansi.bright.red }}",
"conflict.background": "{{ s.ansi.bright.red }}1a",
"conflict.border": "{{ s.ansi.bright.red }}",
"ignored": "{{ s.ui.dim }}",
"ignored.background": "{{ s.ui.dim }}1a",
"ignored.border": "{{ s.ui.border }}",
"hidden": "{{ s.ui.dim }}",
"hidden.background": "{{ s.ui.dim }}1a",
"hidden.border": "{{ s.ui.border }}",
"terminal.background": "{{ s.palette.background }}",
"terminal.foreground": "{{ s.palette.foreground }}",
"terminal.bright_foreground": "{% if s.type == 'dark' %}#ffffff{% else %}{{ s.palette.foreground }}{% endif %}",
"terminal.dim_foreground": "{{ s.ui.dim }}",
"terminal.ansi.background": "{{ s.palette.background }}",
"terminal.ansi.black": "{{ s.ansi.normal.black }}",
"terminal.ansi.red": "{{ s.ansi.normal.red }}",
"terminal.ansi.green": "{{ s.ansi.normal.green }}",
"terminal.ansi.yellow": "{{ s.ansi.normal.yellow }}",
"terminal.ansi.blue": "{{ s.ansi.normal.blue }}",
"terminal.ansi.magenta": "{{ s.ansi.normal.magenta }}",
"terminal.ansi.cyan": "{{ s.ansi.normal.cyan }}",
"terminal.ansi.white": "{{ s.ansi.normal.white }}",
"terminal.ansi.bright_black": "{{ s.ansi.bright.black }}",
"terminal.ansi.bright_red": "{{ s.ansi.bright.red }}",
"terminal.ansi.bright_green": "{{ s.ansi.bright.green }}",
"terminal.ansi.bright_yellow": "{{ s.ansi.bright.yellow }}",
"terminal.ansi.bright_blue": "{{ s.ansi.bright.blue }}",
"terminal.ansi.bright_magenta": "{{ s.ansi.bright.magenta }}",
"terminal.ansi.bright_cyan": "{{ s.ansi.bright.cyan }}",
"terminal.ansi.bright_white": "{{ s.ansi.bright.white }}",
"terminal.ansi.dim_black": "{{ s.ansi.normal.black }}",
"terminal.ansi.dim_red": "{{ s.ansi.normal.red }}",
"terminal.ansi.dim_green": "{{ s.ansi.normal.green }}",
"terminal.ansi.dim_yellow": "{{ s.ansi.normal.yellow }}",
"terminal.ansi.dim_blue": "{{ s.ansi.normal.blue }}",
"terminal.ansi.dim_magenta": "{{ s.ansi.normal.magenta }}",
"terminal.ansi.dim_cyan": "{{ s.ansi.normal.cyan }}",
"terminal.ansi.dim_white": "{{ s.ansi.normal.white }}",
"players": [
{
"cursor": "{{ s.palette.cursor }}",
"background": "{{ s.palette.cursor }}",
"selection": "{{ s.palette.cursor }}33"
},
{
"cursor": "{{ s.palette.info }}",
"background": "{{ s.palette.info }}",
"selection": "{{ s.palette.info }}33"
},
{
"cursor": "{{ s.palette.special }}",
"background": "{{ s.palette.special }}",
"selection": "{{ s.palette.special }}33"
},
{
"cursor": "{{ s.palette.success }}",
"background": "{{ s.palette.success }}",
"selection": "{{ s.palette.success }}33"
},
{
"cursor": "{{ s.palette.warning }}",
"background": "{{ s.palette.warning }}",
"selection": "{{ s.palette.warning }}33"
}
],
"version_control.added": "{{ s.palette.success }}",
"version_control.modified": "{{ s.palette.warning }}",
"version_control.deleted": "{{ s.ansi.bright.red }}",
"version_control.conflict": "{{ s.ansi.bright.red }}",
"version_control.renamed": "{{ s.palette.info }}",
"version_control.ignored": "{{ s.ui.dim }}",
"syntax": {
"comment": {
"color": "{{ s.ui.dim }}",
"font_style": "italic"
},
"comment.doc": {
"color": "{{ s.ui.dim }}",
"font_style": "italic"
},
"keyword": {
"color": "{{ s.palette.info }}"
},
"keyword.import": {
"color": "{{ s.palette.info }}"
},
"keyword.storage": {
"color": "{{ s.palette.info }}"
},
"function": {
"color": "{{ s.palette.azure }}"
},
"function.method": {
"color": "{{ s.palette.azure }}"
},
"function.special.definition": {
"color": "{{ s.palette.azure }}"
},
"type": {
"color": "{{ s.palette.special }}"
},
"type.builtin": {
"color": "{{ s.palette.special }}"
},
"string": {
"color": "{{ s.palette.success }}"
},
"string.escape": {
"color": "{{ s.ansi.bright.green }}"
},
"string.regex": {
"color": "{{ s.palette.warning }}"
},
"number": {
"color": "{{ s.palette.warning }}"
},
"boolean": {
"color": "{{ s.palette.warning }}"
},
"constant": {
"color": "{{ s.palette.foreground }}"
},
"constant.builtin": {
"color": "{{ s.palette.special }}"
},
"variable": {
"color": "{{ s.palette.foreground }}"
},
"variable.special": {
"color": "{{ s.palette.special }}"
},
"property": {
"color": "{{ s.palette.foreground }}"
},
"attribute": {
"color": "{{ s.palette.azure }}"
},
"tag": {
"color": "{{ s.palette.info }}"
},
"label": {
"color": "{{ s.palette.azure }}"
},
"operator": {
"color": "{{ s.palette.foreground }}"
},
"punctuation": {
"color": "{{ s.ui.dim }}"
},
"punctuation.bracket": {
"color": "{{ s.ui.dim }}"
},
"punctuation.delimiter": {
"color": "{{ s.ui.dim }}"
},
"punctuation.list_marker": {
"color": "{{ s.ui.dim }}",
"font_weight": 700
},
"link_text": {
"color": "{{ s.palette.info }}"
},
"link_uri": {
"color": "{{ s.palette.azure }}"
},
"emphasis": {
"font_style": "italic"
},
"emphasis.strong": {
"font_weight": 700
},
"title": {
"color": "{{ s.palette.foreground }}",
"font_weight": 700
},
"text.literal": {
"color": "{{ s.palette.success }}"
},
"preproc": {
"color": "{{ s.palette.azure }}"
},
"constructor": {
"color": "{{ s.palette.azure }}"
},
"enum": {
"color": "{{ s.palette.special }}"
},
"variant": {
"color": "{{ s.palette.special }}"
},
"hint": {
"color": "{{ s.palette.azure }}"
},
"predictive": {
"color": "{{ s.ui.dim }}"
}
}
}
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}