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 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. program's output should look different from the compiler's.
** TODO compilation-mode steps over the notes ** DONE compilation-mode steps over the notes
Nothing sets the skip threshold, so =next-error= walks the errors and steps over CLOSED: [2026-09-25]
the notes, which are still parsed, coloured and clickable. Labelling them as The daemon buffer and the diagnostics buffer set =compilation-skip-threshold= to
warnings would make them navigable and is refused: a note is not a warning. 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 * 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) ("\\_<\\([a-zA-Z][a-zA-Z0-9!?*+=<>._-]*/\\)" 1 font-lock-type-face)
;; The types the compiler knows without being told: every primitive in ;; The types the compiler knows without being told: every primitive in
;; `Types.primitive_names', plus the four applied ones the checker ;; `Types.primitive_names', plus the four applied ones the checker
;; resolves and the function type. `dyn' is lowercase on purpose — it is ;; resolves and the two function types, `Fn' and `CFn'. `dyn' is
;; a primitive beside `i64' and `bool', not a container over something. ;; 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'. ;; `int' and `float' are builtin aliases for `i32' and `f32'.
;; ;;
;; `Unit' is deliberately absent, though `Types.primitive_names' has it. ;; `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 ;; word outright — unit is spelled `()'. Drawing it as a valid type would
;; advertise a spelling the parser rejects, which is the same reason ;; advertise a spelling the parser rejects, which is the same reason
;; `find-restart' and `await' are left out of `flan--special'. ;; `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) . font-lock-type-face)
;; A type variable, `$t', which is what a generic `defn' names its ;; A type variable, `$t', which is what a generic `defn' names its
;; parameter types with and what `{:where (ordered? $t)}' constrains. ;; parameter types with and what `{:where (ordered? $t)}' constrains.

View File

@ -78,6 +78,15 @@
;; the commands here and requires nothing back. ;; the commands here and requires nothing back.
(require 'flan-mode) (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 (defgroup flan nil
"Talking to a running Flan program." "Talking to a running Flan program."
:group 'flan :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 ;; program runs, and `compilation-mode' would claim it as the output of
;; one finished command — killing the process on a `recompile', among ;; one finished command — killing the process on a `recompile', among
;; other things it has no business doing to a live session. ;; other things it has no business doing to a live session.
(compilation-minor-mode 1)) (compilation-minor-mode 1)
(flan--navigable-notes))
(make-process (make-process
:name "flan-daemon" :buffer buf :name "flan-daemon" :buffer buf
:command args :command args
@ -1449,7 +1459,8 @@ no longer wrong."
;; should go there. The minor mode rather than deriving from ;; should go there. The minor mode rather than deriving from
;; `compilation-mode', because this buffer is not the output of a command ;; `compilation-mode', because this buffer is not the output of a command
;; that ran once. ;; that ran once.
(compilation-minor-mode 1)) (compilation-minor-mode 1)
(flan--navigable-notes))
(defvar-local flan--diagnostics-memory-start nil (defvar-local flan--diagnostics-memory-start nil
"Marker at the start of the memory section, or nil while there is none. "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)) (eq (key-binding (kbd k)) #'flan-macroexpand--not-source))
'("C-c C-c" "C-c C-k" "C-x C-e")))) '("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 ;; `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 ;; so belongs with the other fixture-driven checks rather than with anything
;; that needs a daemon. Loaded rather than run separately because ;; 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") ("(def v (Vec u8))" "Vec" font-lock-type-face "Vec")
("(declare apply [(Fn [i64] i64)] i64)" "Fn" ("(declare apply [(Fn [i64] i64)] i64)" "Fn"
font-lock-type-face "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 ("(defn seen? [k $t] bool 1)" "$t" font-lock-type-face
"a type variable") "a type variable")
;; The package alias of a qualified name, `clojure-mode''s ;; The package alias of a qualified name, `clojure-mode''s