As part of #218, I've been digging in to the code fsharp-mode uses to compute indentation. This is a fairly complicated topic, including regexen for keyword detection, predicate functions, and motion functions. In particular, I've found a set of problems with fsharp-statement-opens-block-p and fsharp-goto-beyond-final-line. This goes like so:
fsharp-statement-opens-block-p needs to compute whether or not the current statement creates a new block or not. To do this, it searches between the current value of point, and an endpoint called finish. finish is set to the value of fsharp-goto-beyond-final-line.
fsharp-goto-beyond-final-line claims to go to the line after the end of "the current statement."[^1]
fsharp-goto-beyond-final-line uses a while loop and-ing on fsharp-continuation-line-p.
fsharp-continuation-line-ponly considers a line a "continuation line" if it either 1) ends in a dangling arithmetic operator or 2) point is inside a block delimited by a pair (i.e. point is inside [] or {}). This means the function almost always goes one line forward, then returns point at that position.
fsharp-statement-opens-block-pimmediately adjusts the value returned from fsharp-continuation-line-p by subtracting 1.
To summarize:
fsharp-statement-opens-block-p is taking an incredibly convoluted approach to searching until end of same line. This might be correct, but there are no previously existing tests.
fsharp-goto-beyond-final-line definitely does no such thing. (Again, no tests.)
fsharp-continuation-line-p is being used when we likely want a slightly different function.
For example, let x = 5 + is a "continuation line", but type Shape = is not.
(As a final, frustrating note, F# does not, in fact, have statements, at all.)
Proposed Solutions
fsharp-statement-opens-block-p needs to reliably return whether or not the statement (which is to say, expression) opens a block. It is used all over the place, so should be well documented, and under test. (Also, the name should be changed to use "expression" over "statement".)
fsharp-goto-beyond-final-line should do so, and be under test. I assert we need a function similar to, but distinct from, fsharp-continuation-line-p. Something like fsharp-in-block-p -- "tell me if this line could be considered part of an ongoing block." Right now, there is no code to detect this -- it's handled in fsharp-compute-indentation as the final default "fall-through" case, so lacks a proper predicate. We should probably have one!
Footnotes
[^1] Note that if #223 has been merged, this will say "the current expression."
Description
As part of #218, I've been digging in to the code
fsharp-mode
uses to compute indentation. This is a fairly complicated topic, including regexen for keyword detection, predicate functions, and motion functions. In particular, I've found a set of problems withfsharp-statement-opens-block-p
andfsharp-goto-beyond-final-line
. This goes like so:fsharp-statement-opens-block-p
needs to compute whether or not the current statement creates a new block or not. To do this, it searches between the current value ofpoint
, and an endpoint calledfinish
.finish
is set to the value offsharp-goto-beyond-final-line
.fsharp-goto-beyond-final-line
claims to go to the line after the end of "the current statement."[^1]fsharp-goto-beyond-final-line
uses a while loopand
-ing onfsharp-continuation-line-p
.fsharp-continuation-line-p
only considers a line a "continuation line" if it either 1) ends in a dangling arithmetic operator or 2) point is inside a block delimited by a pair (i.e. point is inside[]
or{}
). This means the function almost always goes one line forward, then returnspoint
at that position.fsharp-statement-opens-block-p
immediately adjusts the value returned fromfsharp-continuation-line-p
by subtracting1
.To summarize:
fsharp-statement-opens-block-p
is taking an incredibly convoluted approach to searching until end of same line. This might be correct, but there are no previously existing tests.fsharp-goto-beyond-final-line
definitely does no such thing. (Again, no tests.)fsharp-continuation-line-p
is being used when we likely want a slightly different function.For example,
let x = 5 +
is a "continuation line", buttype Shape =
is not.(As a final, frustrating note, F# does not, in fact, have statements, at all.)
Proposed Solutions
fsharp-statement-opens-block-p
needs to reliably return whether or not the statement (which is to say, expression) opens a block. It is used all over the place, so should be well documented, and under test. (Also, the name should be changed to use "expression" over "statement".)fsharp-goto-beyond-final-line
should do so, and be under test. I assert we need a function similar to, but distinct from,fsharp-continuation-line-p
. Something likefsharp-in-block-p
-- "tell me if this line could be considered part of an ongoing block." Right now, there is no code to detect this -- it's handled infsharp-compute-indentation
as the final default "fall-through" case, so lacks a proper predicate. We should probably have one!Footnotes
[^1] Note that if #223 has been merged, this will say "the current expression."