From 9d7da2ba7aed49dc23282f22fd9371b8cfee51d3 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Tue, 22 Sep 2026 11:12:53 +0700 Subject: [PATCH] A stop takes the window, because the next key is aimed at it --- TODO.org | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- emacs/flan.el | 24 +++++++++++++----------- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/TODO.org b/TODO.org index f93a1740..08b63fcb 100644 --- a/TODO.org +++ b/TODO.org @@ -1,5 +1,5 @@ #+TITLE: Flan -#+TODO: TODO NEXT WAIT | DONE CANCELLED +#+TODO: TODO WAIT | DONE CANCELLED #+ARCHIVE: ::* Archive Every decision, open question and known gap, one =**= heading each under the @@ -470,7 +470,7 @@ an ordinary =defn= declares no environment and is byte-for-byte what it was. The static side does not pay for the dynamic side. Rejected names: Closure, Proc, Fun, Func, Fnptr. -** NEXT Escaping closures, allocated on the GC side +** TODO Escaping closures, allocated on the GC side The second half of "do both". What changes is where the environment points — a frame slot today, a collector allocation then — and the escape check goes away with it, along with the refusals on returning, storing, pointing at and pushing a @@ -1731,6 +1731,51 @@ specification's own branch — the flag is the command and the printed shape is error pattern, so anyone who wants one has the four lines, and the manual carries them. +** TODO The break buffer prints a condition's fields, not its message +=ArithError — op 4, lhs -2147483648, rhs 2147483647= where the runtime's own +sentence for that op is "this value does not fit the integer type it is cast +to" (=runtime/flan_rt.c:986=). The good sentences exist and go to stderr on an +unhandled stop; the buffer renders the struct generically instead. Either put +the rendered sentence on the wire, or let a condition type carry a printer. +=op= being a bare number is the same gap — it is an enum spelled as =i32=. + +** TODO A backtrace frame names the function, not the call +=fninfo= (=lib/emit.ml:185=) holds one static =loc=, the =defn='s own, and +=flan_frame= (=runtime/flan_dev.c:1011=) adds no per-call location — so two +calls to the same function from one caller are indistinguishable in the stack. +Wants the caller storing its call site into the frame before the call, which is +a field and a store on every dev-build call. + +** TODO The condition buffer cannot jump to the source +It prints the source line and carets for the stop (=flan-cnr.el:197=) and lists +frames, but no key opens the file at that line. Wants RET-on-a-frame, or =M-.=, +and =next-error= over the frame list. + +** TODO loop's bindings should be sequential, like let's +=check_loop= (=lib/check.ml:4741=) checks every initialiser before binding any, +so =(loop [curr-r r next-r (inc curr-r)] ...)= cannot see =curr-r= and the +refusal reads as an unknown name. Every binding form is sequential — there is +no =let*= here and there is not going to be one. Check the other binding forms +for the same gap while fixing it. + +** TODO C-c C-c reports one error, not every error in the form +Whole-file paths use =Check.program_all= and report every bad declaration. The +daemon asks for the sink off (=lib/loc.ml:185=) and gets one exception, so a +function with three bad expressions takes three round trips. The sink is +per-phase; making it per-form would need a resync point inside a body. + +** TODO A session should start before a program compiles +=flan dev= builds the program first, so a =main= that does not compile gives no +session. Want SBCL/nREPL order: empty image, then load a file into it. Needs a +host built with no user program, and a load-file op — the reload machinery +already builds a file as a module. Open: what =flan-rerun= does with no =main=, +and a half-loaded file. =C-c C-k= is taken by the inspector. + +** TODO The daemon buffer is navigable but not coloured +=*flan*= is all plain text. =compilation-minor-mode= is on (=emacs/flan.el:822=) +so =next-error= works, but a minor mode installs no font-lock. Open: whether the +program's output should look different from the compiler's. + ** TODO compilation-mode steps over the notes Nothing sets the skip threshold, so =next-error= walks the errors and steps over the notes, which are still parsed, coloured and clickable. Labelling them as diff --git a/emacs/flan.el b/emacs/flan.el index 3017aa6f..b6e6cd18 100644 --- a/emacs/flan.el +++ b/emacs/flan.el @@ -381,14 +381,13 @@ open, above its prompt, which is where whoever is typing there is looking." ;; ;; Three things had to be settled to build it, and they are settled here. ;; -;; **It displays, it does not select.** A program stops on its own clock, not -;; the editor's: the likeliest moment is in a frame of its own game loop while -;; someone is typing in another buffer. Taking the window would send the next -;; keystrokes somewhere they were not aimed, and `q' in a break buffer is not -;; what a half-typed word wanted to be. So `display-buffer': the buffer -;; appears, point does not move, and the window that had focus keeps it. -;; `flan-break-on-stop' can be set to `focus' by anyone who disagrees, and -;; to nil to go back to the mode line alone. +;; **It selects the window.** A stop is a question, the answer is a restart +;; taken in that buffer, and the next keystroke is aimed there — so going there +;; is what it wanted. This was `display' at first, on the argument that a +;; program stops on its own clock and taking the window would send keystrokes +;; somewhere they were not aimed; in use that argument lost, because every stop +;; ended in the same two keys to get to the buffer anyway. `display' is still +;; there for anyone who prefers it, and nil goes back to the mode line alone. ;; ;; **`(pause)' is not a special case.** It was worth asking — a breakpoint is ;; deliberate where an error is not, so it could be argued it has earned the @@ -409,10 +408,13 @@ open, above its prompt, which is where whoever is typing there is looking." ;; stopped and `C-c C-b' still works, so nothing is lost but the automatic ;; part. -(defcustom flan-break-on-stop 'display +(defcustom flan-break-on-stop 'focus "What to do when the program stops. -`display' shows the break buffer without taking focus, `focus' shows it and -selects its window, and nil leaves it to the mode line and `C-c C-b'." +`focus' shows the break buffer and selects its window, `display' shows it +without taking focus, and nil leaves it to the mode line and `C-c C-b'. + +A stop is the program asking a question, and the answer is a restart taken in +that buffer, so going there is what the next keystroke wants anyway." :type '(choice (const :tag "Show it" display) (const :tag "Show it and go there" focus) (const :tag "Only the mode line" nil)))