From d7bd784d23d9543740e2428bd7f65fb85283d26f Mon Sep 17 00:00:00 2001 From: danix Date: Thu, 11 Jun 2026 10:48:18 +0200 Subject: docs: add CLAUDE.md and README.md Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 82 ++++++++++++++++++++++++++ README.md | 195 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) create mode 100644 CLAUDE.md create mode 100644 README.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..2aa4393 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,82 @@ +# CLAUDE.md + +Guidance for AI agents working in this repo. + +## What this is + +`wallp` — a single bash script that sets and restores wallpapers on a fixed +two-screen wayland (sway/hyprland) setup. It merges two older scripts +(`multiwal.sh` interactive setter, `qar-lastwall.sh` restorer). Uses `swaybg` to +paint wallpapers, `qarma` for GUI selection, `wal` (pywal) for the color theme. + +Logical screens are `H` (horizontal) and `V` (vertical), mapped to physical +outputs via config (`OUTPUT_H`/`OUTPUT_V`). + +## Layout + +- `wallp` — the whole program (one bash file, ~320 lines). +- `tests/wallp.bats` — bats test suite (the only tests). +- `wallp.conf.example` — sample config. +- `docs/superpowers/specs/` — design spec. +- `docs/superpowers/plans/` — implementation plan. + +## Build / test + +No build step. Run the suite: + +```bash +bats tests/wallp.bats +``` + +Requires `bats` (1.5.0 known good). Tests run hermetically: `setup()` creates a +temp `$HOME`, stubs `swaybg`/`wal`/`qarma`/`notify-send`/`pkill`/`kill` on `PATH` +(each logs its call to `$HOME/calls.log` and exits 0), then `source`s `wallp`. +The sourcing guard at EOF (`[ "${BASH_SOURCE[0]}" = "$0" ]`) keeps `main` from +running on source — **do not remove it.** + +Syntax check: `bash -n wallp`. + +## Development rules + +- **TDD.** Every change: write the failing bats test first, confirm it fails, + implement, confirm green, commit. Functions go ABOVE `main()`. +- **Test conventions:** use `run fn` when asserting on `$status`/`$output`; call + the function directly when asserting on globals (`CONF_*`, `SET_*`) or + filesystem side effects, since `run` executes in a subshell. +- **Pure logic is unit-testable** (conf parse, arg parse, tilde expansion, output + mapping, theme resolution). Side-effecting bits (`swaybg`, `wal`, `qarma`) are + isolated in thin functions and exercised via the PATH stubs. +- `set -u` is on. Empty-array expansion `"${set_args[@]}"` is safe on bash ≥ 4.4 + (this host is fine). Guard env vars with `${VAR:-}`. +- Quote all paths (wallpaper filenames may contain spaces). + +## Critical gotchas + +- **Install is a COPY, not a symlink.** The live binary is `~/bin/wallp`, copied + from this repo. After editing repo `wallp`, re-copy: + `cp /home/danix/Programming/GIT/wallp/wallp ~/bin/wallp` + Otherwise hypr autostart/keybind run the stale version. +- **qarma `--list` needs `--radiolist --print-column=2`.** A plain `--list` + prints nothing on selection (bug that shipped once). `qarma_select` depends on + these flags; a regression test guards it. +- **Selective kill.** `apply_output` kills only the changed output's swaybg PID + (tracked in `~/.cache/wallp/{H,V}.pid`). Updating one screen must never blank + the other — there's a test for this; keep it green. +- **`load_conf` return codes:** 0 ok, 1 invalid (missing required key), 10 + bootstrapped (template just written → caller exits 0, no wallpaper change). +- **Persistence is wallp-owned**, under `~/.config/wallp/` (`wall_h`, `wall_v`, + `theme`). `~/.cache/wal/wpaper` symlink is still maintained (rofi reads it). + `~/bin/wal.sh` was trimmed to dunst+kitty glue only; it no longer touches + wallpaper pointers. + +## External integration (outside this repo) + +- `~/bin/wal.sh` — wal's `-o` hook; dunst + kitty theming only now. +- `~/.config/hypr/sections/autostart.lua` → `wallp --restore`. +- `~/.config/hypr/sections/keybindings.lua` → `wallp --set` (mainMod+Return). +- Old `~/bin/multiwal.sh` + `qar-lastwall.sh` kept as fallback, unreferenced. + +## Commits + +Pre-commit gitleaks hook prints ASCII art — normal; the commit succeeds when it +reports "no leaks found". diff --git a/README.md b/README.md new file mode 100644 index 0000000..d66216f --- /dev/null +++ b/README.md @@ -0,0 +1,195 @@ +# wallp + +A single-script wallpaper manager for a two-screen Wayland (sway / Hyprland) +setup. Sets and restores wallpapers per screen, drives a [pywal](https://github.com/dylanaraps/pywal) +color theme, and remembers what you had across reboots. + +It replaces two older scripts — an interactive setter and a session restorer — +with one flag-driven program. + +## Features + +- **Two independent screens** — a horizontal (`H`) and a vertical (`V`) output, + mapped to physical connectors in config. +- **Partial updates** — change one screen without disturbing the other. Each + screen's `swaybg` process is tracked by PID and only the changed one is + restarted (no full-screen blank flash). +- **GUI or CLI** — pick wallpapers through a [qarma](https://github.com/luebking/qarma) + dialog, or pass file paths as arguments for scripted/headless use. +- **Session restore** — re-applies the last wallpapers (and last theme) at login, + falling back to configured defaults on first run. +- **Theme persistence** — the last theme sticks until you change it; `--restore` + brings it back, not the config default. +- **Self-bootstrapping config** — first run writes a template config and tells + you to fill it in, without touching your wallpapers. + +## Requirements + +| Tool | Required | Purpose | +|---------------|---------------------|--------------------------------------| +| `bash` | yes (≥ 4.4) | the script itself | +| `swaybg` | yes | paints the wallpaper on each output | +| `wal` (pywal) | yes | generates/applies the color theme | +| `qarma` | only for GUI `--set`| screen-choice menu + file picker | +| `notify-send` | optional | desktop notification on theme change | +| `bats` | dev only | running the test suite | + +`wallp` checks for the required binaries at startup and exits with a clear +message if one is missing. + +## Install + +`wallp` is a standalone script — put it somewhere on your `PATH`: + +```bash +cp wallp ~/bin/wallp +chmod +x ~/bin/wallp +``` + +> **Note:** this is a plain copy. If you later edit the script in the repo, +> re-copy it to `~/bin` for the change to take effect. + +## Configuration + +Config lives at `~/.config/wallp/wallp.conf`. On the very first run, if it +doesn't exist, `wallp` writes a template there and exits **without changing any +wallpaper** — edit it, then run again. + +```ini +# ~/.config/wallp/wallp.conf + +# Optional. Defaults to sexy-splurge if omitted. +THEME=sexy-splurge + +# Physical output names. Find yours with: +# swaymsg -t get_outputs (sway) +# hyprctl monitors (Hyprland) +# wlr-randr +OUTPUT_H=DP-1 +OUTPUT_V=DP-3 + +# Used by --restore when there is no saved wallpaper yet. +# A leading ~ is expanded to your home directory. +DEFAULT_H=~/Pictures/wallpapers/SFW/horizontal.png +DEFAULT_V=~/Pictures/wallpapers/SFW/vertical.png +``` + +Format notes: + +- Plain `key=value`, one per line. Blank lines and `#` comments are ignored. +- The file is **not** sourced as shell — it's parsed manually, so it can't run + code. +- `OUTPUT_H`, `OUTPUT_V`, `DEFAULT_H`, `DEFAULT_V` are required. A missing or + empty one is a hard error (named in the message). `THEME` is optional. + +## Usage + +``` +wallp Show help +wallp --help | -h Show help +wallp --set Interactive selection (qarma): pick H / V / Both +wallp --set H= Set the horizontal screen only +wallp --set V= Set the vertical screen only +wallp --set H= V= Set both screens +wallp --restore Restore last session (defaults if none saved) +wallp --theme Override the theme (combine with --set or --restore) +``` + +### Examples + +```bash +# Interactive: a menu asks which screen, then a file picker opens. +wallp --set + +# Change only the vertical monitor; the horizontal one is untouched. +wallp --set V=~/Pictures/wallpapers/portrait.png + +# Set both at once. +wallp --set H=~/pics/wide.jpg V=~/pics/tall.jpg + +# Restore on login (defaults on first ever run). +wallp --restore + +# Set a wallpaper and switch theme in one go; the theme persists afterwards. +wallp --set H=~/pics/wide.jpg --theme gruvbox +``` + +### Theme precedence + +When resolving which theme to apply, `wallp` uses, in order: + +1. `--theme ` on the command line, +2. the last persisted theme (`~/.config/wallp/theme`), +3. `THEME` from the config, +4. the built-in default `sexy-splurge`. + +The resolved theme is always saved, so it carries across `--restore`. + +### GUI vs CLI + +`qarma` is used **only** to draw windows — the screen-choice menu, the file +picker, dialogs, and the help screen when a display is present. The actual +wallpaper is always set by `swaybg`, so the `H=`/`V=` argument forms work fine +without any display (e.g. from a startup script). `--restore` never needs a +display. + +If you run `wallp --set` with no arguments and no Wayland display is available, +it errors and asks you to pass `H=`/`V=` instead. + +## How it works + +State is owned entirely by `wallp`: + +| Path | Role | +|-------------------------------|-------------------------------------------------| +| `~/.config/wallp/wallp.conf` | configuration | +| `~/.config/wallp/wall_h` | persisted horizontal wallpaper path | +| `~/.config/wallp/wall_v` | persisted vertical wallpaper path | +| `~/.config/wallp/theme` | persisted theme name | +| `~/.cache/wallp/H.pid` | PID of the horizontal `swaybg` | +| `~/.cache/wallp/V.pid` | PID of the vertical `swaybg` | +| `~/.cache/wal/wpaper` | symlink to the current horizontal image | + +Setting a screen: validate the file, kill **only** that screen's old `swaybg`, +launch a new one (`swaybg -o -i -m fill`), record the new PID, +and save the path. Then update the `wpaper` symlink and apply the theme via +`wal --backend colorz -nq --theme -o ~/bin/wal.sh`. + +Restoring: for each screen, use the saved path if present, otherwise the +configured default; apply it; then re-apply the resolved (persisted) theme. + +The `~/.cache/wal/wpaper` symlink is kept because other tools (e.g. rofi themes) +read it. + +## Integration with sway / Hyprland + +Bind the interactive setter to a key and run a restore at startup. For Hyprland: + +```ini +# autostart +exec-once = wallp --restore + +# keybind +bind = $mainMod, Return, exec, wallp --set +``` + +(For sway, use `exec` / `bindsym` equivalents.) + +## Development + +The whole program is the single `wallp` file; functions are small and isolated +so they can be unit-tested. Tests use [bats](https://github.com/bats-core/bats-core): + +```bash +bats tests/wallp.bats +``` + +The suite stubs `swaybg`, `wal`, `qarma`, and `notify-send` on `PATH` and runs +against a temporary `$HOME`, so it touches nothing real. Contributions should +follow TDD — add a failing test first. + +Design notes and the implementation plan live under `docs/superpowers/`. + +## License + +Personal tooling; use as you like. -- cgit v1.2.3