A defining form written as the fallback call in a .fln buffer draws its head as a keyword and its name as a definition, and imenu lists it.

This commit is contained in:
Joseph Ferano 2026-09-26 05:14:11 +07:00
parent 72c73117d6
commit 3f4e5a930f
2 changed files with 78 additions and 1 deletions

View File

@ -1526,6 +1526,29 @@ it, so a block pasted at another depth stays one block."
(defconst flan-fln--name-re "\\([^][ \t\n(){},;\":]+\\)"
"A declared name: a run up to a bracket, a space, or the colon of `x: T'.")
;; A defining form written as the fallback call, `defmacro(m, [x]):' or
;; `defmethod(area, point, [p]):'. The heads are `flan-mode''s own, so a
;; head it learns is drawn here too; its name is drawn as the sugar draws the
;; same kind of name.
(defconst flan-fln--fallback-type-heads
(seq-filter (lambda (h) (member h '("defstruct" "defdata" "defunion" "defenum"
"defalias" "defclass")))
flan--definers))
(defconst flan-fln--fallback-variable-heads
(seq-filter (lambda (h) (member h '("def" "defonce" "defconst"))) flan--definers))
(defconst flan-fln--fallback-function-heads
(seq-remove (lambda (h) (or (member h flan-fln--fallback-type-heads)
(member h flan-fln--fallback-variable-heads)
(member h '("defmacro" "import" "package"
"declare" "declare-c"))))
flan--definers)
"The fallback heads that define something called, for imenu.")
(defun flan-fln--fallback-re (heads)
(concat "^" (regexp-opt heads t) "(" flan-fln--name-re))
(defun flan-fln--return-type-matcher (limit)
"Find the next return type up to LIMIT: after the `->' of a fn header, a
lambda or a `Fn(...)' type, and not after a match arm's."
@ -1565,6 +1588,17 @@ lambda or a `Fn(...)' type, and not after a match arm's."
;; An alias's type, `type Row = Vec(i32)'.
(,(concat "^type[ \t]+[^][ \t\n(){},;\":]+[ \t]+=[ \t]+" flan-fln--name-re)
1 font-lock-type-face)
;; A defining form as the fallback call: the head a keyword, its first
;; argument the name it defines.
(,(flan-fln--fallback-re flan-fln--fallback-type-heads)
(1 font-lock-keyword-face) (2 font-lock-type-face))
(,(flan-fln--fallback-re flan-fln--fallback-variable-heads)
(1 font-lock-keyword-face) (2 font-lock-variable-name-face))
(,(flan-fln--fallback-re
(seq-remove (lambda (h) (or (member h flan-fln--fallback-type-heads)
(member h flan-fln--fallback-variable-heads)))
flan--definers))
(1 font-lock-keyword-face) (2 font-lock-function-name-face))
;; A condition's parent, `struct DiskFull :parent IoError'.
(,(concat "^struct[ \t]+[^][ \t\n(){},;\":]+[ \t]+:parent[ \t]+" flan-fln--name-re)
1 font-lock-type-face)
@ -1602,9 +1636,12 @@ lambda or a `Fn(...)' type, and not after a match arm's."
(defvar flan-fln-imenu-generic-expression
`(("Functions" ,(concat "^fn-?[ \t]+" flan-fln--name-re) 1)
("Functions" ,(flan-fln--fallback-re flan-fln--fallback-function-heads) 2)
("Macros" ,(concat "^\\(?:macro[ \t]+\\|defmacro(\\)" flan-fln--name-re) 1)
("Types" ,(concat "^\\(?:struct\\|data\\|union\\|enum\\|type\\)[ \t]+" flan-fln--name-re) 1)
("Variables" ,(concat "^\\(?:def\\|once\\|const\\)[ \t]+" flan-fln--name-re) 1))
("Types" ,(flan-fln--fallback-re flan-fln--fallback-type-heads) 2)
("Variables" ,(concat "^\\(?:def\\|once\\|const\\)[ \t]+" flan-fln--name-re) 1)
("Variables" ,(flan-fln--fallback-re flan-fln--fallback-variable-heads) 2))
"Imenu index for `flan-fln-mode'.")
(defun flan-fln-current-defun-name ()

View File

@ -768,6 +768,46 @@ fn gcd(a: i32, b: i32) -> i32
(test-flan--check "imenu lists the macro"
(assoc "repeat" (cdr (assoc "Macros" (imenu--generic-function
imenu-generic-expression)))))))
(test-flan-fln--in "defmacro(m, [x]):
quote
~x
defmethod(area, point, [p]):
0
defclass(Shape, [w dyn]):
defstruct(Io, :parent, Error, [])
defconst(k, 3)
"
(font-lock-ensure)
(let ((face (lambda (needle)
(save-excursion (goto-char (point-min)) (search-forward needle)
(get-text-property (match-beginning 0) 'face)))))
(dolist (c '(("defmacro" m font-lock-function-name-face)
("defmethod" area font-lock-function-name-face)
("defclass" Shape font-lock-type-face)
("defstruct" Io font-lock-type-face)
("defconst" k font-lock-variable-name-face)))
(test-flan-fln--is (format "a fallback %s's head is a keyword" (car c))
(funcall face (concat (car c) "(")) 'font-lock-keyword-face)
(test-flan-fln--is (format "and the name it defines, %s" (cadr c))
(save-excursion
(goto-char (point-min))
(search-forward (concat (car c) "("))
(get-text-property (point) 'face))
(nth 2 c))))
(let ((index (imenu--generic-function flan-fln-imenu-generic-expression)))
(test-flan--check "imenu lists a fallback defmacro"
(assoc "m" (cdr (assoc "Macros" index))))
(test-flan--check "a fallback defmethod"
(assoc "area" (cdr (assoc "Functions" index))))
(test-flan--check "a fallback defclass and defstruct"
(and (assoc "Shape" (cdr (assoc "Types" index)))
(assoc "Io" (cdr (assoc "Types" index)))))
(test-flan--check "and a fallback defconst"
(assoc "k" (cdr (assoc "Variables" index))))))
(test-flan-fln--in "fn far(a: i64,\n b: i64) -> Point\n match a\n Some(x) -> Other\n"
(font-lock-ensure)
(let ((face (lambda (needle)