aboutsummaryrefslogtreecommitdiffstats
path: root/docs/scripting.md
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-15 23:53:30 +0200
committeruser <user@clank>2026-08-15 23:53:30 +0200
commit4dc055692c56324a94d1087331da8862ea650d2b (patch)
tree5ddec99f7cf6b144ede4138b6e952c84379725aa /docs/scripting.md
parentsl0ppty: marks a font actually draws at cell size (diff)
downloadslosh-4dc055692c56324a94d1087331da8862ea650d2b.tar.gz
slosh-4dc055692c56324a94d1087331da8862ea650d2b.tar.xz
slosh-4dc055692c56324a94d1087331da8862ea650d2b.zip
sl0ppty: a README you can read, and docs/ for the rest
The README was 331 lines and had become a manual with a title. Everything in it was true and most of it was the wrong thing to hand somebody who has just arrived: five pages of shader expression semantics before they have split a pane. So the front page is 60 lines -- what it is, install, run, where the docs are, and six bullets on what is actually different about it -- and the detail moved into docs/, nine pages that each answer one question: index.md what it is, install, run, where to go keys.md the leader, every default, rebinding, direct binds panes.md splitting, resizing, the mouse, dead panes, small terminals config.md the file, live reload, include, themes, the knobs shaders.md the passes, the built-ins, the expression language chrome.md where="chrome", channel, since, the perimeter trick layouts.md a session as a file, and writing one back out scripting.md the control socket, OSC 5577, headless design.md the two decisions, and a map of the source docs/nav holds the order and the grouping and nothing else -- titles come from each page's own heading, so a renamed page cannot end up with two names. It is what the site generator will read. Reference material that only existed in code comments is written down for the first time: every action that can be bound (including the two with no default key, which is what the palette is for), every control verb, the built-in shaders with what each takes, the pane-state ranking, and the layout file's shape. Two things I got wrong on the first pass and fixed before committing: the docs linked repo files through github.com URLs for a project whose remote is a private git server, so those are inline paths now; and the README advertised `make docs`, which does not exist yet. It will in the next commit, and it can be advertised then.
Diffstat (limited to 'docs/scripting.md')
-rw-r--r--docs/scripting.md75
1 files changed, 75 insertions, 0 deletions
diff --git a/docs/scripting.md b/docs/scripting.md
new file mode 100644
index 0000000..0c27565
--- /dev/null
+++ b/docs/scripting.md
@@ -0,0 +1,75 @@
+# Scripting
+
+Three things make sl0ppty easy to drive from other programs: a socket that does
+everything the keyboard does, an escape sequence a pane can use to draw its own
+chrome, and a headless mode that is the whole program without a terminal.
+
+## The control socket
+
+One JSON object per line, over the session's socket. A detached session answers
+exactly as an attached one does.
+
+```bash
+$ sl0ppty -s work cmd '{"cmd":"new-tab","name":"api"}'
+{"ok":true,"id":2}
+$ sl0ppty -s work cmd '{"cmd":"panes"}'
+{"ok":true,"panes":[{"id":1,"title":"nvim","alive":true,...}]}
+```
+
+Panes and tabs are addressed by **id**, so a background tab is scriptable.
+
+| verb | |
+|---|---|
+| `panes` `tabs` | what exists, with ids, rects, titles, purposes, state |
+| `snapshot` | the composited screen, as JSON or `format:"text"` |
+| `deadline` | when the session wants its next frame, in ms, or -1 |
+| `send` | bytes as if typed, decoded like input (`"data":"\\x01\\\\"`) |
+| `raw` | bytes straight into the focused pane's pty |
+| `resize` | `cols` `rows`, and optionally `cell_w` `cell_h` |
+| `split` | `dir:"cols"\|"rows"`, `id` for which pane to split |
+| `focus` | `id` |
+| `close` `rerun` | `id`, or 0 for the focused pane |
+| `new-tab` `select-tab` `close-tab` `move-tab` `set-name` | tabs, by `id` or `index` |
+| `set-purpose` | `target:"pane"\|"tab"`, `id`, `purpose` |
+| `dump-layout` `apply-layout` | see [layouts](layouts.md) |
+| `notify` | put a line in the session's status area |
+| `graphics` | the kitty placements on screen, or the bytes sent for them |
+| `clipboard` | what the session has copied |
+| `reload` | re-read the config; answers `{"ok":true,"warning":...}` if it had a complaint |
+| `edit-config` | open the config in a pane |
+| `alive` | is it running, and how many panes and tabs |
+| `quit` | end the session |
+
+## A pane can draw its own chrome
+
+By printing an escape sequence — no plugin, no config:
+
+```bash
+printf '\033]5577;1;status;building 3/7\033\\'
+printf '\033]5577;1;buttons;approve:Approve;cancel:Cancel\033\\'
+# clicking [Approve] arrives on the program's stdin as:
+# \033]5577;1;click;approve\033\\
+```
+
+The status text appears in the pane's frame; the buttons are real targets in it.
+A program that wants to be asked something can ask *in place* rather than
+printing a prompt and hoping.
+
+`purpose` is the other verb: `printf '\033]5577;1;purpose;logs\033\\'`. A purpose
+declared by a layout or the control API wins and cannot be overwritten this way.
+
+## Headless
+
+`sl0ppty --script` is the whole program without a terminal: commands on stdin,
+answers on stdout. It is how the test suite works — drive these events, assert
+this screen — which is also why the suite is 700-odd real end-to-end checks that
+finish in eight seconds.
+
+```bash
+$ printf '%s\n' '{"cmd":"split","dir":"cols"}' '{"cmd":"snapshot","format":"text"}' \
+ | sl0ppty --script --cols 80 --rows 24 -- /bin/sh
+```
+
+The bare-verb form (`snapshot text`, `send \x01\\`, `resize 100 30`) is a
+human-friendly alias for the same code, so a script and a test cannot drift from
+what the API does.