Both editor notes are answers now, not asks

This commit is contained in:
Joseph Ferano 2026-09-12 04:04:46 +07:00
parent 38004eec3e
commit 2c32b9ad62

43
NEXT.md
View File

@ -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.<name>` 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 `<ptr>` 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