Question 1 - Number of spaces per indentation
4?
By the way, you will see in some examples that even if we pick a specific
indentation, we might also have a smaller indentation, or so it seems (nested brackets,
Question 4)
Question 2 - Page Width
I currently have a 100-column page width. Do we want this? 100? 90? 80?
The reason I'm using PrettyExpressive is that other formatters also use similar
pretty-printing algorithms, notably the Wadler-Leijen Algorithm and its
functional variant, Strictly Pretty. In this family of pretty-printing
algorithms, there is a page width, and the algorithm can make the code look
pretty within the page width, but if needed, let it go beyond the page
width and care less about the prettiness.
Some tools, like Golang's "go fmt" don't do this. They honor the line breaks
of the author. If the author wants very long lines, so be it.
"go fmt" isn't producing canonical output, it's just adjusting
the author's formatting to make it nicer.
Since we do want canonical output, we have to enforce a canonical way of
where to break lines. And thus, we need a page width.
The simplest example of this is is Gren's "module" line. If the "exposing" list is short
and can fit in the page width, we can render it on one line.
module Geometry exposing ( Point, area, perimeter )
But if it's long, we can render it in the multi-line format.
module Geometry exposing
( Point
, Shape
, Circle
, Rectangle
, computeArea
, computePerimeter
, scaleShape
, translateShape
, rotateShape
)
But also, as an example, a function call that is short stays on one line:
result = renderWidget header content footer
while one that is long enough to reach the page boundary wraps, and its
overflow arguments indent one tab stop:
result =
renderWidget mainContainerElement headerSectionElement navigationBarElement contentAreaElement
footerSectionElement
Question 3 - Multi-line "if" predicates
If we are going to have a page width boundary, and thus long expressions
do wrap, how shall we render if/then expression with long "if" predicates?
Example of a short predicate:
if callSomeFunction then
runTrue
else
runFalse
Example of a long predicate, indented to the same level as the body:
if (callSomeFunction with lots of arguments that need to
wrap the line) then
runTrue
else
runFalse
Example of a long predicate, indented to an extra tab-stop, to be visually
different from the body:
if (callSomeFunction with lots of arguments that need to
wrap the line) then
runTrue
else
runFalse
This last example is what the formatter is currently doing.
It turns out the wrapping can happen such that the "then" is by itself on a
line. The then is pushed to a line of its own, indented one
extra step (+8) past the branch body (+4):
ifLong x =
if conditionOne x && conditionTwo x && conditionThree x && conditionFour x && conditionFive x
then
trueBranchResult
else
falseBranchResult
Is a dangling then the layout we want, or should the then kept attached to the last predicate line?
Question 4 - Indentation of nested brackets
It can appear that nested brackets have 2-space tab stops instead of 4. The
outer [ and its item separators , sit at one tab stop (column 5 here), but
because each item begins with [ / , (two characters), an item that is
itself a bracketed block lines its {, , and } up two columns further in
(column 7) — so the inner brackets read as a 2-space indent rather than 4.
shapes =
[ { name = "circle"
, numberOfSides = 0
, isFilled = True
, colorValue = "crimson"
, strokeWidth = 2
}
, { name = "triangle"
, numberOfSides = 3
, isFilled = False
, colorValue = "cornflowerblue"
, strokeWidth = 1
}
]
Is this okay? Or is another rendering better?
By the way, each item also decides independently whether it fits, so a short item can stay
inline while a longer sibling breaks
shapes =
[ { name = "circle", numberOfSides = 0, isFilled = True, colorValue = "red", strokeWidth = 2 }
, { name = "triangle"
, numberOfSides = 3
, isFilled = False
, colorValue = "blue"
, strokeWidth = 1
}
]
Question 5 - Multi-line block comments are re-indented
The body of a multi-line block comment is re-indented from the comment's own
structure: the shallowest body line is aligned three columns past the {-
(under the first character after {- ), and any deeper line keeps its extra
indentation relative to that.
This is straight-forward. However the body was written:
config =
{- the body of this block comment
spans several lines
and is re-indented -}
42
it comes out anchored to the {-, independent of the original columns:
config =
{- the body of this block comment
spans several lines
and is re-indented -}
42
However, there are cases where the 2nd line (and beyond) of the multi-line
comment start at a column before the "{-".
Here the opener is indented but the body lines start flush at the left margin:
config =
{- this comment opener is indented
but the body lines are written flush at the left margin
and this one is a little deeper -}
42
The body is still pulled in and anchored three columns past the {-, with the
deeper line kept deeper:
config =
{- this comment opener is indented
but the body lines are written flush at the left margin
and this one is a little deeper -}
42
Is this what we want? or, do we keep the comments at the absolute starting
column position at which the author wrote them?
Question 6 - Binop chains break strangely
Here is something I just noticed.
A binop chain that overflows breaks the first operand(s) onto their own lines but
then leaves the remaining operands crammed onto one line, with operators at the
seed column (not indented):
binopChain =
operandOne
+ operandTwo
+ operandThree + operandFour + operandFive + operandSix + operandSeven + operandEight
I think this should change to look more like how a long function call wraps:
binopChain =
operandOne + operandTwo operandThree + operandFour + operandFive + operandSix
+ operandSeven + operandEight
or
binopChain =
operandOne + operandTwo operandThree + operandFour + operandFive + operandSix +
operandSeven + operandEight
Where does the binop go?
Question 1 - Number of spaces per indentation
4?
By the way, you will see in some examples that even if we pick a specific
indentation, we might also have a smaller indentation, or so it seems (nested brackets,
Question 4)
Question 2 - Page Width
I currently have a 100-column page width. Do we want this? 100? 90? 80?
The reason I'm using PrettyExpressive is that other formatters also use similar
pretty-printing algorithms, notably the Wadler-Leijen Algorithm and its
functional variant, Strictly Pretty. In this family of pretty-printing
algorithms, there is a page width, and the algorithm can make the code look
pretty within the page width, but if needed, let it go beyond the page
width and care less about the prettiness.
Some tools, like Golang's "go fmt" don't do this. They honor the line breaks
of the author. If the author wants very long lines, so be it.
"go fmt" isn't producing canonical output, it's just adjusting
the author's formatting to make it nicer.
Since we do want canonical output, we have to enforce a canonical way of
where to break lines. And thus, we need a page width.
The simplest example of this is is Gren's "module" line. If the "exposing" list is short
and can fit in the page width, we can render it on one line.
But if it's long, we can render it in the multi-line format.
But also, as an example, a function call that is short stays on one line:
while one that is long enough to reach the page boundary wraps, and its
overflow arguments indent one tab stop:
Question 3 - Multi-line "if" predicates
If we are going to have a page width boundary, and thus long expressions
do wrap, how shall we render if/then expression with long "if" predicates?
Example of a short predicate:
Example of a long predicate, indented to the same level as the body:
Example of a long predicate, indented to an extra tab-stop, to be visually
different from the body:
This last example is what the formatter is currently doing.
It turns out the wrapping can happen such that the "then" is by itself on a
line. The
thenis pushed to a line of its own, indented oneextra step (
+8) past the branch body (+4):Is a dangling
thenthe layout we want, or should thethenkept attached to the last predicate line?Question 4 - Indentation of nested brackets
It can appear that nested brackets have 2-space tab stops instead of 4. The
outer
[and its item separators,sit at one tab stop (column 5 here), butbecause each item begins with
[/,(two characters), an item that isitself a bracketed block lines its
{,,and}up two columns further in(column 7) — so the inner brackets read as a 2-space indent rather than 4.
Is this okay? Or is another rendering better?
By the way, each item also decides independently whether it fits, so a short item can stay
inline while a longer sibling breaks
Question 5 - Multi-line block comments are re-indented
The body of a multi-line block comment is re-indented from the comment's own
structure: the shallowest body line is aligned three columns past the
{-(under the first character after
{-), and any deeper line keeps its extraindentation relative to that.
This is straight-forward. However the body was written:
it comes out anchored to the
{-, independent of the original columns:However, there are cases where the 2nd line (and beyond) of the multi-line
comment start at a column before the "{-".
Here the opener is indented but the body lines start flush at the left margin:
The body is still pulled in and anchored three columns past the
{-, with thedeeper line kept deeper:
Is this what we want? or, do we keep the comments at the absolute starting
column position at which the author wrote them?
Question 6 - Binop chains break strangely
Here is something I just noticed.
A binop chain that overflows breaks the first operand(s) onto their own lines but
then leaves the remaining operands crammed onto one line, with operators at the
seed column (not indented):
I think this should change to look more like how a long function call wraps:
or
Where does the binop go?