The manual says how a form is indented, and NEXT loses what landed

The indentation rules were written and tested but never described anywhere a
user would look. MANUAL.md had no section on editing at all — it starts at
`C-c C-c' and assumes the file is already written — so the rule that cost the
friction, a binding vector lining up name under name, was only visible by
trying it.

What is written down is what was checked, not what the port was aimed at: the
call fallback, the `handler-bind' clause vector, `defn' parameter alignment
with a return type after it, and `restart-case' clause bodies were each
reindented from scratch and the manual quotes the result.

NEXT.md keeps the half of the field-label handover that is still open. The
printer in render.ml has to move in the same commit as the inspector that
parses it, and that is the inspector lane's; the font-lock half is done here,
so only that half is struck.
This commit is contained in:
Joseph Ferano 2026-09-12 16:15:37 +07:00
parent c9e9d93a91
commit 64342c406e
2 changed files with 54 additions and 6 deletions

17
NEXT.md
View File

@ -286,9 +286,11 @@ BUILT.md, "The colon belongs to keys".
**What it left for the Emacs lane, both verified.** `render.ml` still *prints* a struct with colons, deliberately: **What it left for the Emacs lane, both verified.** `render.ml` still *prints* a struct with colons, deliberately:
`emacs/flan-inspect.el:165` parses that output and hard-codes the colon when it reads a field out, so the printer `emacs/flan-inspect.el:165` parses that output and hard-codes the colon when it reads a field out, so the printer
has to move in the same commit as its reader. And `flan-mode.el:61` font-locks `:name` as a constant with nothing has to move in the same commit as its reader. That half is still open and belongs with whoever next opens the
matching `.name`, so a field label is now unfontified where it used to be coloured. Neither is urgent; both belong inspector. ~~And `flan-mode.el:61` font-locks `:name` as a constant with nothing matching `.name`, so a field label
with whoever next opens `emacs/`. is now unfontified where it used to be coloured.~~ **The font-lock half is done:** a field is drawn as a constant in
both of the spellings that exist while the corpus moves, so `{.x 1}` and the accessor `(.x v)` read alike, and the
keyword rule stayed where it was because the colon still means an enum member and a map key.
**7. `Map` follows Odin's implementation.** Read `base/runtime/dynamic_map_internal.odin` before writing any of it; **7. `Map` follows Odin's implementation.** Read `base/runtime/dynamic_map_internal.odin` before writing any of it;
the checkout is at `~/Repositories/Odin`. Three properties are the ones worth copying, and they are stated in its own the checkout is at `~/Repositories/Odin`. Three properties are the ones worth copying, and they are stated in its own
@ -423,9 +425,12 @@ run one lane at a time; item 4 is disjoint and runs alongside any of them.
whole of the resource-cleanup answer. whole of the resource-cleanup answer.
4. **The Emacs batch. Disjoint from the compiler, so it runs in parallel with anything above.** Globals in the break 4. **The Emacs batch. Disjoint from the compiler, so it runs in parallel with anything above.** Globals in the break
buffer; the buffer opening itself when the program stops; the indentation rewrite with `clojure-mode` as the buffer; the buffer opening itself when the program stops; ~~the indentation rewrite with `clojure-mode` as the
reference; `#_`; hex, binary and addresses on primitives in the inspector. The indentation one is worth doing first reference~~; ~~`#_`~~; hex, binary and addresses on primitives in the inspector. **The indentation rewrite and `#_`
within this batch — it costs friction on every keystroke today. are done.** The indenter is ported from `clojure-mode`'s source rather than derived from it — `flan-mode` still
requires nothing outside stock Emacs — and it aligns a binding vector name-under-name, which is the bug that cost
friction on every keystroke. `defn` parameter lists and `restart-case` clause parameters were the same shape and
came with it. What remains in this batch is the break buffer and the inspector, and they are independent.
5. **Union values, then the macro expander, then `Result`/`try`.** Promoted above `Handle` on the author's call — 5. **Union values, then the macro expander, then `Result`/`try`.** Promoted above `Handle` on the author's call —
macros are the thing most worth wanting, and unions are the only thing between here and them. macros are the thing most worth wanting, and unions are the only thing between here and them.

View File

@ -263,6 +263,49 @@ the inner binding.
--- ---
## Writing it
`TAB` indents the line, and `C-M-q` the form under point. The rules are ported
from `clojure-mode`'s, because Clojure has the shapes Flan has and Emacs Lisp
does not — vectors that bind, bracket variety, and keys inside braces.
**A binding vector lines up name under name.** The second and later bindings of a
`let` sit under the first one's *name*, not under its value:
```
(let [vel (+ gravity (at velocity row col))
y (min (- rows 1) (+ row (i32 vel)))]
…)
```
The same rule draws `defn` parameter lists, `restart-case` and `handler-bind`
clause parameters, and both spellings of a struct literal — they are all a vector
or a brace read in pairs, so they are all indented as one.
**A body indents two.** `let`, `if`, `when`, `while`, `match`, `restart-case`,
`handler-bind`, `defn` and the `def…` forms all put their body two columns in
from the head. What differs between them is only how many forms come *before*
the body and stay on the head's line — a `let`'s binding vector, an `if`'s test,
a `restart-case`'s protected form — and the indenter knows that count per form.
A form it has no entry for is treated as a call: the arguments line up under the
first argument, not two in. That is the fallback, and it is what you want for
`(rl/draw-rectangle x y w h)` and for every function you write.
`defn` carries a return type between the parameter vector and the body, and it is
optional. The indenter does not need to know which — everything after the head
indents two, which is the right answer for the name, the parameters, a return type
if one is written, and the body alike.
**A field is drawn as a constant**, in the accessor `(.x v)` and as a label in
`{.x 1.0}`. The colon is still a constant too; it means an enum member, `:green`,
and a key in a map.
Nothing here needs a running program. Indentation and colouring are the major
mode's, so they work in a file you have only opened.
---
## Getting around ## Getting around
| Key | Does | | Key | Does |