147 lines
5.0 KiB
Python
147 lines
5.0 KiB
Python
import argparse
|
|
import inspect
|
|
import subprocess
|
|
import json
|
|
import os
|
|
import tomllib as toml
|
|
from pathlib import Path
|
|
|
|
from colorama import Fore
|
|
|
|
def add_set_subparser(subparsers):
|
|
parser = subparsers.add_parser(
|
|
'set',
|
|
description='Generate theme files for various applications. Uses a template (in TOML ' \
|
|
+ 'format) to map application-specific config keywords to colors (in JSON ' \
|
|
+ 'format).'
|
|
)
|
|
parser.add_argument(
|
|
'-p', '--palette',
|
|
required=True,
|
|
help='Palette name, must match a folder in themes/'
|
|
)
|
|
parser.add_argument(
|
|
'-s', '--scheme',
|
|
required=True,
|
|
help='Preferred lightness scheme, either "light" or "dark".'
|
|
)
|
|
parser.add_argument(
|
|
'-a', '--app',
|
|
required=True,
|
|
help='Application target for theme. App must be present in the registry. ' \
|
|
+ 'Use "*" to apply to all registered apps'
|
|
)
|
|
parser.set_defaults(func=update_theme_settings)
|
|
|
|
|
|
def get_running_path():
|
|
calling_module = inspect.getmodule(inspect.stack()[-1][0])
|
|
return Path(calling_module.__file__).parent
|
|
|
|
def os_scheme_settings(scheme):
|
|
'''
|
|
Groups of settings/commands to invoke globally based on the provided `scheme`. This
|
|
may control things like default app light/dark behavior, for instance.
|
|
'''
|
|
os_cmd_groups = {
|
|
'Linux': [
|
|
"gsettings set org.gnome.desktop.interface color-scheme 'prefer-{scheme}'",
|
|
],
|
|
'Darwin': [],
|
|
}
|
|
|
|
if scheme not in ['light', 'dark']: return
|
|
osname = os.uname().sysname
|
|
cmd_list = os_cmd_groups.get(osname, [])
|
|
|
|
for cmd in cmd_list:
|
|
subprocess.check_call(cmd.format(scheme=scheme).split())
|
|
|
|
def update_theme_settings():
|
|
osname = os.uname().sysname
|
|
basepath = get_running_path()
|
|
app_registry = toml.load(Path(basepath, 'app_registry.toml').open('rb'))
|
|
app_registry = app_registry.get('app', {})
|
|
|
|
if args.app not in app_registry and args.app != '*':
|
|
print(f'App {args.app} not registered, exiting')
|
|
return
|
|
|
|
app_list = []
|
|
if args.app == '*':
|
|
app_list = list(app_registry.items())
|
|
else:
|
|
app_list = [(args.app, app_registry[args.app])]
|
|
|
|
links_succ = {}
|
|
links_fail = {}
|
|
for app_name, app_settings in app_list:
|
|
config_dir = Path(app_settings['config_dir']).expanduser()
|
|
config_file = app_settings['config_file']
|
|
config_path = Path(config_dir, config_file)
|
|
|
|
if osname not in app_settings['supported_oses']:
|
|
print(f'OS [{osname}] not support for app [{app_name}]')
|
|
continue
|
|
|
|
if app_settings['external_theme']:
|
|
# symlink from "current-theme.conf" in app's config-dir ...
|
|
from_conf_path = Path(config_dir, 'current-theme.conf')
|
|
|
|
# ... to appropriate generated theme path here in autoconf
|
|
to_conf_path = Path(
|
|
basepath,
|
|
f'themes/{args.palette}/apps/{app_name}/generated/{args.scheme}.conf'
|
|
)
|
|
else:
|
|
# symlink from the canonical config file ...
|
|
from_conf_path = config_path
|
|
|
|
# ... to appropriate theme variant
|
|
to_conf_path = Path(
|
|
config_dir,
|
|
f'{app_name}-{args.palette}-{args.scheme}{config_path.suffix}'
|
|
)
|
|
|
|
if not to_conf_path.exists():
|
|
print(
|
|
f'Expected symlink target [{to_conf_path}] doesn\'t exist, skipping'
|
|
)
|
|
links_fail[app_name] = (from_conf_path.name, to_conf_path.name)
|
|
continue
|
|
|
|
# if config file being symlinked exists & isn't already a symlink (i.e.,
|
|
# previously set by this script), throw an error.
|
|
if from_conf_path.exists() and not from_conf_path.is_symlink():
|
|
print(
|
|
f'Symlink origin [{from_conf_path}] exists and isn\'t a symlink; please ' \
|
|
+ 'first manually remove this file so this script can set the symlink.'
|
|
)
|
|
links_fail[app_name] = (from_conf_path.name, to_conf_path.name)
|
|
continue
|
|
else:
|
|
# if path doesn't exist, or exists and is symlink, remove the symlink in
|
|
# preparation for the new symlink setting
|
|
from_conf_path.unlink(missing_ok=True)
|
|
|
|
print(f'Linking [{from_conf_path}] -> [{to_conf_path}]')
|
|
|
|
# run color scheme live-reload for app, if available
|
|
# TODO: store the status of this cmd & print with the messages
|
|
if 'refresh_cmd' in app_settings:
|
|
subprocess.check_call(app_settings['refresh_cmd'], shell=True)
|
|
|
|
from_conf_path.symlink_to(to_conf_path)
|
|
links_succ[app_name] = (from_conf_path.name, to_conf_path.name)
|
|
|
|
for app, (from_p, to_p) in links_succ.items():
|
|
print(Fore.GREEN + f'> {app} :: {from_p} -> {to_p}')
|
|
|
|
for app, (from_p, to_p) in links_fail.items():
|
|
print(Fore.RED + f'> {app} :: {from_p} -> {to_p}')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
os_scheme_settings(args.scheme)
|
|
update_theme_settings()
|