docs: add "Working on Nomarchy" orientation guide
Some checks failed
Check / eval-and-lint (push) Failing after 6m21s
Some checks failed
Check / eval-and-lint (push) Failing after 6m21s
A short, task-indexed guide for navigating the repo: the core/features/themes mental model, the two app-config namespaces, the four script locations (incl. themes/engine/scripts/), the build/test loop, how theming works, and a Walker+elephant deep-dive covering the dmenu vs custom-provider menu paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
210
docs/WORKING-ON-NOMARCHY.md
Normal file
210
docs/WORKING-ON-NOMARCHY.md
Normal file
@@ -0,0 +1,210 @@
|
||||
# Working on Nomarchy — a practical orientation
|
||||
|
||||
This is the "I just want to change something without getting lost" guide. It is
|
||||
deliberately short. For the full architecture, see [STRUCTURE.md](STRUCTURE.md);
|
||||
for every option, [OPTIONS.md](OPTIONS.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. The 60-second mental model
|
||||
|
||||
Nomarchy is a NixOS flake. Three layers, top to bottom:
|
||||
|
||||
```
|
||||
core/ foundation → the OS + base user env that must always exist
|
||||
features/ the desktop → apps, Hyprland/waybar, user scripts (opt-in modules)
|
||||
themes/ the look → palettes (data) + engine (logic) + templates (.tpl)
|
||||
```
|
||||
|
||||
Everything else is plumbing: `lib/` (shared Nix helpers), `installer/` + `hosts/`
|
||||
(how it gets onto a disk), `bin/` (repo tooling, **not** shipped to users),
|
||||
`docs/`.
|
||||
|
||||
The flake wires it up as two NixOS/HM modules:
|
||||
- `nixosModules.system` ← `core/system/` (the OS)
|
||||
- `nixosModules.home` ← `features/` (which itself imports `core/home/` + the theme engine)
|
||||
|
||||
### The two things that confuse everyone
|
||||
|
||||
There are **two** places that look like "app config," and they are *different
|
||||
concepts*:
|
||||
|
||||
| Path | What it is |
|
||||
|------|-----------|
|
||||
| `features/apps/<app>/` | The **module** for an app — turns it on, sets its config. This is *code*. |
|
||||
| `core/home/config/nomarchy/default/<app>/` | A **payload** of files copied verbatim to `~/.config/nomarchy/default/<app>/` at rebuild. This is *data* that scripts + the theme engine read at runtime. |
|
||||
|
||||
So when you saw `alacritty` in both trees: `features/apps/alacritty/` is the app
|
||||
module; `core/home/config/nomarchy/default/alacritty/screensaver.toml` is just a
|
||||
screensaver file that happens to be named after alacritty. Not a duplicate.
|
||||
|
||||
**Rule of thumb:** changing how an app *behaves* → `features/apps/`. Changing a
|
||||
file that lands in the user's home and gets read at runtime → `core/home/config/`.
|
||||
|
||||
---
|
||||
|
||||
## 2. "I want to change X" → go here
|
||||
|
||||
| I want to… | Go to |
|
||||
|------------|-------|
|
||||
| Tweak an app's settings (kitty, btop, tmux…) | `features/apps/<app>/default.nix` (+ its `config/`) |
|
||||
| Change Hyprland behaviour / keybinds | `features/desktop/hyprland/` and `core/home/config/nomarchy/default/hypr/` |
|
||||
| Change the status bar | `features/desktop/waybar/` |
|
||||
| Add/remove a theme | `themes/palettes/<name>/` |
|
||||
| Change how theming is applied | `themes/engine/loader.nix` |
|
||||
| Add a **user** command (`nomarchy-foo`) | `features/scripts/utils/` |
|
||||
| Add a **system/root** command | `core/system/scripts/` |
|
||||
| Add a NixOS option (`nomarchy.system.*`) | `core/system/options.nix` |
|
||||
| Add a HM option (`nomarchy.*`) | `core/home/options.nix` |
|
||||
| Change what the installer writes | `installer/install.sh` |
|
||||
|
||||
When in doubt, grep for an existing example of the thing you're changing and copy
|
||||
its shape — the repo is very consistent *within* each of these buckets.
|
||||
|
||||
---
|
||||
|
||||
## 3. The build/test loop
|
||||
|
||||
You almost never need a full install to test a change. From the repo root:
|
||||
|
||||
```bash
|
||||
# Evaluate + build the whole system WITHOUT activating it (safe, no sudo):
|
||||
nixos-rebuild build --flake .#default --impure
|
||||
# → prints "Done. The new configuration is /nix/store/…" if it builds.
|
||||
# (drops a ./result symlink you can delete)
|
||||
```
|
||||
|
||||
On a real install, the user-facing commands are:
|
||||
|
||||
```bash
|
||||
sys-update # sudo nixos-rebuild switch --flake .#default --impure (system)
|
||||
env-update # home-manager switch --flake .#default --impure (user env)
|
||||
```
|
||||
|
||||
`bin/utils/` holds repo tooling that regenerates the auto-docs
|
||||
(`SCRIPTS.md`, `KEYBINDINGS.md`). A pre-commit hook runs them; you rarely call
|
||||
them by hand.
|
||||
|
||||
---
|
||||
|
||||
## 4. Where scripts live (the one rule)
|
||||
|
||||
There are **four** script homes, by **execution context**, not by topic:
|
||||
|
||||
| Dir | Context | Example |
|
||||
|-----|---------|---------|
|
||||
| `bin/utils/` | Repo tooling, never shipped | `nomarchy-docs-scripts` |
|
||||
| `core/system/scripts/` | System / root / hardware | `nomarchy-setup-dns`, `nomarchy-toggle-hybrid-gpu` |
|
||||
| `features/scripts/utils/` | User / desktop | `nomarchy-menu`, `nomarchy-launch-walker` |
|
||||
| `themes/engine/scripts/` | Theme engine | **`nomarchy-theme-set`**, `nomarchy-theme-bg-set`, `nomarchy-theme-next` |
|
||||
|
||||
> **Heads-up:** the `nomarchy-theme-*` family lives in `themes/engine/scripts/`, **not**
|
||||
> `features/scripts/utils/`. All four dirs are built onto the user's `$PATH`, so at
|
||||
> runtime `nomarchy-theme-set "Tokyo Night"` just works regardless of which dir it's in —
|
||||
> the split only matters when you're hunting for the *source*. Find any script's source
|
||||
> fast with `grep -rl nomarchy-theme-set .` rather than guessing the directory.
|
||||
|
||||
New script? Ask: *does it need root or system packages?* → `core/system/scripts/`.
|
||||
*Is it user-facing desktop glue?* → `features/scripts/utils/`. *Only useful inside
|
||||
this repo?* → `bin/utils/`. Scripts are found by name on `$PATH`, so moving one
|
||||
between the first two means changing the Nix derivation it's built into, not the
|
||||
call sites.
|
||||
|
||||
---
|
||||
|
||||
## 5. How theming works (the short version)
|
||||
|
||||
1. The active theme name lives in **state**: `~/.config/nomarchy/state.json`
|
||||
(runtime) → mirrored into `/etc/nixos/nomarchy-state.nix` for reproducibility.
|
||||
2. `themes/engine/loader.nix` reads that name and deploys the matching themed
|
||||
files (btop theme, kitty colors, waybar css…) into `~/.config/`.
|
||||
3. `themes/templates/*.tpl` are filled with the palette's colors to produce
|
||||
dynamic configs.
|
||||
4. Switching a theme runs scripts that rewrite those files and then *reload* the
|
||||
affected apps (this is what the `nomarchy-restart-*` family is for — each app
|
||||
reloads differently: SIGUSR2, a full restart, etc.).
|
||||
|
||||
---
|
||||
|
||||
## 6. Walker + elephant (so you can decide on the menus later)
|
||||
|
||||
This is the bit you wanted to understand before changing anything. There are
|
||||
**two separate programs**:
|
||||
|
||||
- **Walker** — the *front-end*. A Rust/GTK4 window that shows a list and a
|
||||
search box. It's what you see. Started as a user service
|
||||
(`programs.walker`, `runAsService = true`).
|
||||
- **elephant** — the *back-end*. A Go daemon that actually produces the data
|
||||
(apps, calculator, clipboard, emoji, and **custom menus**). Walker talks to it
|
||||
over a Unix socket. Config lives in `features/apps/elephant/config/`, deployed
|
||||
to `~/.config/elephant/`.
|
||||
|
||||
Think: **Walker draws, elephant supplies.**
|
||||
|
||||
### How a menu reaches the screen
|
||||
|
||||
There are two completely different paths, and only one of them touches Lua:
|
||||
|
||||
**Path A — `--dmenu` (no elephant data providers, no Lua).**
|
||||
Used by `nomarchy-menu`, `nomarchy-font`, the keybindings viewer, etc.
|
||||
You pipe plain text lines into `walker --dmenu`; Walker shows them and prints the
|
||||
chosen line back. **Text only** — Walker's dmenu mode literally cannot show icons
|
||||
or an image preview pane (verified in its source: each line becomes `item.text`
|
||||
and the preview box is hidden). This is the simple, dependency-free path.
|
||||
|
||||
```
|
||||
echo -e "Option A\nOption B" | walker --dmenu -p "Pick…"
|
||||
```
|
||||
|
||||
**Path B — elephant custom menu providers (`-m menus:<name>`).**
|
||||
Used by the theme picker and wallpaper picker. Here elephant loads a *menu
|
||||
provider* from `~/.config/elephant/menus/`. A menu provider can be:
|
||||
- a **TOML** file with a *static* list of entries — each entry can have an
|
||||
`icon`, a `preview`/`preview_type`, and `actions`; or
|
||||
- a **Lua** file (`run = "lua:…"`) whose `GetEntries()` returns a *dynamic*
|
||||
list built at runtime.
|
||||
|
||||
The theme/wallpaper menus need a *variable* list (one entry per theme/wallpaper,
|
||||
discovered on disk) **and** an image preview. In elephant, the only built-in way
|
||||
to generate a variable-length list is Lua's `GetEntries()`. That's the entire
|
||||
reason `nomarchy_themes.lua` and `nomarchy_background_selector.lua` exist — and
|
||||
they're the *only* Lua in the whole repo.
|
||||
|
||||
### The decision space (for later)
|
||||
|
||||
If you want to drop Lua but keep Walker, the trade is purely about previews:
|
||||
|
||||
- **Keep previews** → replace the two `.lua` files with a small **bash generator**
|
||||
that writes *static* elephant TOML menus (one `[[entries]]` per theme/wallpaper,
|
||||
each with `preview = "…/preview.png"`), regenerated at rebuild + on theme
|
||||
switch. No Lua, keeps the preview pane, adds one generator script.
|
||||
- **Drop previews** → route the theme/wallpaper pickers through `walker --dmenu`
|
||||
like the other menus. Deletes both `.lua` files, the elephant menu config for
|
||||
them, and the `pkgs.lua` dependency. Simplest possible; theme/wallpaper become
|
||||
plain text lists.
|
||||
|
||||
Nothing here is decided yet — this section is just the map.
|
||||
|
||||
### Key files for the menu system
|
||||
|
||||
| File | Role |
|
||||
|------|------|
|
||||
| `features/scripts/utils/nomarchy-launch-walker` | Wrapper: starts elephant + walker services, routes `--dmenu` vs provider calls |
|
||||
| `features/scripts/utils/nomarchy-menu` | The big interactive menu (all Path A / dmenu) |
|
||||
| `features/apps/walker.nix` | Walker module + config (prefixes, providers, theme) |
|
||||
| `features/apps/elephant/config/` | elephant providers (calc, symbols, **menus/**) |
|
||||
| `features/apps/elephant/config/menus/*.lua` | The two dynamic preview menus (the only Lua) |
|
||||
|
||||
---
|
||||
|
||||
## 7. Gotchas worth knowing
|
||||
|
||||
- **`--impure` is required** on rebuilds — the config reads runtime state
|
||||
(`state.json`) outside the flake.
|
||||
- **`docs/SCRIPTS.md` and `docs/KEYBINDINGS.md` are auto-generated.** Don't edit by
|
||||
hand; the pre-commit hook (and CI) regenerate and verify them.
|
||||
- **The deep `core/home/config/nomarchy/default/…` tree is a payload**, deployed
|
||||
wholesale to `~/.config/nomarchy/default/`. Moving files out of it will break the
|
||||
scripts/loader that read those exact runtime paths.
|
||||
- **Two parallel module systems**: `core/system` = NixOS (root), `features` +
|
||||
`core/home` = Home Manager (user). A setting only works if it's in the right one.
|
||||
Reference in New Issue
Block a user