diff --git a/TODO.org b/TODO.org index 8633ec77..ea4ee6f5 100644 --- a/TODO.org +++ b/TODO.org @@ -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 diff --git a/emacs/MANUAL.md b/emacs/MANUAL.md index 6f044e41..3db7b4f1 100644 --- a/emacs/MANUAL.md +++ b/emacs/MANUAL.md @@ -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-` / `M-` | same | move the statement past its neighbour | diff --git a/emacs/flan-fln-mode.el b/emacs/flan-fln-mode.el index 96e0c01c..260ac514 100644 --- a/emacs/flan-fln-mode.el +++ b/emacs/flan-fln-mode.el @@ -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) diff --git a/emacs/test-flan-fln.el b/emacs/test-flan-fln.el index 1a69fbd1..05d5b995 100644 --- a/emacs/test-flan-fln.el +++ b/emacs/test-flan-fln.el @@ -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"