docs: add docs/PLUMBING.md for configuring ~/lib/plumbing

Document the user-side plumber rules that make files and directories open in
Kate: the edit-port routing model, setting editor = /usr/bin/kate so files
(with their addr line/col) open in Kate instead of acme, the isdir rule that
opens a directory as a folder (plumb start kate $dir), reloading a running
plumber (9p write plumb/rules), verification, and troubleshooting. Cross-link
from PLAN.md.

Note: ~/lib/plumbing itself lives in the user's home, not the repo; this
documents how to configure it.
This commit is contained in:
Levi Neely 2026-10-08 16:14:41 +02:00
parent 50d037690f
commit 376a190b52
2 changed files with 143 additions and 0 deletions

View File

@ -357,6 +357,10 @@ Kate flow through the real plumber rules.
plumber/namespace is reachable, so CI stays green. The live round-trip was
confirmed passing. The GUI open/cursor path (`openUrl`/`setCursorPosition`)
is not exercisable headless and is unverified on a live display.
- **User configuration**: routing (what a plumbed string means, and that files
and directories open in Kate) is set in `~/lib/plumbing`. See
**`docs/PLUMBING.md`** for the editor variable, the directory rule, reloading
the plumber, and troubleshooting.
### Sam — structural-regexp editing panel — DONE
A dockable tool view ("Sam", left sidebar) runs the plan9 **sam** command

139
docs/PLUMBING.md Normal file
View File

@ -0,0 +1,139 @@
# Plumbing — configuring `~/lib/plumbing` for Kate
Kate is a full plan9port **plumb client**: it sends plumb messages (plumb a
token under the caret) and receives them on the `edit` port (open a file at a
line, or a directory as a folder). The *routing* — what a plumbed string means —
lives in the plumber's rules, not in Kate. This document covers the user-side
rules in `~/lib/plumbing` that make files and directories open in Kate.
See `PLAN.md` → "Plumbing" for the implementation (the native 9P client, the
edit-port reader, and the in-process handler).
## How plumbing reaches Kate
```
plumb <text> # or Kate's F2 on the caret token
│
▼
plumber ── applies ~/lib/plumbing rules ──► routes to a PORT
│
▼ (edit port)
Kate's reader thread ──► onPlumbEdit() ──► open file@line / open folder
```
- The plumber matches the message against rules **top to bottom; first match
wins**.
- A rule routes to a **port** (`plumb to edit`, `plumb to web`, …). The `edit`
port is where editors listen.
- `plumb client <prog>` / `plumb start <prog>` name what to run **if no
application currently holds that port**. A ruleset may contain **only one**
`client`/`start` action.
- `client` — the started program is expected to *open the port itself*; the
message is then delivered through the port. acme and Kate both work this
way (Kate via its edit-port reader).
- `start` — just runs the program with the given arguments.
## Make Kate the editor
Set the editor variable near the top of `~/lib/plumbing`:
```
editor = /usr/bin/kate
```
Every file rule ends with `plumb to edit` + `plumb client $editor`, so this
alone makes **files open in Kate**:
- If Kate is already running, its reader holds the `edit` port and receives the
message directly.
- If nothing holds `edit`, the plumber cold-starts `/usr/bin/kate`; once its
reader attaches, the message is delivered.
The **line/column** travels in the message as an `addr` attribute (e.g.
`addr=42`), *not* as a command-line argument. `plumb client` delivers it through
the port, and Kate's handler jumps to it — so `foo.c:42` opens `foo.c` at line
42.
> The `edit` port is single-consumer. If acme and Kate run at the same time,
> whichever holds `edit` wins; you cannot have both receive plumbed files. With
> `editor = /usr/bin/kate`, Kate is the one cold-started and holding the port.
## Open a directory as a folder
The stock `basic` rules only match **regular files** (`arg isfile`), so a bare
directory path fails with *"couldn't find destination for message."* Add a
directory rule. Place it **before** the generic file rules (those use `isfile`,
which fails on a directory, so ordering is not strictly required, but keeping it
with the other specific rules is clearest):
```
# any existing directory opens as a folder in Kate
type is text
data matches '[a-zA-Z¡-￿0-9_\-./@~]+'
arg isdir $0
data set $dir
plumb to edit
plumb start kate $dir
```
- `arg isdir $0` succeeds only for an existing directory and sets `$dir`.
- `data set $dir` makes the directory path the message payload.
- `plumb to edit` delivers to Kate's reader when it is running (the in-process
handler opens the folder; `start` does **not** fire).
- `plumb start kate $dir` cold-starts Kate on the directory when nothing holds
`edit`. Kate registers `inode/directory` in its desktop entry and opens a
directory as a folder.
Note the one-`client`/`start`-per-ruleset limit: this rule uses `start` (not
both `client` and `start`), which covers running and cold-start cases together.
## Apply changes to a running plumber
Rules reload without restarting the plumber:
```
cat ~/lib/plumbing | 9p write plumb/rules
```
A malformed ruleset is rejected whole (the write fails with an error such as
`ruleset has more than one client or start action`); the previous rules stay
in effect until a valid file is written.
## Quick verification
```
# a file (should route to the edit port, carrying addr=3)
plumb /path/to/file:3
# a directory (should route to the edit port, data = the dir)
plumb /path/to/dir
```
To watch what a plumb actually delivers, read the edit port in another shell:
```
9p read plumb/edit # prints the message: src/dst/wdir/type/attr/ndata/data
```
A successful file message looks like:
```
plumb
edit
<wdir>
text
addr=3
15
/path/to/file
```
and a directory message has an empty attr line and `data = /path/to/dir`.
## Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| `plumb: can't send message: couldn't find destination` | no rule matched (e.g. a directory with only `isfile` rules) | add the directory rule above |
| files open in **acme**, not Kate | `editor` still points at acme | set `editor = /usr/bin/kate` and reload |
| `9p write plumb/rules` fails | malformed rule, or two `client`/`start` actions in one ruleset | keep a single `client`/`start` per rule; fix the reported line |
| directory plumb starts Kate but no folder | Kate build without `inode/directory` handling | verify `kate /some/dir` opens the folder from a shell |