commit 21080d07492028ac39bfbad8688239a5b23e0c71
Author: Pollux <pollux@pollux.codes>
Date: Sun, 13 Apr 2025 22:07:09 -0500
feat: initial commit
Signed-off-by: Pollux <pollux@pollux.codes>
Diffstat:
4 files changed, 143 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+src/morph.egg-info
+src/__pycache__
diff --git a/pyproject.toml b/pyproject.toml
@@ -0,0 +1,16 @@
+[build-system]
+requires = ["setuptools", "setuptools-scm"]
+build-backend = "setuptools.build_meta"
+
+[project]
+name = "morph"
+version = "0.0"
+authors = [
+ { name = "Pollux", email = "pollux@pollux.codes" }
+]
+description = ""
+readme = "README.md"
+requires-python = ">=3.13"
+
+[project.scripts]
+morph = "morph:main"
diff --git a/src/morph.py b/src/morph.py
@@ -0,0 +1,117 @@
+import argparse
+import tomllib
+import os
+import subprocess
+import glob
+import re
+
+template_regex = re.compile('{{([^}:]*)(?::([^}]*))?}}')
+
+def get_destination_dir(cmdline):
+ if cmdline != None:
+ return cmdline
+ home=os.getenv('HOME')
+ return f'{home}/.cache/morph'
+
+def get_templates_dir(cmdline):
+ if cmdline != None:
+ return cmdline
+
+ xdg_config_home=os.getenv('XDG_CONFIG_HOME')
+ home=os.getenv('HOME')
+
+ if xdg_config_home != None:
+ return f'{xdg_config_home}/morph/templates'
+ return f'{home}/.config/morph/templates'
+
+def get_config_file(cmdline):
+ if cmdline != None:
+ return cmdline
+
+ xdg_config_home=os.getenv('XDG_CONFIG_HOME')
+ home=os.getenv('HOME')
+
+ if xdg_config_home != None:
+ return f'{xdg_config_home}/morph/config.toml'
+ return f'{home}/.config/morph/config.toml'
+
+def replace_colors(theme):
+ def tmp(match):
+ color = match.group(1)
+ format = match.group(2)
+ if format == None:
+ format = 'hex_rgba'
+
+ hex = theme[color]
+ r = int(hex[:2],16)
+ g = int(hex[2:4],16)
+ b = int(hex[4:6],16)
+ a = int(hex[6:8],16)
+
+ match format:
+ case 'hex_rgba':
+ return hex
+ case 'hex_rgb':
+ return hex[:6]
+ case 'int_rgba':
+ return f'{r}, {g}, {b}, {a}'
+ case 'int_rgb':
+ return f'{r}, {g}, {b}'
+ case 'float_rgba':
+ return f'{r/255}, {g/255}, {b/255}, {a/255}'
+ case 'float_rgb':
+ return f'{r/255}, {g/255}, {b/255}'
+ return tmp
+
+def main():
+
+ parser = argparse.ArgumentParser(
+ prog='morph',
+ description='Linux color ricer')
+
+ parser.add_argument('theme')
+ parser.add_argument('-c', '--config')
+ parser.add_argument('-t', '--templates')
+ parser.add_argument('-d', '--destination')
+ parser.add_argument('-v', '--verbose', action='store_true')
+
+ args = parser.parse_args()
+
+ config_file = get_config_file(args.config)
+ templates_dir = get_templates_dir(args.templates)
+ destination_dir = get_destination_dir(args.destination)
+
+ with open(config_file, 'rb') as f:
+ themes = tomllib.load(f)
+
+ if args.verbose:
+ print(f'Config File: {config_file}')
+ print(f'Templates: {templates_dir}')
+ print(f'Destination: {destination_dir}')
+ print(f'Applying theme: {args.theme}')
+
+ theme = themes[args.theme]
+
+ if 'pre-exec' in theme:
+ subprocess.run(theme['pre-exec'], shell=True)
+
+ files = glob.glob('**', root_dir=templates_dir, recursive=True)
+
+ for file in files:
+ if os.path.isdir(f'{templates_dir}/{file}'):
+ os.makedirs(f'{destination_dir}/{file}', exist_ok=True)
+ continue
+
+ src_file = f'{templates_dir}/{file}'
+ dest_file = f'{destination_dir}/{file}'
+
+ with open(src_file, 'r') as f:
+ src_string = f.read()
+
+ out_string = re.sub(template_regex, replace_colors(theme), src_string)
+
+ with open(dest_file, 'w') as f:
+ f.write(out_string)
+
+ if 'post-exec' in theme:
+ subprocess.run(theme['post-exec'], shell=True)
diff --git a/theme.toml b/theme.toml
@@ -0,0 +1,8 @@
+[general]
+pre-exec="test"
+post-exec="test"
+
+[colors]
+a="ffffff"
+b="000000"
+c="cccccc"