In a .fln buffer a closer-led line inside open brackets goes to the bracket's continuation column, save the closer of a lambda's block

This commit is contained in:
Joseph Ferano 2026-09-26 06:20:55 +07:00
parent f91ed8ad27
commit 04b29f283d
4 changed files with 30 additions and 11 deletions

View File

@ -652,11 +652,6 @@ after it (so a second block lambda, or one not last) is refused, and the fix nam
Held 2026-09-26 by the author: F#-style ~f x y~ or Nim-style one-argument calls
without parentheses. Collides with space-separated vector and index elements.
** TODO RET inside an open call puts the closer at the statement's column
In a .fln buffer, ~if and(state.paused|)~ then RET leaves ~)~ at the ~if~'s column, so
the next argument cannot be typed where it belongs. A line inside open brackets,
closer-led or not, goes to the continuation column (aligned after the opening bracket).
** NEXT A let takes several bindings on indented lines
Decided 2026-09-26: lines indented under a ~let~ that are ~name = v~ or ~name: T = v~ are
more bindings of the same let; anything else there stays refused. flan convert writes

View File

@ -1205,7 +1205,7 @@ Use `C-c C-g` if you need frames.
| `M-a` / `M-e` | `(` / `)` | statement: start / end (`)`: start of the next) |
| `C-M-u` | same | up to the enclosing bracket, or the line that owns the block |
| `C-M-f` / `C-M-b` | same | brackets and terms, as everywhere |
| `TAB` | same | a line at a valid column stays; an empty or misplaced line goes deepest; each repeat steps out a level. One level deeper only after a line that opens a block: never after a `let`, unless its value goes on under it (`= match x`, `= if c`, `= loop i = 0`, a lambda header). After a line ending in `=>`, one level in from that line, inside brackets too; a line of that block keeps to the block's columns |
| `TAB` | same | a line at a valid column stays; an empty or misplaced line goes deepest; each repeat steps out a level. One level deeper only after a line that opens a block: never after a `let`, unless its value goes on under it (`= match x`, `= if c`, `= loop i = 0`, a lambda header). After a line ending in `=>`, one level in from that line, inside brackets too; a line of that block keeps to the block's columns. Inside open brackets, under the first element after the opener, or one level in from the opener's line when it ends that line; a line that starts with the closer goes there too, so `RET` in `and(a|)` leaves room for the next argument. The closer of a bracket that holds a lambda's block goes to the call's column |
| `DEL` in indentation | same | drop one level |
| `C-c <` / `C-c >` | `<` / `>` | shift the region's lines a level |
| `M-<up>` / `M-<down>` | same | move the statement past its neighbour |

View File

@ -1338,14 +1338,32 @@ brackets, which the reader refuses."
(car e))))
(flan-fln--stack pos)))))
(defun flan-fln--holds-block-p (open pos)
"Non-nil if a line between OPEN and POS's line ends in a `=>' directly
inside the bracket at OPEN: a lambda's block the bracket holds."
(save-excursion
(let ((bol (flan-fln--bol pos)) hit)
(goto-char open)
(while (and (not hit) (< (line-end-position) bol))
(let ((end (flan-fln--code-end (point))))
(goto-char end)
(when (and (looking-back "[ \t]=>" (line-beginning-position))
(eql (nth 1 (save-excursion (syntax-ppss (- end 2)))) open))
(setq hit t)))
(forward-line 1))
hit)))
(defun flan-fln--bracket-column (open)
"The column a line inside the bracket at OPEN goes to.
Under the first element when one follows the bracket on its line, one level
in from that line when none does -- the paren mode's rule for data and
calls alike. A line that starts with the closing bracket goes to the
opening line's column."
calls alike. A line that starts with the closing bracket goes there too, so
RET before the `)' of `and(a|)' leaves room to type the next argument where
it belongs. The one exception is the closer of a bracket that holds a
lambda's block: it ends that block, and goes to the opening line's column."
(save-excursion
(let ((closing (save-excursion (back-to-indentation) (looking-at "\\s)"))))
(let ((closing (and (save-excursion (back-to-indentation) (looking-at "\\s)"))
(flan-fln--holds-block-p open (point)))))
(goto-char open)
(if closing
(current-indentation)

View File

@ -866,8 +866,14 @@ defconst(k, 3)
(test-flan-fln--tabs " paint-at(i32(m.y) / cell-size,\n|i32(m.x))" 1) 11)
(test-flan-fln--is "inside a bracket with nothing after it, one level in"
(test-flan-fln--tabs " let v = [\n|1 2]" 1) 4)
(test-flan-fln--is "a closing bracket, at its opening line's column"
(test-flan-fln--tabs " let v = [\n 1 2\n|]" 1) 2)
(test-flan-fln--is "a closing bracket, at the bracket's own column"
(test-flan-fln--tabs " let v = [\n 1 2\n|]" 1) 4)
(test-flan-fln--is "a closer after RET in an open call, under the first argument"
(test-flan-fln--tabs " if and(state.paused\n|)" 1) 9)
(test-flan-fln--in "fn f()\n if and(state.paused|)\n"
(newline-and-indent)
(test-flan-fln--is "RET before the closer puts it under the first argument"
(list (current-indentation) (char-after)) '(9 ?\))))
(test-flan-fln--is "after a line ending in an operator, deeper than its statement"
(test-flan-fln--tabs " if a and\n|b" 1) 4)
(test-flan-fln--is "never deeper after a let"