The rejection goes away when you do anything else

An overlay that lasted until the next accepted evaluation was a durable
annotation on the source, which is not what it is: it is feedback about the
action that just failed, and the moment you move, type or evaluate it is
describing a program state nobody is in any more.

pre-command-hook rather than post-command-hook, which fires at the end of
the failing command and would take the overlay down before redisplay ever
drew it. Buffer-local and installed only while an overlay exists, so a
session of twenty buffers does not end up running this on every keystroke
in all of them.
This commit is contained in:
Joseph Ferano 2026-09-12 03:56:41 +07:00
parent 8eb6de15c5
commit c1a612abfb

View File

@ -731,9 +731,27 @@ Compared with `file-equal-p', so a symlinked or relative path still matches."
;; An error is shown where it is rather than only in the echo area, because the
;; echo area is gone the moment you type and the location is the useful half of
;; the message. It is cleared when the next evaluation of that buffer is
;; accepted: an overlay left behind after a fix is a lie about the program, and
;; a stale one is worse than none.
;; the message.
;;
;; It is feedback about the evaluation that just failed and not an annotation
;; on the source, so it lasts exactly as long as that: the next command in that
;; buffer takes it away, whatever the command was — a keystroke, a motion,
;; another evaluation. An overlay that survived until some later evaluation
;; was accepted outlived the thing it was about, and a stale one is worse than
;; none.
;;
;; `pre-command-hook' and not `post-command-hook': the hook has to run before
;; the *next* command, because `post-command-hook' fires at the end of the
;; failing command itself and would take the overlay down before redisplay had
;; ever 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. Globally it would
;; be a hook every buffer in the session runs on every keystroke for the sake
;; of a feature most of them will never use; buffer-locally it is also the
;; behaviour asked for, since the overlay belongs to the buffer the failed
;; evaluation came from and a command somewhere else is not "doing something
;; else in that buffer".
(defface flan-dev-error-face
'((t :inherit error :underline (:style wave)))
@ -749,7 +767,19 @@ Compared with `file-equal-p', so a symlinked or relative path still matches."
"Remove Flan error overlays from BUFFER, or from the current buffer."
(interactive)
(with-current-buffer (or buffer (current-buffer))
(remove-overlays (point-min) (point-max) 'flan-dev-error t)))
(remove-overlays (point-min) (point-max) 'flan-dev-error t)
;; With nothing left to clear there is nothing for the hook to do, and a
;; hook that stays installed after the last overlay is gone is the half of
;; this that quietly accumulates.
(remove-hook 'pre-command-hook #'flan-dev--clear-errors-on-command t)))
(defun flan-dev--clear-errors-on-command ()
"Take this buffer's error overlays down, as a `pre-command-hook'.
Any command at all, because the overlay is about the evaluation that failed
and not about the text: moving, typing and evaluating are all something
else, and an overlay that survived a fix would be pointing at code that is
no longer wrong."
(flan-dev-clear-errors))
(defun flan-dev--show-error (loc msg)
"Mark MSG at LOC, if LOC names a file some buffer is visiting.
@ -771,6 +801,10 @@ Returns non-nil when it put an overlay somewhere."
(overlay-put ov 'after-string
(propertize (concat " " msg)
'face 'flan-dev-error-message-face))
;; Local to this buffer, and installed only now that there is
;; something for it to remove.
(add-hook 'pre-command-hook
#'flan-dev--clear-errors-on-command nil t)
;; Point goes there too, but only in the buffer being looked at:
;; moving point in a buffer nobody is showing is a surprise the
;; next time it is visited.
@ -1079,6 +1113,10 @@ of the tenth name tells you neither how many there were nor which."
(note (plist-get reply :note))
(value (plist-get reply :value)))
;; Accepted, so whatever the last rejection marked is no longer true.
;; Redundant now that any command clears it — the command that ran this
;; evaluation already did — and kept because it is the claim being
;; made, not the mechanism: an accepted evaluation is never left with a
;; rejection drawn over it.
(flan-dev-clear-errors)
;; ...and a name that was just installed should complete, and have a
;; signature, from this moment rather than from the next connect.