add minor details to usage docs

This commit is contained in:
smgr 2025-09-28 03:43:59 -07:00
parent 4d707b97e4
commit 13e366d1fe
8 changed files with 535 additions and 331 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ __pycache__/
.pytest_cache/
.python-version
.venv/
.ruff_cache/
# vendor and build files
dist/

165
README.md
View File

@ -1,63 +1,67 @@
# Symconf
`symconf` is a CLI tool for managing local application configuration. It implements a
general model that supports dynamically switching/reloading themes for any application,
and provides a basic means of templatizing your config files.
`symconf` is a CLI tool for managing local application configuration. It
implements a general model that supports dynamically switching/reloading themes
for any application, and provides a basic means of templatizing your config
files.
## Simple example
Below is a simple example demonstrating two system-wide theme switches:
![Simple example](docs/_static/example.gif)
This GIF shows two `symconf` calls, the first of which applies a `gruvbox` dark theme and
the second a dark [`monobiome`][1] variant. Each call (of the form `symconf config -m dark -s
style`) indicates a dark mode preference and a particular color palette that should be
used when populating config file templates. Specifically, in this example, invoking
`symconf` results in the following app-specific config updates:
This GIF shows two `symconf` calls, the first of which applies a `gruvbox` dark
theme and the second a dark [`monobiome`][1] variant. Each call (of the form
`symconf config -m dark -s style`) indicates a dark mode preference and a
particular color palette that should be used when populating config file
templates. Specifically, in this example, invoking `symconf` results in the
following app-specific config updates:
- **GTK**: reacts to the mode setting and sets `prefer-dark` system-wide, changing general
GTK-responsive applications like Nautilus and Firefox (and subsequently websites that
are responsive to `prefers-color-scheme`)
- **kitty**: theme template is re-generated using the specified palette, and `kitty`
processes are sent a message to live-reload the new config file
- **neovim**: a `vim` theme file (along with a statusline theme) is generated from the
chosen palette, and running instances of `neovim` are sent a message to re-source this
theme (via `nvim --remote-send`)
- **GTK**: reacts to the mode setting and sets `prefer-dark` system-wide,
changing general GTK-responsive applications like Nautilus and Firefox (and
subsequently websites that are responsive to `prefers-color-scheme`)
- **kitty**: theme template is re-generated using the specified palette, and
`kitty` processes are sent a message to live-reload the new config file
- **neovim**: a `vim` theme file (along with a statusline theme) is generated
from the chosen palette, and running instances of `neovim` are sent a message
to re-source this theme (via `nvim --remote-send`)
- **waybar**: bar styles are updated to match the mode setting
- **sway**: the background color and window borders are dynamically set to base palette
colors, and `swaymsg reload` is called
- **sway**: the background color and window borders are dynamically set to base
palette colors, and `swaymsg reload` is called
- **fzf**: a palette-dependent theme is re-generated and re-exported
- **rofi**: launcher text and highlight colors are set according to the mode and palette,
applying on next invocation
- **rofi**: launcher text and highlight colors are set according to the mode
and palette, applying on next invocation
This example highlights the generality of `symconf`, and so long as an app's config can be
reloaded dynamically, you can use a single `symconf` call to apply themes for an arbitrary
number of apps at once.
This example highlights the generality of `symconf`, and so long as an app's
config can be reloaded dynamically, you can use a single `symconf` call to
apply themes for an arbitrary number of apps at once.
# Behavior
`symconf` uses a simple operational model that symlinks centralized config files to their
expected locations across the system. This central config directory can then be version
controlled, and app config files can be updated in one place.
`symconf` uses a simple operational model that symlinks centralized config
files to their expected locations across the system. This central config
directory can then be version controlled, and app config files can be updated
in one place.
App config files can either be concrete (fully-specified) or templates (to be populated by
values conditional on style, e.g., a palette). When `symconf` is executed with a
particular mode preference (dark or light) and a style (any other indicator of thematic
elements, often simply in the form of a palette like `solarized` or `gruvbox`), it
searches for both concrete and template config files that match and symlinks them to
registered locations. When necessary, `symconf` will also match and execute scripts to
reload apps after updating their configuration.
App config files can either be concrete (fully-specified) or templates (to be
populated by values conditional on style, e.g., a palette). When `symconf` is
executed with a particular mode preference (dark or light) and a style (any
other indicator of thematic elements, often simply in the form of a palette
like `solarized` or `gruvbox`), it searches for both concrete and template
config files that match and symlinks them to registered locations. When
necessary, `symconf` will also match and execute scripts to reload apps after
updating their configuration.
You can find more details on how `symconf`'s matching scheme works in
[Matching](docs/reference/matching.md).
# Configuring
Before using, you must first set up your config directory to house your config files and
give `symconf` something to act on. See [Configuring](docs/reference/configuring.md) for
details.
Before using, you must first set up your config directory to house your config
files and give `symconf` something to act on. See
[Configuring](docs/reference/configuring.md) for details.
# Installation
The recommended way to install `symconf` is via `pipx`, which is particularly well-suited
for managing Python packages meant to be used as CLI programs. With `uv` on your system,
you can install with
The recommended way to install `symconf` is via `pipx`, which is particularly
well-suited for managing Python packages meant to be used as CLI programs. With
`uv` on your system, you can install with
```sh
uv tool install symconf
@ -74,56 +78,60 @@ You can also install via `pip`, or clone and install locally.
# Usage
- `-h --help`: print help message
- `-c --config-dir`: set the location of the `symconf` config directory
- `symconf config` is the subcommand used to match and set available config files for
registered applications
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to consider
all registered apps.
* `-m --mode`: preferred lightness mode/scheme, either `light`, `dark`, `any`, or
`none`.
* `-s --style`: style indicator, often the name of a color palette, capturing thematic
details in a config file to be matched. `any` or `none` are reserved keywords (see
below).
* `-T --template-vars`: additional groups to use when populating templates, in the form
`<group>=<value>`, where `<group>` is a template group with a folder
`$CONFIG_HOME/groups/<group>/` and `<value>` should correspond to a TOML file in this
folder (i.e., `<value>.toml`).
- `symconf generate` is a subcommand that can be used for batch generation of config
files. It accepts the same arguments as `symconf config`, but rather than selecting the
best match to be used for the system setting, all matching templates are generated.
There is one additional required argument:
* `-o --output-dir`: the directory under which generated config files should be written.
App-specific subdirectories are created to house config files for each provided app.
- `symconf config` is the subcommand used to match and set available config
files for registered applications
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
* `-m --mode`: preferred lightness mode/scheme, either `light`, `dark`,
`any`, or `none`.
* `-s --style`: style indicator, often the name of a color palette, capturing
thematic details in a config file to be matched. `any` or `none` are
reserved keywords (see below).
* `-T --template-vars`: additional groups to use when populating templates,
in the form `<group>=<value>`, where `<group>` is a template group with a
folder `$CONFIG_HOME/groups/<group>/` and `<value>` should correspond to a
TOML file in this folder (i.e., `<value>.toml`).
- `symconf generate` is a subcommand that can be used for batch generation of
config files. It accepts the same arguments as `symconf config`, but rather
than selecting the best match to be used for the system setting, all matching
templates are generated. There is one additional required argument:
* `-o --output-dir`: the directory under which generated config files should
be written. App-specific subdirectories are created to house config files
for each provided app.
- `symconf install`: runs install scripts for matching apps that specify one
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to consider
all registered apps.
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
- `symconf update`: runs update scripts for matching apps that specify one
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to consider
all registered apps.
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
The keywords `any` and `none` can be used when specifying `--mode`, `--style`, or as a
value in `--template-vars` (and we refer to each of these variables as _factors_ that help
determine a config match):
The keywords `any` and `none` can be used when specifying `--mode`, `--style`,
or as a value in `--template-vars` (and we refer to each of these variables as
_factors_ that help determine a config match):
- `any` will match config files with _any_ value for this factor, preferring config files
with a value `none`, indicating no dependence on the factor. This is the default value
when a factor is left unspecified.
- `none` will match `"none"` directly for a given factor (so no special behavior), but
used to indicate that a config file is independent of the factor. For instance,
- `any` will match config files with _any_ value for this factor, preferring
config files with a value `none`, indicating no dependence on the factor.
This is the default value when a factor is left unspecified.
- `none` will match `"none"` directly for a given factor (so no special
behavior), but used to indicate that a config file is independent of the
factor. For instance,
```sh
symconf config -m light -s none
```
will match config files that capture the notion of a light mode, but do not depend on or
provide further thematic components such as a color palette.
will match config files that capture the notion of a light mode, but do not
depend on or provide further thematic components such as a color palette.
## Examples
- Set a dark mode for all registered apps, matching any available style/palette component:
- Set a dark mode for all registered apps, matching any available style/palette
component:
```sh
symconf config -m dark
```
- Set `solarized` theme for `kitty` and match any available mode (light or dark):
- Set `solarized` theme for `kitty` and match any available mode (light or
dark):
```sh
symconf config -s solarized -a kitty
@ -133,16 +141,17 @@ determine a config match):
```sh
symconf config -m dark -s gruvbox -apps="kitty,nvim"
```
- Set a dark `gruvbox` theme for all apps, and attempt to match other template elements:
- Set a dark `gruvbox` theme for all apps, and attempt to match other template
elements:
```sh
symconf config -m dark -s gruvbox -T font=mono window=sharp
```
which would attempt to find and load key-value pairs in the files
`$CONFIG_HOME/groups/font/mono.toml` and `$CONFIG_HOME/groups/window/sharp.toml` to be
used as values when filling templatized config files.
`$CONFIG_HOME/groups/font/mono.toml` and
`$CONFIG_HOME/groups/window/sharp.toml` to be used as values when filling
templatized config files.
[1]: https://github.com/ologio/monobiome

