summaryrefslogtreecommitdiff
path: root/examples/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'examples/README.md')
-rw-r--r--examples/README.md235
1 files changed, 0 insertions, 235 deletions
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index aaaf5920..00000000
--- a/examples/README.md
+++ /dev/null
@@ -1,235 +0,0 @@
-# examples
-
-Programs that drive pardes from the outside. Each subdirectory is one
-interface; `acmefs/` is the acme control filesystem.
-
-## The acme control filesystem
-
-Started with `--fs`, pardes serves a small filesystem describing itself: one
-directory per pane, holding the pane's text, its tag, its selection, a control
-file of verbs and an event stream. Reading a file asks the editor a question,
-writing one gives it an order, and a middle click can be delivered to a script
-instead of to the editor. That is the whole of plan9 `acme(4)`, which pardes
-follows closely enough that acme's own manual page is the reference; the
-divergences are listed at the end.
-
-The point is that a text editor becomes scriptable by anything that can open a
-file. The scripts here are python3 and bash with no dependencies at all, and
-none of them link, embed, or know anything about pardes.
-
-### Starting it
-
-```
-pardes --fs # mount under $XDG_RUNTIME_DIR/pardes/<pid>
-pardes --fs=/tmp/mypardes # or name the mount point yourself
-```
-
-The mount lives in `$XDG_RUNTIME_DIR/pardes/<pid>`, or
-`~/.local/state/pardes/<pid>` when there is no runtime directory. It is created
-at startup, mode 0700, and unmounted and removed on exit; a startup sweep
-removes directories left by a pardes that died without unmounting.
-
-Every shell pardes starts inside a pane inherits two variables:
-
-| variable | meaning |
-|---|---|
-| `PARDES_FS` | the mount directory |
-| `PARDES_PANE` | the id of the pane the shell is running in |
-
-So a script run from a pane already knows both where the editor is and which
-pane it is talking from, and every example below defaults to those.
-
-One rule the protocol inherits from acme: **a `ctl` verb, an `addr` expression
-and an `event` record must each arrive in ONE `write(2)`.** acme got that for
-free (a 9P message IS a write), and every ordinary client has it too — stdio
-buffers, `echo` and `dd` write whole strings, Python's `os.write` is one call.
-A client that writes a verb one byte at a time gets EINVAL per byte, because a
-control file cannot tell a half-finished verb from a wrong one. Write whole
-lines.
-
-### The tree
-
-```
-/
- index r one line per pane
- cons w appends to +Errors
- new/ dir looking up ANY name here creates a pane
- <id>/ dir one per pane; id is the pane serial, never reused
- addr body ctl data errors event rdsel tag wrsel xdata
- pty/ dir TERMINAL PANES ONLY; absent on a pane with a document
- ctl status data
-```
-
-| file | mode | semantics |
-|---|---|---|
-| `index` | r | one line per pane: five `%11d` fields -- id, tag length, body length, isdir, dirty -- then the tag text. Seekable. |
-| `cons` | w | appended text goes to the `+Errors` pane for the writing pane's directory, created on first write. |
-| `new/<name>` | lookup | creates a pane and resolves to that pane's `<name>`, so `echo hi > $PARDES_FS/new/body` opens a pane containing `hi`. Listing `new/` enumerates nothing at all -- every name it could report is a name whose lookup would create a pane, and `ls -l` stats what a listing reports. |
-| `addr` | rw | read: the current address as two `%11d` byte offsets. Write: an address expression. Never disturbs the user's selection. |
-| `body` | rw | read at any offset; a write APPENDS, whatever the offset. Replacing text means `addr` + `data`. |
-| `tag` | rw | read the whole tag; a write appends to the editable tail. (A pardes tag carries a live read-only prefix, so appending to that would be meaningless.) |
-| `ctl` | rw | read: the five `index` numbers plus `%11d %q %11d` -- width in cells, font name, tab width in cells. Write: newline separated verbs, several per write, applied all or nothing. |
-| `data` | rw | read: whole graphemes from the start of `addr`, up to the read size, moving `addr` past them. Write: replaces the addressed text and leaves `addr` as the null string after the insertion. The file offset is ignored. |
-| `xdata` | rw | `data`, except that reads stop at the end of `addr`. |
-| `errors` | w | appends to `<dir>/+Errors` for this pane's directory. |
-| `rdsel` | r | the pane's current selection. |
-| `wrsel` | w | replaces the pane's current selection. |
-| `event` | rw | the pane's action stream, both directions. See below. |
-| `pty/` | dir | present only when the pane is a terminal, so `test -d $PARDES_FS/<id>/pty` is how a script asks. Absent — not empty — on a file pane, and every file under it answers ENOENT there. |
-| `pty/ctl` | w | newline separated verbs, several per write, applied all or nothing: `winsize <cols> <rows>`, `sig INT\|TERM\|HUP\|QUIT\|KILL`, `exec`. Anything else is EINVAL and applies nothing. |
-| `pty/status` | r | three `%11d` fields: columns, rows, and 1 while a program (vim, a pager, a build) holds the tty rather than the shell prompt. Seekable. |
-| `pty/data` | rw | the raw stream. A write is input to the program, offset ignored, short at a character boundary. A read hands back as much of the pending output as the count allows and keeps the rest — raw bytes have no records, so unlike `event` a small read is served rather than refused — and blocks while there is nothing. Output is only recorded while the file is OPEN. |
-
-`ctl` verbs: `addr=dot`, `clean`, `dirty`, `cleartag`, `del`, `delete`,
-`dot=addr`, `get`, `limit=addr`, `mark`, `nomark`, `name <name>`, `noscroll`,
-`scroll`, `put`, `show`. An unknown verb fails the whole write with EINVAL and
-applies nothing, so a batch is safe to send blind.
-
-`pty/ctl` verbs in detail. `winsize` is `TIOCSWINSZ` and nothing more: it tells
-the program a size and does not move the pane, whose grid is its rectangle on
-screen, so the next time you drag that pane the layout's size wins again.
-`sig` goes to the tty's foreground process group — what ^C would reach — and
-not to the shell, which ignores SIGINT while it waits for a job. `exec`
-respawns the pane's configured shell in the pane's own directory and takes NO
-argument: `exec /bin/sh` is EINVAL rather than an argument silently dropped.
-`raw` and `cooked` do not exist, because the termios belongs to the program on
-the far side of the pty and it never tells us.
-
-Addresses, all in bytes: `#n` an offset, `n` a line, `0` the start, `$` the
-end, `.` the selection, `a,b` a range (`,` alone is the whole body), `+` and
-`-` with a count or a regex, `/re/` forwards, `?re?` backwards. Anything else
-is EINVAL.
-
-### Events
-
-A record is two characters and four blank separated decimal numbers, then the
-text:
-
-```
-origin type q0 q1 flag length [text]
-```
-
-Origin is `E` for a write through the `body` or `tag` file, `F` for an action
-through one of the pane's other files, `K` for the keyboard and `M` for the
-mouse. Type is `D`/`d` for a delete, `I`/`i` for an insert, `L`/`l` for a
-button-3 Look and `X`/`x` for a button-2 Exec -- uppercase for the body,
-lowercase for the tag, which is the entire addressing convention. Text of 256
-bytes or more is elided with a length of 0 and can be fetched from `data`.
-Deletes carry no text.
-
-Two behaviours make this the interesting file:
-
-* **While a pane's event file is open, its Look and Exec are reported and not
- performed.** Chorded Cut and Paste still work normally. That is what lets a
- script put its own words in the tag and mean its own things by them --
- `acmefs/life.py` is nothing but that trick.
-* **Writing a record back performs the action**, as though the event file had
- never been open. The write is only `origin type q0 q1` and a newline: the
- action is named by a range of the pane's own text. Passing on the records you
- do not implement is how a script stays a good citizen of somebody else's
- editor.
-
-### Deliberate divergences from acme
-
-acme counts runes; pardes counts bytes, clamped to grapheme boundaries.
-pardes is byte-addressed end to end -- selections, look spots, LSP offsets --
-and a second coordinate system would add an O(n) scan at every boundary and
-make `addr=dot` and `dot=addr` lossy. For ASCII the two are identical.
-
-`acme`, `draw`, `consctl`, `label` and `editout` are not served. The first four
-are rio and plan9 compatibility stubs with nothing behind them here, and
-`editout` is the output sink of acme's `Edit` language, which pardes does not
-have.
-
-## The examples
-
-All four take the mount from `$PARDES_FS` and accept an override, and all four
-exit quietly when the pane or the mount goes away, because "the editor exited"
-is a normal ending for a program living inside it.
-
-### `acmefs/clock.py` -- a pane that is a clock
-
-Creating a pane, naming it, and replacing its body in place once a second.
-
-```
-$ examples/acmefs/clock.py &
-```
-
-A pane named `/+clock` appears and fills with the time in doubled-width block
-digits. Ctrl-C removes it. Demonstrates: `new/ctl` as the creation handshake,
-batched `ctl` verbs, and `addr` + `data` as the only way to replace body text.
-
-### `acmefs/life.py` -- a game whose buttons are the tag
-
-```
-$ examples/acmefs/life.py &
-```
-
-A pane named `/+life` appears with `Step Run Stop Clear Random` in its tag and
-a random 40x20 board in its body. Middle-click the words: they are not pardes
-commands and pardes has never heard of them, but the script has the event file
-open, so the clicks arrive here as `x` records naming the text. Button 3 on a
-cell toggles it. Middle-clicking anything the script does not implement -- the
-pane's own `Del`, say -- is written back to the event file and performed by the
-editor as usual. Ctrl-C removes the pane.
-
-### `acmefs/pardesctl` -- the editor from the command line
-
-```
-$ examples/acmefs/pardesctl panes
- ID DIRTY BYTES TAG
- 1 - 4213 src/pardes.zig
- 3 * 118 /+clock
-$ examples/acmefs/pardesctl send 3 'hello from the shell'
-$ examples/acmefs/pardesctl body 3 | wc -l
-$ examples/acmefs/pardesctl tag 1
-$ id=$(examples/acmefs/pardesctl new src/pardes.zig)
-$ examples/acmefs/pardesctl exec "$id" Help
-$ examples/acmefs/pardesctl exec "$id" 'date >/tmp/from-pardes'
-$ examples/acmefs/pardesctl del "$id"
-```
-
-`exec` is the remote control door: it appends the command to the pane's tag,
-works out the byte range it landed in, and writes an `x` record naming that
-range -- which is exactly what a middle click on the same text would have sent.
-The command stays in the tag afterwards, where acme leaves it too, so it can be
-clicked again.
-A pardes builtin (`Help`, `New`, `Changelog`, ...) runs as a builtin; anything
-else runs as a shell command with its output going to `+Errors`, the same as if
-you had typed it into a tag and clicked it.
-
-`-m <dir>` overrides `$PARDES_FS`. With no arguments it prints its usage.
-
-### `acmefs/eventlog` -- watch the protocol
-
-```
-$ examples/acmefs/eventlog 3
-ORIGIN ACTION WHERE Q0 Q1 FLAG TEXT
-mouse exec tag 41 45 builtin Help
-fs-write insert body 0 0 - (no text...)
-```
-
-Every record spelled out in words, flag bits included. Point it at a pane and
-type in it, click in it, write to it from `pardesctl`, and watch what the
-editor reports.
-
-## WARNING
-
-**Opening a pane's `event` file suppresses that pane's Look and Exec.** Button
-2 and button 3 in a watched pane are reported to the reader and are *not*
-performed by the editor, so a watched pane feels broken until the reader exits
-(chorded Cut and Paste are exempt). This is a feature -- it is what makes a
-script's own tag words possible -- but `eventlog` inherits it, so do not leave
-it attached to a pane you are trying to work in.
-
-**A record is consumed by whoever reads it first.** Two programs on one pane's
-event file split the stream between them and both misbehave. Do not point
-`eventlog` at the pane `life.py` is driving.
-
-**Writing an `X` or `x` record executes arbitrary commands, by design.** So
-does `Look` reaching an executable name. `pardesctl exec` is four lines of
-shell for a reason: the filesystem is a remote control, and anything that
-can write into the mount directory can run commands as you. The mount is mode
-0700 under your own runtime directory, and that is the only thing standing
-between the two facts. Do not put it on a shared filesystem, and do not serve
-it to anything you would not hand a shell to.