# 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. The implementation (the native 9P client, the edit-port reader, and the in-process handler) lives in `src/plumb/` — `plumb_lib` is the pure codec/9P client and `plumbplugin.{h,cpp}` is the Kate glue. ## How plumbing reaches Kate ``` plumb # 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 ` / `plumb start ` 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 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 |