From 2c32b9ad62f00f38c03f10689143e2541d2d6f14 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 12 Sep 2026 04:04:46 +0700 Subject: [PATCH] Both editor notes are answers now, not asks --- NEXT.md | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/NEXT.md b/NEXT.md index c22d022..f071b46 100644 --- a/NEXT.md +++ b/NEXT.md @@ -801,6 +801,7 @@ request and `read` reads a reply. | `C-c C-r` | a prompt on the running program (`*flan-repl*`) | | `C-c C-b` | what a **stopped** program is offering, and which to take | | `C-c C-d` | what the running program currently defines | +| `C-c C-a` | the code a name compiled to — amd64, or `C-u` for the LLVM IR | | `M-.` / `M-,` | where a name is written, through an `xref` backend | eldoc, `completion-at-point` and `M-.` all read one cached `defs` reply rather than asking per keystroke: eldoc fires on @@ -835,15 +836,41 @@ An accepted evaluation says which names landed and what the build cost, and flas success is indistinguishable from silent failure, and `beginning-of-defun` may well have found a different form from the one point looked like it was in. -**TODO — live disassembly.** Add an editor command that asks the live Flan session for a named function's generated code -and shows a disassembly (with the source location and reload generation it came from). `flan emit --dev` can show LLVM -IR for a whole source file today, but neither the daemon nor Emacs can inspect the native code currently installed in an -indirection cell. There should be options to both show the LLVM IR but also the target platform assembly, which in my -case is amd64, if that's possible. Take a look at how SBCL does it for reference. +**Live disassembly — done.** `C-c C-a` on a name writes the amd64 the running program's copy of it was assembled to +into `*flan-disassembly*`; `C-u C-c C-a` writes the LLVM IR that body was built from. `(:op "disassemble" :name … :form +"asm"|"ir")` is the op. -**TODO — transient error overlays.** The diagnostic ghost text should vanish as soon as the user does anything else in -that buffer — edit, move, evaluate, or invoke another command — rather than surviving until a later evaluation is -accepted. It is feedback about the action that just failed, not a durable annotation on the source. +What makes it possible is that the daemon owns the build: it compiled every module it sent, so `objdump -d +--disassemble=flan.` on the right object *is* the disassembly and the retained `.ll` is the IR. `Build.shared` +deletes its own `.ll` and `Build.executable` leaves the host's under a name that says nothing about which module it was, +so the daemon now writes its own copy beside each `.so` and keeps the host's as `host.ll` — ten reloads in, nothing else +on the machine still has that text. A table from function name to the last module accepted for it is the whole of the +bookkeeping. + +**What it will not claim is that the code shown is installed**, and this is the interesting half. The agent's socket +takes a module path and five verbs; none of them reports an address, `flan_dev_cell` lives in the program's address +space, and `C-x C-e` renders a pointer as `` on purpose — so nothing the daemon can ask would tell it what a cell +holds. The reply carries `:basis` saying which of three things is true, and the buffer prints it above the first +instruction: + +- nothing has been delivered for this name, so the cell still holds the host's body — the one case that is *certain*; +- a module was delivered and the agent queued it, and the program installs it at its next frame boundary — unconfirmed; +- a module was delivered and the program is **stopped**, so it has not reached a frame boundary and this is certainly +not installed yet. + +From SBCL: offsets from the function's own start rather than addresses into an object, and `L0:` labels on branch +targets with the file address that duplicates them dropped. Not source interleaving — SBCL has the mapping and this +build emits no line tables — so the reply says that in words rather than printing a listing with no source in it. When +the debug build lands, that is the line to delete. + +**Transient error overlays — done.** The diagnostic ghost text is feedback about the evaluation that just failed, not an +annotation on the source, so the next command in that buffer takes it down — edit, motion, evaluation, anything. +`pre-command-hook` and not `post-command-hook`, which fires at the end of the *failing* command and would clear the +overlay before redisplay had drawn it. The hook is buffer-local and lives exactly as long as an overlay does: added +where one is drawn, removed where they are cleared, so a session of twenty buffers is not running it on every keystroke +in all of them. `execute-kbd-macro` runs no `pre-command-hook` under `--batch`, so the test drives `run-hooks` — the +same call the command loop makes — and checks the hook is installed in that buffer and in no other; that Emacs runs it +is Emacs' contract and a test claiming to check it would be checking nothing. **The program's stdout is a pipe into the daemon**, and whatever it printed since the last reply rides along with the next one into `*flan-output*`. Having it arrive *with* a reply rather than by a separate request is the point: the