View File

@ -11,10 +11,11 @@
:recursive:
symconf.config
symconf.template
symconf.matching
symconf.reader
symconf.runner
symconf.matching
symconf.template
symconf.util
```
## Auto-reference contents
@ -28,10 +29,10 @@ _autoref/symconf.rst
:maxdepth: 2
:caption: Contents
reference/configuring
reference/usage
reference/archive
reference/documentation/index
reference/configuring
reference/matching
reference/usage
```
```{include} ../README.md

View File

@ -1,80 +1,89 @@
# Archive
The `autoconf` project is an attempt at wrangling the complexity of configuring many
applications across one's Linux system. It provides a simple operational model for pulling
many application config files into one place, as well as generating/setting color schemes
across apps.
The `autoconf` project is an attempt at wrangling the complexity of configuring
many applications across one's Linux system. It provides a simple operational
model for pulling many application config files into one place, as well as
generating/setting color schemes across apps.
Quick terminology rundown for theme-related items:
- **Theme**: loose term referring generally to the overall aesthetic of a visual setting.
Ignoring stylistic changes (only applicable to some apps; example here might be a
a particular setting of the `waybar` layout), a theme is often just the wrapper term for
a choice of color _palette_ and _scheme_. For example, "tone4-light" could be a _theme_
setting for an app like `kitty`, referring to both a palette and scheme.
- **Palette**: a set of base colors used to style text or other aspects of an app's
displayed assets
- **Theme**: loose term referring generally to the overall aesthetic of a
visual setting. Ignoring stylistic changes (only applicable to some apps;
example here might be a a particular setting of the `waybar` layout), a theme
is often just the wrapper term for a choice of color _palette_ and _scheme_.
For example, "tone4-light" could be a _theme_ setting for an app like
`kitty`, referring to both a palette and scheme.
- **Palette**: a set of base colors used to style text or other aspects of an
app's displayed assets
- **Scheme**: an indication of lightness, typically either "light" or "dark.
As far as managing settings across apps, there are current two useful classifications
here:
As far as managing settings across apps, there are current two useful
classifications here:
1. **Inseparable from theme**: some apps (e.g., `sway`, `waybar`) have color scheme
components effectively built in to their canonical configuration file. This can make it
hard to set themes dynamically, as it would likely require some involved
matching/substitution rules. This is not a level of complexity I'm willing to embrace,
so we simply split the config files according to theme and/or scheme.
2. **Can load an external theme file**: some apps (e.g., `kitty`) have a clear mechanism
for loading themes. This typically implies some distinct color format, although usually
somewhat easy to generate (don't have to navigate non-color settings, for instance).
Such apps allow for an even less "invasive" config swapping process when setting a new
theme, as one can just swap out the external theme file.
1. **Inseparable from theme**: some apps (e.g., `sway`, `waybar`) have color
scheme components effectively built in to their canonical configuration
file. This can make it hard to set themes dynamically, as it would likely
require some involved matching/substitution rules. This is not a level of
complexity I'm willing to embrace, so we simply split the config files
according to theme and/or scheme.
2. **Can load an external theme file**: some apps (e.g., `kitty`) have a clear
mechanism for loading themes. This typically implies some distinct color
format, although usually somewhat easy to generate (don't have to navigate
non-color settings, for instance). Such apps allow for an even less
"invasive" config swapping process when setting a new theme, as one can just
swap out the external theme file.
To be clear on operation implications here: apps of type (1) must have _manually
maintained_ config variations according the desired themes. General theme settings must
follow the naming scheme `<app-name>-<palette>-<scheme>.<ext>`. For example, if I wanted to set
`sway` to a light variation (which, at the time of writing, would just entail changing a
single background color), I must have explicitly created a `sway-tone4-light.conf` file
that captures this setting. The canonical config file will then be symlinked to the
theme-specific file when the theme is set. (Note that the palette in this example is pretty much
irrelevant, but it needs to be present in order to match the overarching setting; here you
can just think of the format being `<app-name>-<theme>.<ext>`, where `tone4-light` is the
provided theme name.)
To be clear on operation implications here: apps of type (1) must have
_manually maintained_ config variations according the desired themes. General
theme settings must follow the naming scheme
`<app-name>-<palette>-<scheme>.<ext>`. For example, if I wanted to set `sway`
to a light variation (which, at the time of writing, would just entail changing
a single background color), I must have explicitly created a
`sway-tone4-light.conf` file that captures this setting. The canonical config
file will then be symlinked to the theme-specific file when the theme is set.
(Note that the palette in this example is pretty much irrelevant, but it needs
to be present in order to match the overarching setting; here you can just
think of the format being `<app-name>-<theme>.<ext>`, where `tone4-light` is
the provided theme name.)
For apps of type (2), the canonical config file can remain untouched so long as it refers
to a fixed, generic theme file. For example, with `kitty`, my config file can point to a
`current-theme.conf` file, which will be symlinked to a specific theme file here in
`autoconf` when a change is requested. This enables a couple of conveniences:
For apps of type (2), the canonical config file can remain untouched so long as
it refers to a fixed, generic theme file. For example, with `kitty`, my config
file can point to a `current-theme.conf` file, which will be symlinked to a
specific theme file here in `autoconf` when a change is requested. This enables
a couple of conveniences:
- The true config directory on disk remains unpolluted with theme variants.
- If the set theme is regenerated, there is no intervention necessary to propagate its
changes to the target app. The symlinked file itself will be updated when the theme
does, ensuring the latest theme version is always immediately available and pointed to
by the app.
- If the set theme is regenerated, there is no intervention necessary to
propagate its changes to the target app. The symlinked file itself will be
updated when the theme does, ensuring the latest theme version is always
immediately available and pointed to by the app.
Keep in mind that some apps may fall into some grey area here, allowing some external
customization but locking down other settings internally. In such instances, there's no
need to overcomplicate things; just stick to explicit config variants under the type (1)
umbrella. Type (2) only works for generated themes anyhow; even if the target app can load
an external theme, type (1) should be used if preset themes are fixed.
Keep in mind that some apps may fall into some grey area here, allowing some
external customization but locking down other settings internally. In such
instances, there's no need to overcomplicate things; just stick to explicit
config variants under the type (1) umbrella. Type (2) only works for generated
themes anyhow; even if the target app can load an external theme, type (1)
should be used if preset themes are fixed.
## Naming standards
To keep things simple, we use a few fixed naming standards for setting app config files
and their themed counterparts. The app registry requires each theme-eligible app to
provide a config directory (`config_dir`), containing some canonical config file
(`config_file`) and to serve as a place for theme-specific config variations. The
following naming schemes must be used in order for theme switching to behave
appropriately:
To keep things simple, we use a few fixed naming standards for setting app
config files and their themed counterparts. The app registry requires each
theme-eligible app to provide a config directory (`config_dir`), containing
some canonical config file (`config_file`) and to serve as a place for
theme-specific config variations. The following naming schemes must be used in
order for theme switching to behave appropriately:
- When setting a theme for a particular app, the following variables will be available:
- When setting a theme for a particular app, the following variables will be
available:
* `<app-name>`
* `<palette>`
* `<scheme>`
- For apps with `external_theme = False`, config variants must named as
`<app-name>-<palette>-<scheme>.<ext>`, where `<ext>` is the app's default config file
extension.
- For apps with `external_theme = True`, the file `<config-dir>/current-theme.conf` will
be used when symlinking the requested theme. The config file thus must point to this
file in order to change with the set theme.
`<app-name>-<palette>-<scheme>.<ext>`, where `<ext>` is the app's default
config file extension.
- For apps with `external_theme = True`, the file
`<config-dir>/current-theme.conf` will be used when symlinking the requested
theme. The config file thus must point to this file in order to change with
the set theme.
Additionally, the theme symlink will be created from the file
@ -87,147 +96,162 @@ appropriately:
## Directory structure
- `autoconf/`: main repo directory
* `config/`: app-specific configuration files. Each folder inside this directory is
app-specific, and the target of associated copy operations when a config sync is
performed. Nothing in this directory should pertain to any repo functionality; it
should only contain config files that originated elsewhere on the system.
* `themes/`: app-independent theme data files. Each folder in this directory should
correspond to a specific color palette and house any relevant color spec files
(currently likely be a `colors.json`). Also servers the output location for
generated theme files
* `<palette>/colors.json`: JSON formatted color key-value pairings for palette
colors. There's no standard here aside from the filename and format; downstream
app-specific TOML templates can be dependent on any key naming scheme within the
JSON.
+ `<palette>/apps/<app-name>/templates/`: houses the TOML maps for the color
palette `<palette>` under app `<app-name>`. Files `<fname>.toml` will be mapped to
`<fname>.conf` in the theme output folder (below), so ensure the naming
standards align with those outlined above.
+ `<palette>/apps/<app-name>/generated/`: output directory for generated scheme
variants. These are the symlink targets for dynamically set external themes.
* `app_registry.toml`: global application "registry" used by sync and theme-setting
scripts. This lets apps be dynamically added or removed from being eligible for
config-related operations.
* `config/`: app-specific configuration files. Each folder inside this
directory is app-specific, and the target of associated copy operations
when a config sync is performed. Nothing in this directory should pertain
to any repo functionality; it should only contain config files that
originated elsewhere on the system.
* `themes/`: app-independent theme data files. Each folder in this
directory should correspond to a specific color palette and house any
relevant color spec files (currently likely be a `colors.json`). Also
servers the output location for generated theme files
* `<palette>/colors.json`: JSON formatted color key-value pairings for
palette colors. There's no standard here aside from the filename and
format; downstream app-specific TOML templates can be dependent on
any key naming scheme within the JSON.
+ `<palette>/apps/<app-name>/templates/`: houses the TOML maps for the
color palette `<palette>` under app `<app-name>`. Files
`<fname>.toml` will be mapped to `<fname>.conf` in the theme output
folder (below), so ensure the naming standards align with those
outlined above.
+ `<palette>/apps/<app-name>/generated/`: output directory for
generated scheme variants. These are the symlink targets for
dynamically set external themes.
* `app_registry.toml`: global application "registry" used by sync and
theme-setting scripts. This lets apps be dynamically added or removed
from being eligible for config-related operations.
## Scripts
`set_theme.py`: sets a theme across select apps.
- Applies to specific app with `-a <app>` , or to all apps in the `app_registry.toml` with
`-a "*"`.
- Uses symlinks to set canonical config files to theme-based variations. Which files get
set depends on the _app type_ (see above), which really just boils down to whether
theming (1) can be specified with an external format, and (2) if it depends on
auto-generated theme files from within `autoconf`.
- Palette and scheme are specified as expected. They are used to infer proper paths
according to naming and structure standards.
- Real config files will never be overwritten. To begin setting themes with the script,
you must delete the canonical config file expected by the app (and specified in the app
registry) to allow the first symlink to be set. From there on out, symlinks will be
automatically flushed.
- A report will be provided on which apps were successfully set to the requested theme,
along with the file stems. A number of checks are in place for the existence of involved
files and directories. Overall, the risk of overwritting a real config file is low; we
only flush existing symlinks, and if the would-be target for the requested theme (be it
from an auto-generated theme file, or from a manually manage config variant) doesn't
exist, that app's config will be completed skipped. Essentially, everything must be in
- Applies to specific app with `-a <app>` , or to all apps in the
`app_registry.toml` with `-a "*"`.
- Uses symlinks to set canonical config files to theme-based variations. Which
files get set depends on the _app type_ (see above), which really just boils
down to whether theming (1) can be specified with an external format, and (2)
if it depends on auto-generated theme files from within `autoconf`.
- Palette and scheme are specified as expected. They are used to infer proper
paths according to naming and structure standards.
- Real config files will never be overwritten. To begin setting themes with the
script, you must delete the canonical config file expected by the app (and
specified in the app registry) to allow the first symlink to be set. From
there on out, symlinks will be automatically flushed.
- A report will be provided on which apps were successfully set to the
requested theme, along with the file stems. A number of checks are in place
for the existence of involved files and directories. Overall, the risk of
overwritting a real config file is low; we only flush existing symlinks, and
if the would-be target for the requested theme (be it from an auto-generated
theme file, or from a manually manage config variant) doesn't exist, that
app's config will be completed skipped. Essentially, everything must be in
perfect shape before the symlink trigger is officially pulled.
`gen_theme.py`: generates theme files for palettes by mapping their color
definitions through app-specific templates. These templates specific how to
relate an app's theme variables to the color names provided by the template.
`gen_theme.py`: generates theme files for palettes by mapping their color definitions
through app-specific templates. These templates specific how to relate an app's theme
variables to the color names provided by the template.
- An app and palette are the two required parameters. If no template or output
paths are provided, they will be inferred according to the theme path
standards seen above.
- The `--template` argument can be a directory or a file, depending on what
theme files you'd like to render.
- The `--output` path, if specified, must be a directory. Generated theme files
take on a name with the same stem as their source template, but using the
`.conf` extension.
- The TOML templates should make config variable names to JSON dot-notation
accessors. If color definitions are nested, the dot notation should be
properly expanded by the script when mapping the colors to keyword values.
- There are a number of checks for existing paths, even those inferred (e.g.,
template and output) from the palette and app. If the appropriate setup
hasn't been followed, the script will fail. Make sure the `theme` folder in
question and it's nested `app` directory are correctly setup before running
the script. (Perhaps down the line there are some easy auto-setup steps to
take here, but I'm not making that jump now.)
- TODO: open up different app "writers," or make it easy to extend output
syntax based on the app in question. This would like be as simple as mapping
app names to line-generating functions, which accept the keyword and color
(among other items). This can be fleshed out as needed.
- An app and palette are the two required parameters. If no template or output paths are
provided, they will be inferred according to the theme path standards seen above.
- The `--template` argument can be a directory or a file, depending on what theme files
you'd like to render.
- The `--output` path, if specified, must be a directory. Generated theme files take on
a name with the same stem as their source template, but using the `.conf` extension.
- The TOML templates should make config variable names to JSON dot-notation accessors. If
color definitions are nested, the dot notation should be properly expanded by the script
when mapping the colors to keyword values.
- There are a number of checks for existing paths, even those inferred (e.g., template and
output) from the palette and app. If the appropriate setup hasn't been followed, the
script will fail. Make sure the `theme` folder in question and it's nested `app`
directory are correctly setup before running the script. (Perhaps down the line there
are some easy auto-setup steps to take here, but I'm not making that jump now.)
- TODO: open up different app "writers," or make it easy to extend output syntax based on
the app in question. This would like be as simple as mapping app names to
line-generating functions, which accept the keyword and color (among other items). This
can be fleshed out as needed.
`sync.sh`: copies relevant configuration files from local paths into the `autoconf`
subpath. Markdown files in the docs directory then reference the local copies of these
files, meaning the documentation updates dynamically when the configuration files do. That
is, the (possibly extracted) config snippets will change with the current state of my
system config without any manual intervention of the documentation files.
`sync.sh`: copies relevant configuration files from local paths into the
`autoconf` subpath. Markdown files in the docs directory then reference the
local copies of these files, meaning the documentation updates dynamically when
the configuration files do. That is, the (possibly extracted) config snippets
will change with the current state of my system config without any manual
intervention of the documentation files.
### Specific theme-setting example
To make clear how the theme setting script works on my system, the following breaks down
exactly what steps are taken to exert as much scheme control as possible. Everything at this
point is wrapped up in a single `make set-<palette>-<scheme>` call; suppose we're
currently running the dark scheme (see first image) and I run `make set-tone4-light`:
To make clear how the theme setting script works on my system, the following
breaks down exactly what steps are taken to exert as much scheme control as
possible. Everything at this point is wrapped up in a single `make
set-<palette>-<scheme>` call; suppose we're currently running the dark scheme
(see first image) and I run `make set-tone4-light`:
![
Starting point; have a GTK app (GNOME files), `kitty`, and Firefox (with the
system-dependent default theme set). In Firefox, I have open `localsys` with its
scheme-mode to set to "auto," which should reflect the theme setting picked up by the
browser (and note the white tab icon).
system-dependent default theme set). In Firefox, I have open `localsys` with
its scheme-mode to set to "auto," which should reflect the theme setting
picked up by the browser (and note the white tab icon).
](_static/set-theme-1.png)
_(Starting point; have a GTK app (GNOME files), `kitty`, and Firefox (with the
system-dependent default theme set). In Firefox, I have open `localsys` with its
scheme-mode to set to "auto," which should reflect the theme setting picked up by the
browser (and note the white tab icon).)_
system-dependent default theme set). In Firefox, I have open `localsys` with
its scheme-mode to set to "auto," which should reflect the theme setting picked
up by the browser (and note the white tab icon).)_
1. `set_theme.py` is invoked. Global settings are applied first, based on my OS (`Linux`),
which calls
1. `set_theme.py` is invoked. Global settings are applied first, based on my OS
(`Linux`), which calls
```
gsettings set org.gnome.desktop.interface color-scheme 'prefer-light'
```
controlling settings for GTK apps and other `desktop-portal`-aware programs. This
yields the following:
controlling settings for GTK apps and other `desktop-portal`-aware programs.
This yields the following:
![Portal-aware apps changed, config apps not yet set](_static/set-theme-2.png)
_(Portal-aware apps changed, config apps not yet set. Scheme-aware sites are updated
without page refresh.)_
2. Specific application styles are set. For now the list is small, including `kitty`,
`waybar`, and `sway`. `kitty` is the only type (2) application here, whereas the other
two are type (1).
_(Portal-aware apps changed, config apps not yet set. Scheme-aware sites are
updated without page refresh.)_
2. Specific application styles are set. For now the list is small, including
`kitty`, `waybar`, and `sway`. `kitty` is the only type (2) application
here, whereas the other two are type (1).
a. For the type (1) apps, the canonical config files as specified in the app registry
are symlinked to their light variants. For `sway`, this is `~/.config/sway/config`,
and if we look at the `file`:
a. For the type (1) apps, the canonical config files as specified in the app
registry are symlinked to their light variants. For `sway`, this is
`~/.config/sway/config`, and if we look at the `file`:
```sh
.config/sway/config: symbolic link to ~/.config/sway/sway-tone4-light
```
b. For the type (2) apps, just the `current-theme.conf` file is symlinked to the
relevant palette-scheme file. `kitty` is such an app, with a supported theme file
for `tone4`, and those files have been auto-generated via `gen_theme.py`. Looking at
this file under the `kitty` config directory:
b. For the type (2) apps, just the `current-theme.conf` file is symlinked to
the relevant palette-scheme file. `kitty` is such an app, with a
supported theme file for `tone4`, and those files have been
auto-generated via `gen_theme.py`. Looking at this file under the `kitty`
config directory:
```sh
.config/kitty/current-theme.conf: symbolic link to ~/Documents/projects/autoconf/autoconf/themes/tone4/apps/kitty/generated/light.conf
.config/kitty/current-theme.conf: symbolic link to
~/Documents/projects/autoconf/autoconf/themes/tone4/apps/kitty/generated/light.conf
```
The `kitty.conf` file isn't changed, as all palette-related items are specified in
the theme file. (Note that the general notion of a "theme" could include changes to
other stylistic aspects, like the font family; this would likely require some hybrid
type 1-2 approach not yet implemented).
3. Live application instances are reloaded, according to the registered `refresh_cmd`s.
Here the apps with style/config files set in step (2) are reloaded to reflect those
changes. Again, in this example, this is `kitty`, `sway`, and the `waybar`.
The `kitty.conf` file isn't changed, as all palette-related items are
specified in the theme file. (Note that the general notion of a "theme"
could include changes to other stylistic aspects, like the font family;
this would likely require some hybrid type 1-2 approach not yet
implemented).
3. Live application instances are reloaded, according to the registered
`refresh_cmd`s. Here the apps with style/config files set in step (2) are
reloaded to reflect those changes. Again, in this example, this is `kitty`,
`sway`, and the `waybar`.
![Final light setting: portal-dependent apps _and_ config-based apps changed](_static/set-theme-3.png)
![
Final light setting: portal-dependent apps _and_ config-based apps changed
](_static/set-theme-3.png)
_(Final light setting: portal-dependent apps _and_ config-based apps changed)_
4. `set_theme.py` provides a report for the actions taken; in this case, the following was
printed:
_(Final light setting: portal-dependent apps _and_ config-based apps
changed)_
4. `set_theme.py` provides a report for the actions taken; in this case, the
following was printed:
![`set_theme.py` output](_static/set-theme-4.png)
_(`set_theme.py` output)_

View File

@ -1,61 +1,64 @@
# Configuring
`symconf` operates on a central directory that houses all of the config files you may wish
to apply. The default location for this directory is your `$XDG_CONFIG_HOME` (e.g.,
`~/.config/symconf/`), but it can be any location on your system so long as it's specified
(see more in Usage).
`symconf` operates on a central directory that houses all of the config files
you may wish to apply. The default location for this directory is your
`$XDG_CONFIG_HOME` (e.g., `~/.config/symconf/`), but it can be any location on
your system so long as it's specified (see more in Usage).
`symconf` expects you to create two top-level components in your config directory: an
`apps/` directory and an `app_registry.toml` file.
`symconf` expects you to create two top-level components in your config
directory: an `apps/` directory and an `app_registry.toml` file.
**High-level view**:
- `symconf` operates on a single directory that houses all your config files
- Config files in this directory must be placed under an `apps/<app-name>/` folder to be
associated with the app `<app-name>`
- For apps to be visible, you need an `app_registry.toml` file that tells `symconf` where
to symlink your files in `apps/`
- Config files in this directory must be placed under an `apps/<app-name>/`
folder to be associated with the app `<app-name>`
- For apps to be visible, you need an `app_registry.toml` file that tells
`symconf` where to symlink your files in `apps/`
## Apps directory
An `apps/` directory should be created in your config home, with a subdirectory
`apps/<app-name>/` for each app with config files that you'd like to be visible to
`symconf`. Note that simply populating an app's config folder here will do nothing on its
own; the app must also have been registered (discussed in item #2) in order for these
files to be used when `symconf` is invoked. (This just means you can populate your `apps/`
folder safely without expecting any default behavior. More often than not you'll be
expected to tell `symconf` exactly where your config files should end up, meaning you know
exactly what it's doing.)
`apps/<app-name>/` for each app with config files that you'd like to be visible
to `symconf`. Note that simply populating an app's config folder here will do
nothing on its own; the app must also have been registered (discussed in item
#2) in order for these files to be used when `symconf` is invoked. (This just
means you can populate your `apps/` folder safely without expecting any default
behavior. More often than not you'll be expected to tell `symconf` exactly
where your config files should end up, meaning you know exactly what it's
doing.)
### User config
Inside your app-specific subdirectory, your managed config files should be placed in a
`user/` subdirectory (distinguishing them from those generated by templates; see more
in Themes). Your config files themselves are then expected to follow a specific naming
scheme:
Inside your app-specific subdirectory, your managed config files should be
placed in a `user/` subdirectory (distinguishing them from those generated by
templates; see more in Themes). Your config files themselves are then expected
to follow a specific naming scheme:
```sh
<palette>-<scheme>.<config-name>
```
This ties your config file to a particular theme setting as needed, and `symconf` will
apply it if it matches the theme setting you provide when invoked. The specific values are
as follows:
This ties your config file to a particular theme setting as needed, and
`symconf` will apply it if it matches the theme setting you provide when
invoked. The specific values are as follows:
- `scheme`: can be `light`, `dark`, or `none`. Indicates whether the config file should
be applied specifically when requesting a light or dark mode. Use `none` to indicate
that the config file does not have settings specific to a light/dark mode.
- `palette`: a "palette name" of your choosing, or `none`. The palette name you use
here may refer specifically to a color palette used by the config file, but can be
used generally to indicate any particular group of config settings (e.g., fonts,
transparency, etc). Use `none` to indicate that the file does not correspond to any
particular style group.
- `config-name`: the _name_ of the config file. This should correspond to _same path
name_ that is expected by the app being configured. For example, if your app expects a
config file at `a/b/c/d.conf`, "`d.conf`" is the path name.
- `scheme`: can be `light`, `dark`, or `none`. Indicates whether the config
file should be applied specifically when requesting a light or dark mode. Use
`none` to indicate that the config file does not have settings specific to a
light/dark mode.
- `palette`: a "palette name" of your choosing, or `none`. The palette name you
use here may refer specifically to a color palette used by the config file,
but can be used generally to indicate any particular group of config settings
(e.g., fonts, transparency, etc). Use `none` to indicate that the file does
not correspond to any particular style group.
- `config-name`: the _name_ of the config file. This should correspond to _same
path name_ that is expected by the app being configured. For example, if your
app expects a config file at `a/b/c/d.conf`, "`d.conf`" is the path name.
When invoking `symconf` with specific scheme and palette settings (see more in Usage),
appropriate config files can be matched based on how you've named your files.
When invoking `symconf` with specific scheme and palette settings (see more in
Usage), appropriate config files can be matched based on how you've named your
files.
For example, suppose I want to set up a simple light/dark mode switch for the `kitty`
terminal emulator. The following tree demonstrates a valid setup:
For example, suppose I want to set up a simple light/dark mode switch for the
`kitty` terminal emulator. The following tree demonstrates a valid setup:
```sh
<config-home>
@ -66,30 +69,31 @@ terminal emulator. The following tree demonstrates a valid setup:
└── none-dark.kitty.conf
```
where `none-light.kitty.conf` may set a light background and `none-dark.kitty.conf` a dark
one. `none` is used for the `<palette>` part of the name to indicate the configuration does
not pertain to any specific palette and can be matched even if one is not provided. With
an appropriate `app_regsitry.toml` file (see below), invoking
where `none-light.kitty.conf` may set a light background and
`none-dark.kitty.conf` a dark one. `none` is used for the `<palette>` part of
the name to indicate the configuration does not pertain to any specific palette
and can be matched even if one is not provided. With an appropriate
`app_regsitry.toml` file (see below), invoking
```sh
symconf --theme=light --apps=kitty
```
would symlink `$XDG_CONFIG_HOME/symconf/apps/kitty/user/none-light.kitty.conf` to
`~/.config/kitty/kitty.conf`.
would symlink `$XDG_CONFIG_HOME/symconf/apps/kitty/user/none-light.kitty.conf`
to `~/.config/kitty/kitty.conf`.
### Templatized config
Note the potential inconvenience in needing to manage two separate config files in the
above example, very likely with all but one line of difference. Templating enables
populating config template files dynamically with theme-specific variables of your
choosing.
Note the potential inconvenience in needing to manage two separate config files
in the above example, very likely with all but one line of difference.
Templating enables populating config template files dynamically with
theme-specific variables of your choosing.
### Reload scripts
After symlinking a new set of config files, it is often necessary to reload the system or
relevant apps in order for the new config settings to apply. Within an app's subdirectory,
a `call/` folder can be created to hold scripts that should apply based on certain schemes
or palettes (matching them in the same way as config files). For example,
After symlinking a new set of config files, it is often necessary to reload the
system or relevant apps in order for the new config settings to apply. Within
an app's subdirectory, a `call/` folder can be created to hold scripts that
should apply based on certain schemes or palettes (matching them in the same
way as config files). For example,
```sh
<config-home>
@ -99,22 +103,22 @@ or palettes (matching them in the same way as config files). For example,
└── none-none.sh
```
`none-none.sh` might simply contain `kill -s USR1 $(pgrep kitty)`, which is a way to tell
all running `kitty` instances to reload their config settings. Again, following the naming
scheme for config files, a script named `none-none.sh` will apply under any scheme or
palette specification. Thus, in our light/dark mode switch example, invoking `symconf
--theme=light --apps=kitty` would:
`none-none.sh` might simply contain `kill -s USR1 $(pgrep kitty)`, which is a
way to tell all running `kitty` instances to reload their config settings.
Again, following the naming scheme for config files, a script named
`none-none.sh` will apply under any scheme or palette specification. Thus, in
our light/dark mode switch example, invoking `symconf --theme=light
--apps=kitty` would:
1. Search and match the config name `none-light.kitty.conf` and symlink it to
`~/.config/kitty/kitty.conf`.
2. Search and match `none-none.sh` and execute it, applying the new light mode settings to
all running `kitty` instances.
2. Search and match `none-none.sh` and execute it, applying the new light mode
settings to all running `kitty` instances.
## App registry
An `app_registry.toml` file, used to specify the target locations for app-specific
config files. To "register" an app, you simply need to add the following text block to
the `app_registry.toml` file:
An `app_registry.toml` file, used to specify the target locations for
app-specific config files. To "register" an app, you simply need to add the
following text block to the `app_registry.toml` file:
```toml
[app.<app-name>]
@ -128,22 +132,22 @@ config_map = {
}
```
(Note that text in angle brackets refers to values that should be replaced.) This tells
`symconf` how it should handle each app's config files. The `<app-name>` (e.g.,
`kitty`) should correspond to a subdirectory under `apps/` (e.g., `apps/kitty/`) that
holds your config files for that app. As shown, you then need to supply either of the
following options:
(Note that text in angle brackets refers to values that should be replaced.)
This tells `symconf` how it should handle each app's config files. The
`<app-name>` (e.g., `kitty`) should correspond to a subdirectory under `apps/`
(e.g., `apps/kitty/`) that holds your config files for that app. As shown, you
then need to supply either of the following options:
- `config_dir`: specifies a single directory where all of the app's matching config
files should be symlinked. In the `kitty` example, this might be `~/.config/kitty`.
This is the simplest and most common option provided most apps expect all of their
config files to be in a single directory.
- `config_map`: a dictionary mapping config file _path names_ to the _exact paths_ that
should be created during the symlink process. This is typically needed when an app
has many config files that need to be set in several disparate locations across your
system. In the `kitty` example, although not necessary (and in general you should
prefer to set `config_dir` when applicable), we could have the following
`config_map`:
- `config_dir`: specifies a single directory where all of the app's matching
config files should be symlinked. In the `kitty` example, this might be
`~/.config/kitty`. This is the simplest and most common option provided most
apps expect all of their config files to be in a single directory.
- `config_map`: a dictionary mapping config file _path names_ to the _exact
paths_ that should be created during the symlink process. This is typically
needed when an app has many config files that need to be set in several
disparate locations across your system. In the `kitty` example, although not
necessary (and in general you should prefer to set `config_dir` when
applicable), we could have the following `config_map`:
```toml
[app.kitty]
@ -152,8 +156,9 @@ following options:
}
```
This tells `symconf` to symlink the exact location `~/.config/kitty/kitty.conf` to
the matching `kitty.conf` under the `apps/kitty` directory.
This tells `symconf` to symlink the exact location
`~/.config/kitty/kitty.conf` to the matching `kitty.conf` under the
`apps/kitty` directory.
## Directory structure
In total, the structure of your base config directory can look as follows:

View File

@ -1,6 +1,170 @@
# Usage
```{toctree}
:hidden:
```sh
usage: symconf [-h] [-c CONFIG_DIR] [-v] {config,generate,install,update} ...
Manage application configuration with symlinks.
options:
-h, --help show this help message and exit
-c CONFIG_DIR, --config-dir CONFIG_DIR
Path to config directory
-v, --version Print symconf version
subcommand actions:
{config,generate,install,update}
```
Additional argument details:
- `-h --help`: print help message
- `-c --config-dir`: the location of the `symconf` config directory. Assumes
`$XDG_CONFIG_HOME` (e.g., `~/.config/symconf/`) by default.
## `config` subcommand
The config subcommand applies symlinks for registered application routes that
meet specified constraints.
```sh
usage: symconf config [-h] [-s STYLE] [-m MODE] [-a APPS] [-T TEMPLATE_VARS [TEMPLATE_VARS ...]]
Set config files for registered applications.
options:
-h, --help show this help message and exit
-s STYLE, --style STYLE
Style indicator (often a color palette) capturing thematic details in a config file
-m MODE, --mode MODE Preferred lightness mode/scheme, either "light," "dark," "any," or "none."
-a APPS, --apps APPS Application target for theme. App must be present in the registry. Use "*" to apply to all registered apps
-T TEMPLATE_VARS [TEMPLATE_VARS ...], --template-vars TEMPLATE_VARS [TEMPLATE_VARS ...]
Groups to use when populating templates, in the form group=value
```
- `symconf config` is the subcommand used to match and set available config
files for registered applications
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
* `-m --mode`: preferred lightness mode/scheme, either `light`, `dark`,
`any`, or `none`.
* `-s --style`: style indicator, often the name of a color palette, capturing
thematic details in a config file to be matched. `any` or `none` are
reserved keywords (see below).
* `-T --template-vars`: additional groups to use when populating templates,
in the form `<group>=<value>`, where `<group>` is a template group with a
folder `$CONFIG_HOME/groups/<group>/` and `<value>` should correspond to a
TOML file in this folder (i.e., `<value>.toml`).
## `generate` subcommand
The generate subcommand fills in templates with theme values matched under
provided constraints,
```sh
usage: symconf generate [-h] -o OUTPUT_DIR [-s STYLE] [-m MODE] [-a APPS] [-T TEMPLATE_VARS [TEMPLATE_VARS ...]]
Generate all template config files for specified apps
options:
-h, --help show this help message and exit
-o OUTPUT_DIR, --output-dir OUTPUT_DIR
Path to write generated template files
-s STYLE, --style STYLE
Style indicator (often a color palette) capturing thematic details in a config file
-m MODE, --mode MODE Preferred lightness mode/scheme, either "light," "dark," "any," or "none."
-a APPS, --apps APPS Application target for theme. App must be present in the registry. Use "*" to apply to all registered apps
-T TEMPLATE_VARS [TEMPLATE_VARS ...], --template-vars TEMPLATE_VARS [TEMPLATE_VARS ...]
Groups to use when populating templates, in the form group=value
```
- `symconf generate` is a subcommand that can be used for batch generation of
config files. It accepts the same arguments as `symconf config`, but rather
than selecting the best match to be used for the system setting, all matching
templates are generated. There is one additional required argument:
* `-o --output-dir`: the directory under which generated config files should
be written. App-specific subdirectories are created to house config files
for each provided app.
## `install` subcommand
The install subcommand runs the `install.sh` scripts for registered apps.
```sh
usage: symconf install [-h] [-a APPS]
Run install scripts for registered applications.
options:
-h, --help show this help message and exit
-a APPS, --apps APPS Application target for theme. App must be present in the registry. Use "*" to apply to all registered apps
```
- `symconf install`: runs install scripts for matching apps
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
## `update` subcommand
The update subcommand runs the `update.sh` scripts for registered apps. This
action expects the install process for each matched app to have been run
beforehand.
```sh
usage: symconf update [-h] [-a APPS]
Run update scripts for registered applications.
options:
-h, --help show this help message and exit
-a APPS, --apps APPS Application target for theme. App must be present in the registry. Use "*" to apply to all registered apps
```
- `symconf update`: runs update scripts for matching apps that specify one
* `-a --apps`: comma-separate list of registered apps, or `"*"` (default) to
consider all registered apps.
## Matching factors
The keywords `any` and `none` can be used when specifying `--mode`, `--style`,
or as a value in `--template-vars` (and we refer to each of these variables as
_factors_ that help determine a config match):
- `any` will match config files with _any_ value for this factor, preferring
config files with a value `none`, indicating no dependence on the factor.
This is the default value when a factor is left unspecified.
- `none` will match `"none"` directly for a given factor (so no special
behavior), but used to indicate that a config file is independent of the
factor. For instance,
```sh
symconf config -m light -s none
```
will match config files that capture the notion of a light mode, but do not
depend on or provide further thematic components such as a color palette.
## Examples
- Set a dark mode for all registered apps, matching any available style/palette
component:
```sh
symconf config -m dark
```
- Set `solarized` theme for `kitty` and match any available mode (light or
dark):
```sh
symconf config -s solarized -a kitty
```
- Set a dark `gruvbox` theme for multiple apps (but not all):
```sh
symconf config -m dark -s gruvbox -apps="kitty,nvim"
```
- Set a dark `gruvbox` theme for all apps, and attempt to match other template
elements:
```sh
symconf config -m dark -s gruvbox -T font=mono window=sharp
```
which would attempt to find and load key-value pairs in the files
`$CONFIG_HOME/groups/font/mono.toml` and
`$CONFIG_HOME/groups/window/sharp.toml` to be used as values when filling
templatized config files.

View File

@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "symconf"
version = "0.8.2"
version = "0.8.3"
description = "Local app configuration manager"
requires-python = ">=3.12"
authors = [

2
uv.lock generated
View File

@ -529,7 +529,7 @@ wheels = [
[[package]]
name = "symconf"
version = "0.8.2"
version = "0.8.3"
source = { editable = "." }
dependencies = [
{ name = "colorama" },