morph.py (3291B)
1 import argparse 2 import tomllib 3 import os 4 import subprocess 5 import glob 6 import re 7 8 template_regex = re.compile("{{([^}:]*)(?::([^}]*))?}}") 9 10 11 def get_destination_dir(cmdline): 12 if cmdline != None: 13 return cmdline 14 home = os.getenv("HOME") 15 return f"{home}/.cache/morph" 16 17 18 def get_templates_dir(cmdline): 19 if cmdline != None: 20 return cmdline 21 22 xdg_config_home = os.getenv("XDG_CONFIG_HOME") 23 home = os.getenv("HOME") 24 25 if xdg_config_home != None: 26 return f"{xdg_config_home}/morph/templates" 27 return f"{home}/.config/morph/templates" 28 29 30 def get_config_file(cmdline): 31 if cmdline != None: 32 return cmdline 33 34 xdg_config_home = os.getenv("XDG_CONFIG_HOME") 35 home = os.getenv("HOME") 36 37 if xdg_config_home != None: 38 return f"{xdg_config_home}/morph/config.toml" 39 return f"{home}/.config/morph/config.toml" 40 41 42 def replace_colors(theme): 43 def tmp(match): 44 color = match.group(1) 45 format = match.group(2) 46 if format == None: 47 format = "hex_rgba" 48 49 hex = theme[color] 50 r = int(hex[:2], 16) 51 g = int(hex[2:4], 16) 52 b = int(hex[4:6], 16) 53 a = int(hex[6:8], 16) 54 55 match format: 56 case "hex_rgba": 57 return hex 58 case "hex_argb": 59 return hex[6:] + hex[:6] 60 case "hex_rgb": 61 return hex[:6] 62 case "int_rgba": 63 return f"{r}, {g}, {b}, {a}" 64 case "int_rgb": 65 return f"{r}, {g}, {b}" 66 case "float_rgba": 67 return f"{r/255}, {g/255}, {b/255}, {a/255}" 68 case "float_rgb": 69 return f"{r/255}, {g/255}, {b/255}" 70 71 return tmp 72 73 74 def main(): 75 76 parser = argparse.ArgumentParser(prog="morph", description="Linux color ricer") 77 78 parser.add_argument("theme") 79 parser.add_argument("-c", "--config") 80 parser.add_argument("-t", "--templates") 81 parser.add_argument("-d", "--destination") 82 parser.add_argument("-v", "--verbose", action="store_true") 83 84 args = parser.parse_args() 85 86 config_file = get_config_file(args.config) 87 templates_dir = get_templates_dir(args.templates) 88 destination_dir = get_destination_dir(args.destination) 89 90 with open(config_file, "rb") as f: 91 themes = tomllib.load(f) 92 93 if args.verbose: 94 print(f"Config File: {config_file}") 95 print(f"Templates: {templates_dir}") 96 print(f"Destination: {destination_dir}") 97 print(f"Applying theme: {args.theme}") 98 99 theme = themes[args.theme] 100 101 if "pre-exec" in theme: 102 subprocess.run(theme["pre-exec"], shell=True) 103 104 files = glob.glob("**", root_dir=templates_dir, recursive=True) 105 106 for file in files: 107 if os.path.isdir(f"{templates_dir}/{file}"): 108 os.makedirs(f"{destination_dir}/{file}", exist_ok=True) 109 continue 110 111 src_file = f"{templates_dir}/{file}" 112 dest_file = f"{destination_dir}/{file}" 113 114 with open(src_file, "r") as f: 115 src_string = f.read() 116 117 out_string = re.sub(template_regex, replace_colors(theme), src_string) 118 119 with open(dest_file, "w") as f: 120 f.write(out_string) 121 122 if "post-exec" in theme: 123 subprocess.run(theme["post-exec"], shell=True)