Dotfile Templater

Rust Rust
Regex Regex

Project Summary

  • Built a lightweight templating tool in Rust for modifying configuration files in-place.
  • Implements a minimal inline templating language embedded within comments.
  • Designed for dotfile theming and automation, enabling dynamic config updates without separate template files.

Technical Challenges

  • Designing a minimal templating language that works within existing config syntax.
  • Parsing inline comment-based instructions without interfering with file semantics.
  • Ensuring safe, deterministic replacements using a fixed-length constraint.
  • Managing multiple sequential transformations on a single line.
  • Supporting flexible file formats with different comment styles.

Core Design

  • Inline templating system:
    • Template logic is written inside comments on the same line as the target config.
    • Avoids separate template files, keeping configuration self-contained.
  • Marker-Based Parsing:
    • Each file defines a marker_char (e.g: //, ;, %).
    • Template code is detected when the marker is repeated marker_repetition_num times.
  • Pattern-Based Replacement:
    • Uses Regex patterns to locate target text.
    • Replaces matched segments with values defined in config (keyword).

Safety Model

  • Enforces fixed-length replacements:
    • Replacement text must match the length of the original.
    • Prevents unintended shifts in file structure or formatting.
  • Deterministic matching:
    • Each function operates on a specific match index.
    • Multiple functions on a line act on successive matches (nth match based on their order).

Templating System

  • Keyword-driven replacement:
    • A keyword maps to a value defined in the TOML config.
    • Used to replace matched patterns in config files.
  • Execution Model:
    • Functions are parsed left-to-right on a line.
    • Each function targets a specific match within the line.

Supported Functions

Function Arguments Description
@replace keyword pattern Replace first text which matches pattern with the keyword.
@replace‑col keyword Replace first text which matches #[A‑Za‑z\d]{6} with the keyword.
@replace‑pattern pattern_1 keyword pattern_2 Find first text which matches pattern_1, then find first match within this match based on pattern_2 and replace that with the keyword.
@replace‑pattern‑col keyword pattern_2 Find first text which matches #[A‑Za‑z\d]{6}, then find first match within this match based on pattern_2 and replace that with the keyword.

Configuration System

  • Uses TOML for configuration.
  • Located at $XDG_CONFIG_HOME/dotfile-templater/config.toml.
  • Defines:
    • Active theme.
    • Marker behaviour (marker_char, marker_repetition_num).
    • Target files and their parsing rules.
  • File configuration:
    • Supports relative paths (from .config/) and absolute paths.
    • Each file must define its own marker_char.

Example Config

theme = "purple-night"
marker_repetition_num = 3
files = [
  {file = "eww/eww.scss", marker_char = "//"},
  {file = "eww/bar/bar.yuck", marker_char = ";"},
  {file = "wofi/style.css", marker_char = ";"},
  {file = "hypr/hyprland.conf", marker_char = "%"},
]

[[themes]]
name = "purple-night"

primary_col = "#9549FF"
secondary_col = "#FF4958"
tertiary_col = "#B3FF49"
quaternary_col = "#49FFF0"

bg_col = "#1A1B26"
bg_col_light = "#24283B"
fg_col = "#A9B1D6"

[[themes]]
name = "blue-banana"

primary_col = "#48FFD1"
secondary_col = "#4876FF"
tertiary_col = "#FF4876"
quaternary_col = "#FFD148"

bg_col = "#0A0A40"
bg_col_light = "#11116C"
fg_col = "#9999F8"

Theme System

  • Themes are defined as named sections in the config.
  • Each theme:
    • Must include a name.
    • Can define arbitrary variables (e.g: colours, strings).
  • Enables:
    • Centralised value management.
    • Easy switching between configurations (e.g: colour schemes).

Example Usage

test = This will not be configured % Even if there are comments

$primary: rgb(9549FF); %%% @replace-pattern('rgb\([A-Za-z\d]{6}\)', primary_col, '[A-Za-z\d]{6}')
$secondary: #FF4958; %%% @replace-pattern-col(secondary_col, '[A-Za-z\d]{6}')
$tertiary: #B3FF49; #123456; %%% @replace-col(fg_col) @replace-col(bg_col)
$quaternary: #49FFF0; %%% @replace-col(quaternary_col)

$background: #1A1B26; %%% @replace-col(bg_col)
$background-lighter: #24283B; %%% @replace-col(bg_col_light)
$foreground: #A9B1D6; %%% @replace-col(fg_col)

Extensibility

  • New template functions can be added without changing file format.
  • Supports:
    • Arbitrary regex-based transformations.
    • Custom themes with user-defined variables.
    • Multiple file types with different comment syntaxes.
  • Suitable for:
    • Dotfile management.
    • Theming systems.
    • Automated config generation.

Current Limitations

  • Fixed-length replacement constraint limits flexibility.
  • Regex-based approach may be brittle for complex syntax.
  • No validation for malformed template expressions.
  • Limited error feedback for failed matches or replacements.

Phone

I am not comfortable putting my personal phone number on this public site, please use my email, or contact via LinkedIn.

Address

Newcastle Upon Tyne, United Kingdom