A stop takes the window, because the next key is aimed at it

This commit is contained in:
Joseph Ferano 2026-09-22 11:12:53 +07:00
parent 45cc4d20e8
commit 9d7da2ba7a
2 changed files with 60 additions and 13 deletions

View File

@ -1,5 +1,5 @@
#+TITLE: Flan #+TITLE: Flan
#+TODO: TODO NEXT WAIT | DONE CANCELLED #+TODO: TODO WAIT | DONE CANCELLED
#+ARCHIVE: ::* Archive #+ARCHIVE: ::* Archive
Every decision, open question and known gap, one =**= heading each under the 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, static side does not pay for the dynamic side. Rejected names: Closure, Proc, Fun,
Func, Fnptr. 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 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 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 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 error pattern, so anyone who wants one has the four lines, and the manual carries
them. 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 ** TODO compilation-mode steps over the notes
Nothing sets the skip threshold, so =next-error= walks the errors and steps over 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 the notes, which are still parsed, coloured and clickable. Labelling them as

View File

@ -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. ;; 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 ;; **It selects the window.** A stop is a question, the answer is a restart
;; the editor's: the likeliest moment is in a frame of its own game loop while ;; taken in that buffer, and the next keystroke is aimed there — so going there
;; someone is typing in another buffer. Taking the window would send the next ;; is what it wanted. This was `display' at first, on the argument that a
;; keystrokes somewhere they were not aimed, and `q' in a break buffer is not ;; program stops on its own clock and taking the window would send keystrokes
;; what a half-typed word wanted to be. So `display-buffer': the buffer ;; somewhere they were not aimed; in use that argument lost, because every stop
;; appears, point does not move, and the window that had focus keeps it. ;; ended in the same two keys to get to the buffer anyway. `display' is still
;; `flan-break-on-stop' can be set to `focus' by anyone who disagrees, and ;; there for anyone who prefers it, and nil goes back to the mode line alone.
;; to nil to go back to the mode line alone.
;; ;;
;; **`(pause)' is not a special case.** It was worth asking — a breakpoint is ;; **`(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 ;; 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 ;; stopped and `C-c C-b' still works, so nothing is lost but the automatic
;; part. ;; part.
(defcustom flan-break-on-stop 'display (defcustom flan-break-on-stop 'focus
"What to do when the program stops. "What to do when the program stops.
`display' shows the break buffer without taking focus, `focus' shows it and `focus' shows the break buffer and selects its window, `display' shows it
selects its window, and nil leaves it to the mode line and `C-c C-b'." 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) :type '(choice (const :tag "Show it" display)
(const :tag "Show it and go there" focus) (const :tag "Show it and go there" focus)
(const :tag "Only the mode line" nil))) (const :tag "Only the mode line" nil)))