A binding ends its let's bindings only when its value ends in an open block, the message names the let's own line, and Emacs offers no binding column after such a value
This commit is contained in:
parent
3d5caf25ae
commit
17ff7cb348
@ -1347,10 +1347,26 @@ whose brackets have closed is no block POS can join."
|
||||
(unless (eql min 0) (push (cons 0 nil) out))
|
||||
(nreverse out)))
|
||||
|
||||
(defun flan-fln--open-ended-p (l)
|
||||
"Non-nil if the joined line L ends in a block still open at its end: a
|
||||
trailing `fn(x) =>', `= match x', `= if c', `x =' or `f():', and not a
|
||||
block lambda inside brackets, whose block closes with them."
|
||||
(let ((last (flan-fln--logical-end l)))
|
||||
(and (flan-fln--opener-p l last)
|
||||
(= (car (save-excursion (syntax-ppss (flan-fln--code-end last))))
|
||||
(car (save-excursion (syntax-ppss (flan-fln--first-char l))))))))
|
||||
|
||||
(defun flan-fln--levels (pos)
|
||||
"Columns TAB offers POS's line outside brackets, deepest first."
|
||||
"Columns TAB offers POS's line outside brackets, deepest first.
|
||||
Not the column of a let's binding whose value ended in an open block: that
|
||||
block ends the let's bindings (lib/indent_reader.ml's `binding_lines'), and
|
||||
the reader refuses any line there."
|
||||
(let* ((prev (flan-fln--prev-code pos))
|
||||
(stack (mapcar #'car (flan-fln--stack pos))))
|
||||
(stack (mapcar #'car
|
||||
(seq-remove (lambda (e)
|
||||
(and (cdr e) (flan-fln--binding-let (cdr e))
|
||||
(flan-fln--open-ended-p (cdr e))))
|
||||
(flan-fln--stack pos)))))
|
||||
(cond
|
||||
;; A lambda's block goes under the line its `=>' ends, which may be a
|
||||
;; line of a call wrapped inside its brackets.
|
||||
|
||||
@ -924,6 +924,14 @@ defconst(k, 3)
|
||||
(test-flan-fln--tabs "fn f()\n let a = 1\n| b = 2" 1) 6)
|
||||
(test-flan-fln--is "at the top level too"
|
||||
(test-flan-fln--tabs "let a = 1\n|" 2) 4)
|
||||
(dolist (c '(("fn f()\n let a = 0\n g = fn(x) =>\n x + 1\n|" (8 2 0) "a lambda's block")
|
||||
("fn f()\n let a = 1\n b = match a\n 1 -> 2\n|" (8 2 0) "a match's arms")
|
||||
("let a = 0\n g = fn(x) =>\n x + 1\n|" (6 0) "a global's lambda block")
|
||||
("fn f()\n let a = 1\n g = map(xs, fn(x) =>\n x + 1)\n|" (6 2 0)
|
||||
"but a lambda's brackets closed, where the column stays")))
|
||||
(test-flan-fln--is (format "no binding column after a binding's open block: %s" (nth 2 c))
|
||||
(test-flan-fln--in (car c) (flan-fln--block-levels (point)))
|
||||
(cadr c)))
|
||||
(test-flan-fln--is "but not after a tab between let and its name"
|
||||
(list (test-flan-fln--tabs "fn f()\n let\ta = 1\n|" 1)
|
||||
(test-flan-fln--tabs "fn f()\n let\ta = 1\n|" 2))
|
||||
|
||||
@ -1704,8 +1704,10 @@ and binding_lines : 'a. ?global:bool -> st -> first:Form.t -> name_col:int -> on
|
||||
let_misaligned t.loc ~let_line:first.loc.Loc.line ~name:(text_of first)
|
||||
~name_col
|
||||
in
|
||||
(* [block] is the binding before this line when its value took the
|
||||
lines under it, which ends the let's bindings. *)
|
||||
(* [block] is the binding before this line when its value ended in a
|
||||
block still open at its end — a trailing [fn(x) =>], [match], [if],
|
||||
[x =] or [f():] — which ends the let's bindings. A block lambda whose
|
||||
brackets close after its block does not. *)
|
||||
let rec go ?block acc =
|
||||
match (peek p).tok with
|
||||
| DEDENT -> ignore (advance p); List.rev acc
|
||||
@ -1715,14 +1717,16 @@ and binding_lines : 'a. ?global:bool -> st -> first:Form.t -> name_col:int -> on
|
||||
| _ when binding_line ~global p ->
|
||||
if (peek p).loc.Loc.col <> name_col then misaligned (peek p);
|
||||
(match block with
|
||||
| Some (name, line) -> let_after_block (peek p).loc ~let_line:line ~name
|
||||
| Some name -> let_after_block (peek p).loc ~let_line:first.loc.Loc.line ~name
|
||||
| None -> ());
|
||||
let i0 = p.i and t0 = peek p in
|
||||
let t0 = peek p in
|
||||
let x = one () in
|
||||
let took = ref false in
|
||||
for k = i0 to p.i - 1 do if p.toks.(k).tok = INDENT then took := true done;
|
||||
go ?block:(if !took then Some (text_of_tok t0, t0.loc.Loc.line) else None)
|
||||
(x :: acc)
|
||||
(* The last token the value took, past its line's end. *)
|
||||
let rec last_real k =
|
||||
if k > 0 && p.toks.(k).tok = NEWLINE then last_real (k - 1) else k
|
||||
in
|
||||
let open_block = p.toks.(last_real (p.i - 1)).tok = DEDENT in
|
||||
go ?block:(if open_block then Some (text_of_tok t0) else None) (x :: acc)
|
||||
| _ -> not_binding ()
|
||||
and not_binding () =
|
||||
failk "let-block" (where_ p)
|
||||
|
||||
@ -206,7 +206,9 @@ Each item: the proposal, then the reason in one line.
|
||||
there, is refused, and so is a tab between `let` and its first name. A
|
||||
binding whose value is a block (`= match x`, a lambda header, `=` and the
|
||||
lines under it) is its let's last; the printer starts a new `let` after
|
||||
one. At the top level each such line is one more global, `(def col i32 …)`,
|
||||
one. A block lambda whose brackets close after its block,
|
||||
`g = map(xs, fn(x) =>` over `x + 1)`, is not: its block is shut when the
|
||||
value ends, and more bindings may follow. At the top level each such line is one more global, `(def col i32 …)`,
|
||||
and may be `name: T` alone as a global's own line may; a pattern there is
|
||||
refused, since a global binds one name. A `let` is otherwise flat: its scope is the rest of its
|
||||
block. To end it early, put it in a `do:` block.
|
||||
|
||||
@ -779,7 +779,17 @@ let () =
|
||||
refuses "a binding after a deeper block" "fn f()\n let g =\n h()\n y = 2\n g"
|
||||
"indent/let-after-block" "after g";
|
||||
refuses "a binding after a later binding's block" "fn f()\n let a = 0\n g = fn(x) =>\n x\n h = 2\n h"
|
||||
"indent/let-after-block" "one more binding of the let on line 3, after g, whose value is the block above it. A binding whose value is a block ends its let's bindings, so this one needs a let of its own, at that let's column:\n\n let h = 2";
|
||||
"indent/let-after-block" "one more binding of the let on line 2, after g, whose value is the block above it. A binding whose value is a block ends its let's bindings, so this one needs a let of its own, at that let's column:\n\n let h = 2";
|
||||
(* A block lambda whose brackets close ends no group: its block is shut
|
||||
when its value ends. *)
|
||||
reads ~global:false "a binding after a later binding's bracketed lambda"
|
||||
"let a = 1\n g = map(xs, fn(x) =>\n x + 1)\n h = 2\nh"
|
||||
"(let [a 1 g (map xs (fn [x] (+ x 1))) h 2] h)";
|
||||
reads ~global:false "a binding after a first binding's bracketed lambda"
|
||||
"let g = map(xs, fn(x) =>\n x + 1)\n h = 2\nh"
|
||||
"(let [g (map xs (fn [x] (+ x 1))) h 2] h)";
|
||||
refuses "a binding after a later binding's match" "fn f()\n let a = 1\n b = match a\n 1 -> 2\n _ -> 3\n c = 4\n c"
|
||||
"indent/let-after-block" "the let on line 2, after b";
|
||||
refuses "a global after a global's block" "let a = 0\n g =\n h()\n b = 2"
|
||||
"indent/let-after-block" "after g";
|
||||
(* Only a line shaped as a binding gets the alignment advice. *)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user