diff --git a/DISCUSS.md b/DISCUSS.md index de129d3..0b6a596 100644 --- a/DISCUSS.md +++ b/DISCUSS.md @@ -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) )`. 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.