diff options
Diffstat (limited to 'docs/macos.md')
| -rw-r--r-- | docs/macos.md | 73 |
1 files changed, 45 insertions, 28 deletions
diff --git a/docs/macos.md b/docs/macos.md index 7f695000..ff19ff93 100644 --- a/docs/macos.md +++ b/docs/macos.md @@ -61,10 +61,12 @@ removing; it is the encoding being right. The one real difference is IO. The browser has no ptys, so `src/web.zig` forwards every effect out to JavaScript as a numbered code plus a byte payload, and JavaScript performs it. macOS has `forkpty`, `read` and `write` right there, -so effects never cross the boundary at all: `pardes_tick` drains the core's -effect queue and performs each one in Zig, the way `drainEffects` in -`src/tty/tty.zig` does. That is why the runtime struct is two callbacks and not -twelve. +so almost no effect crosses the boundary at all: `pardes_tick` drains the +core's effect queue and performs each one in Zig, the way `drainEffects` in +`src/tty/tty.zig` does. That is why the runtime struct is three callbacks and +not twelve — and why two of the three are the clipboard: the pasteboard is +AppKit's, in both directions, and is the one piece of IO the Zig side cannot +reach for itself. ## The seam @@ -100,13 +102,20 @@ is made of and what opens a path from argv or the Dock (`Look <path>`). it. `pardes_resize` also carries one cell in *physical* pixels, which only the native PDF placement path reads — pass the backing-store size, not points. -**Runtime callbacks.** `pardes_runtime_s` is a `userdata` and two functions, +**Runtime callbacks.** `pardes_runtime_s` is a `userdata` and three functions, copied by value during init so the struct need not outlive the call. `wakeup` -means "your state moved, please pump me"; `set_clipboard` fires inside a tick -when the yank register changes, with the text borrowed for the duration of the -call. There is no `open_url` callback because the core already opens links -itself through `/usr/bin/open` (`src/look.zig`), and no file callbacks because -it owns the filesystem side too. +means "your state moved, please pump me". `set_clipboard` hands over text to put +on the pasteboard, borrowed for the duration of the call; it fires inside a tick +for the five `SPC` clipboard words and for the tag's own `y` chord, and for +nothing else — an ordinary `y` or `d` writes the core's register and never +reaches here, which is what stopped deleting a character from clobbering the +desktop's clipboard. `read_clipboard` is that direction reversed: "give me the +pasteboard", with no payload either way, because the host answers by calling +`pardes_paste` — and NSPasteboard being synchronous, that usually happens inside +the callback itself, before it returns. Both are main thread, inside +`pardes_tick`. There is no `open_url` callback because the core already opens +links itself through `/usr/bin/open` (`src/look.zig`), and no file callbacks +because it owns the filesystem side too. **Lifecycle.** `pardes_init` returns 0 or an opaque nonzero code, `pardes_deinit` tears down, `pardes_tick` drains pty output plus the effect @@ -195,11 +204,14 @@ already-Exec is the only case with nothing to do. The view also needs system's business and never arrives — and the user needs "Force Click and haptic feedback" on in System Settings, which nothing in this process can read. -Twisting two fingers is a dial, and a dial over a list of search hits is `n`. -`pardes_rotate` takes raw degrees and libpardes quantizes them, one search step -per 10°, keeping the remainder — the same accumulate-and-spend shape as -`pardes_scroll`, in Zig for the same reason: it is then unit-tested on a machine -with no trackpad. AppKit reports counterclockwise as positive and the forward +Twisting two fingers is a dial, and a dial over a list of look-able places is +`n`. A notch moves the SELECTION one place along and opens nothing; Enter opens +the one the dial stopped at, which is what makes the dial worth spinning at all +— a stepper that opened every place it passed could not be. `pardes_rotate` +takes raw degrees and libpardes quantizes them, one step per 10°, keeping the +remainder — the same accumulate-and-spend shape as `pardes_scroll`, in Zig for +the same reason: it is then unit-tested on a machine with no trackpad. AppKit +reports counterclockwise as positive and the forward step is clockwise, so the sign inverts here and nowhere else. The banked remainder is deliberate hysteresis; a gesture beginning passes 0 to clear it, so the first degree of a new twist cannot inherit a nearly-complete notch from the @@ -244,10 +256,11 @@ asserting the machine's timer jitter. Both halves are goldens. `rotate.snap` turns the dial at 4° per 100 ms (40°/s, under the floor) and asserts the screen is byte-identical across the release, then at 12° per 5 ms and asserts it is not. The list it walks is twenty-four -hits rather than three for a reason worth keeping: `n` at the last match has -nowhere to go, so on a short list the hardest possible flick and no flick at -all produce the same screen — a golden that would have passed before momentum -existed. +places rather than three for a reason worth keeping, and `n`/`N` becoming a +RING only sharpened it: a short ring comes round, so a hard flick can stop +exactly where a single notch would have and the two screens agree — a golden +that passes before momentum exists. Twenty-four is longer than the cap can +travel (about eleven), so the fling has nowhere to hide. ## A drop is a click plus Look @@ -306,8 +319,11 @@ the *word under the pointer* and most words resolve to nothing: and the screen does not move. The pulse still fires — the gesture worked. - **Exec** (three fingers) on a builtin name runs it. On ordinary prose it types that word at a shell, which needs a terminal pane to type into. -- **`n`/`N`** (twist) steps a results buffer. With no `/pattern`, Grep or Find - behind it there is nothing to step. +- **`n`/`N`** (twist) moves the SELECTION to the next look-able place and opens + nothing; Enter opens what it landed on. It walks a ring across panes — the + ones a Look came from first, then the output buffers none has — so a twist + with no results buffer anywhere still steps the pane in front of you. A screen + with no filename on it is what has nothing to step. `PARDES_LOG=1` prints every decoded gesture to stderr — the fingers counted, the stream it came in on, the button it resolved to, the pressure stage, the @@ -319,12 +335,13 @@ because guessing at that from a screenshot cost an afternoon. Every Exec and every Look taps the trackpad. The core arms a one-slot pulse in the ONE dispatcher — `lookAt` and `execute`, the two functions a middle click, a -right click, Enter, Tab, a tag chord, `n`/`N` stepping and the `Look`/`Exec` -builtins all funnel into — and the host takes it once per pump with -`pardes_take_haptic`. Exec gets `.generic`, the definite tap of something done; -Look gets `.alignment`, the lighter detent AppKit uses when a dragged guide -snaps. A pulse, not a queue: five Execs inside one keystroke are one thing the -hand did. +right click, Enter, Tab, a tag chord and the `Look`/`Exec` builtins all funnel +into — and the host takes it once per pump with `pardes_take_haptic`. Exec gets +`.generic`, the definite tap of something done; Look gets `.alignment`, the +lighter detent AppKit uses when a dragged guide snaps. A pulse, not a queue: +five Execs inside one keystroke are one thing the hand did. A twist taps nothing +now that `n`/`N` only move the selection, and that is the honest report: the +detent belongs to the Enter that opens, and that is where it fires. Three details are load-bearing. `execute` arms only at `exec_depth == 0`, because `Exec ls` re-enters as `ls` and one Tab is one gesture however many @@ -672,7 +689,7 @@ zig build unit-test -Dplatform=macos That covers the ABI's Zig side, the effect drain, and the two quantizers the trackpad depends on — `takeScrollTicks` and `takeRotationNotches` are pure -functions precisely so that "how many search steps is a 180° twist" is answerable +functions precisely so that "how many notches is a 180° twist" is answerable on a machine with no trackpad in it. The header is kept honest with ghostty's trick. `build.zig` runs `translate-C` |
