Instrumenting with pause, and the source locations that make it not a pure Emacs job

This commit is contained in:
Joseph Ferano 2026-09-12 17:10:21 +07:00
parent 66c29dfa5f
commit 46b3080eda

View File

@ -314,3 +314,33 @@ literal and not a map with symbol keys. Those get written on purpose.
Deriving at runtime stays rejected — it would add an external dependency to a mode that ships inside this repo and
currently needs nothing beyond stock Emacs, and that community is mid-transition to a tree-sitter mode, so the base is
moving.
## 9. Instrumenting with `(pause)` from Emacs, without editing the buffer
Requested, not scheduled. The Clojure model: `C-u` before an eval marks the form so it stops when it runs. Wanted here
for **three targets** — the top-level form, the last expression, and **the form point is inside**, so that with the
cursor at `(+ 1| 1)` the program stops at that `(+ ...)`.
**What already exists, so this is mostly assembly:**
- **`(pause)` itself**, landed today in `lib/prelude.ml`. It is `error` under a `restart-case` with a `continue`
clause — a breakpoint is not a compiler feature here, it is what a condition system already gives you. Taking
`continue` resumes at the call.
- **`flan-eval-defun`** takes the top-level form's bounds and sends the text; **`flan-eval-last-sexp`** sends the sexp
before point. Both hand a *string* to the daemon, which is the hook — the buffer never has to be modified.
- **`flan-dev--enclosing-head`** (`flan-dev.el:1009`) already walks out to the enclosing form to find its head, for
eldoc. The third target's hard part is already written.
- `current-prefix-arg` is already read in one place (`flan-dev.el:1429`), so the `C-u` convention has precedent.
**So the work is a source-to-source rewrite in Emacs before sending:** find the target form's bounds, send the
top-level form with that span replaced by `(do (pause) <span>)`. Nothing on the compiler side changes.
**The one real difficulty: source locations.** Splicing text shifts every line and column after the insertion, so
error overlays, `layout`, the break loop's frame locations and DWARF would all point slightly wrong for an
instrumented form. Options, none free: pad the inserted text to preserve offsets (ugly, fragile across newlines); send
the instrumentation as a separate field the daemon splices *after* parsing, where locations are already attached; or
accept the drift and say so. **The second is almost certainly right** and makes this a small daemon change rather than
a pure-Emacs one — which also means it should not be built as a pure-Emacs hack first.
Worth deciding at the same time: whether an instrumented eval should also *stick* — Clojure's marks the var until
re-evaluated plainly — or whether it applies once.