next-error stops on a diagnostic's notes, and CFn is drawn as a type

This commit is contained in:
Joseph Ferano 2026-09-25 07:01:36 +07:00
parent 5557594f31
commit 9c0e659209
5 changed files with 50 additions and 9 deletions

View File

@ -1862,10 +1862,12 @@ and a half-loaded file. =C-c C-k= is taken by the inspector.
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
warnings would make them navigable and is refused: a note is not a warning.
** DONE compilation-mode steps over the notes
CLOSED: [2026-09-25]
The daemon buffer and the diagnostics buffer set =compilation-skip-threshold= to
0 locally, so =next-error= stops on a note as well as an error. The user's own
default is left alone. Rules out relabelling a note as a warning to make it
navigable.
* Docs and the repository

View File

@ -235,8 +235,9 @@ reason and is the odd one — it is legal only as the last item of a `def' or a
("\\_<\\([a-zA-Z][a-zA-Z0-9!?*+=<>._-]*/\\)" 1 font-lock-type-face)
;; The types the compiler knows without being told: every primitive in
;; `Types.primitive_names', plus the four applied ones the checker
;; resolves and the function type. `dyn' is lowercase on purpose — it is
;; a primitive beside `i64' and `bool', not a container over something.
;; resolves and the two function types, `Fn' and `CFn'. `dyn' is
;; lowercase on purpose — it is a primitive beside `i64' and `bool', not
;; a container over something.
;; `int' and `float' are builtin aliases for `i32' and `f32'.
;;
;; `Unit' is deliberately absent, though `Types.primitive_names' has it.
@ -245,7 +246,7 @@ reason and is the odd one — it is legal only as the last item of a `def' or a
;; word outright — unit is spelled `()'. Drawing it as a valid type would
;; advertise a spelling the parser rejects, which is the same reason
;; `find-restart' and `await' are left out of `flan--special'.
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|string\\|dyn\\|int\\|float\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|Fn\\)\\_>"
("\\_<\\(?:[iu]\\(?:8\\|16\\|32\\|64\\)\\|f\\(?:32\\|64\\)\\|bool\\|string\\|dyn\\|int\\|float\\|Never\\|Allocator\\|Ptr\\|Option\\|Vec\\|Map\\|C?Fn\\)\\_>"
. font-lock-type-face)
;; A type variable, `$t', which is what a generic `defn' names its
;; parameter types with and what `{:where (ordered? $t)}' constrains.

View File

@ -78,6 +78,15 @@
;; the commands here and requires nothing back.
(require 'flan-mode)
(defun flan--navigable-notes ()
"Make `next-error' stop on a note as well as on an error, in this buffer.
A diagnostic's notes are `file:line:col: note: ...' lines, and `compile'
reads the word `note' as an info message. Its default
`compilation-skip-threshold' of 1 steps over info messages, so the second
location a diagnostic names was clickable but never reached by `next-error'.
Zero skips nothing. A note is not relabelled as a warning to get there."
(setq-local compilation-skip-threshold 0))
(defgroup flan nil
"Talking to a running Flan program."
:group 'flan
@ -821,7 +830,8 @@ It builds the program first, which for a cold project is most of this."
;; program runs, and `compilation-mode' would claim it as the output of
;; one finished command — killing the process on a `recompile', among
;; other things it has no business doing to a live session.
(compilation-minor-mode 1))
(compilation-minor-mode 1)
(flan--navigable-notes))
(make-process
:name "flan-daemon" :buffer buf
:command args
@ -1449,7 +1459,8 @@ no longer wrong."
;; should go there. The minor mode rather than deriving from
;; `compilation-mode', because this buffer is not the output of a command
;; that ran once.
(compilation-minor-mode 1))
(compilation-minor-mode 1)
(flan--navigable-notes))
(defvar-local flan--diagnostics-memory-start nil
"Marker at the start of the memory section, or nil while there is none.

View File

@ -1680,6 +1680,31 @@ stopped program, which is the case where it should fire."
(eq (key-binding (kbd k)) #'flan-macroexpand--not-source))
'("C-c C-c" "C-c C-k" "C-x C-e"))))
;; A diagnostic's note is a second `file:line:col:' line, labelled `note:'.
;; `compile' reads it as an info message, and next-error has to stop on it as
;; well as on the error above it, in both buffers that carry diagnostics.
(message "\nnext-error reaches a note")
(let ((flan-diagnostics-buffer " *test-flan-diag*"))
(with-current-buffer (get-buffer-create flan-diagnostics-buffer)
(flan-diagnostics-mode)
(let ((inhibit-read-only t))
(insert "a.flan:3:5: cannot add a bool to an i64\n"
" ^\n"
"a.flan:1:7: note: the bool was bound here\n"
" -\n"
"b.flan:9:2: the next error\n"))
(goto-char (point-min))
(compilation-next-error 1)
(test-flan--check "from the error, n lands on its note"
(looking-at "a.flan:1:7: note:"))
(compilation-next-error 1)
(test-flan--check "and then on the next error"
(looking-at "b.flan:9:2:"))
(test-flan--check "the threshold is this buffer's, not the user's setting"
(and (local-variable-p 'compilation-skip-threshold)
(eql (default-value 'compilation-skip-threshold) 1))))
(kill-buffer flan-diagnostics-buffer))
;; `flan-mode' itself — indentation, which is a function from text to text and
;; so belongs with the other fixture-driven checks rather than with anything
;; that needs a daemon. Loaded rather than run separately because

View File

@ -425,6 +425,8 @@
("(def v (Vec u8))" "Vec" font-lock-type-face "Vec")
("(declare apply [(Fn [i64] i64)] i64)" "Fn"
font-lock-type-face "Fn")
("(declare call [(CFn [i64] i64)] i64)" "CFn"
font-lock-type-face "CFn")
("(defn seen? [k $t] bool 1)" "$t" font-lock-type-face
"a type variable")
;; The package alias of a qualified name, `clojure-mode''s