I’m working on a pretty-printer for Lua, and I’m stuck with handling indentation for function syntax.
What I want is this: if function definition is short enough, all definition could be written in one line, but if it’s not that short, then all body is needed to be printed in new line and with indentation. After that, end keyword should be placed in a new line, without indentation.
I think I don’t fully understand how Leijen pretty-printer works, but this is what I’ve got so far:
import Text.PrettyPrint.Leijen
import System.IO (stdout)
sometext = text "short text" </> text "this is some long text at least long enough for my purposes"
p = parens (align (cat (punctuate (comma <> space) (map text ["first parameter", "second parameter", "third"]))))
doc3 = indent 4 (sep [text "function" </> p, indent 4 sometext, text "end"])
main :: IO ()
main = do
displayIO stdout (renderPretty 1 133 (doc3 <$> line))
displayIO stdout (renderPretty 1 134 (doc3 <$> line))
displayIO stdout (renderPretty 1 40 (doc3 <$> line))
This actually works pretty well except the second part of the output:
function (first parameter, second parameter, third)
short text this is some long text at least long enough for my purposes
end
function (first parameter, second parameter, third) short text this is some long text at least long enough for my purposes end
function (first parameter,
second parameter,
third)
short text
this is some long text at least long enough for my purposes
end
Here I don’t want that 4 spaces indentation, in second output. But I couldn’t find a way to do that without ruining other outputs.
Any help will be appreciated.
EDIT: Here’s another test case:
doc4 = sep [ text "if" </> text "test" </> text "then"
, indent 4 then_body
, text "elseif" </> elseif_conditions </> text "then"
, indent 4 elseif_body
, text "end"
]
What I want from it is, if the output is short enough, print all of it at the same line(but without indentation spaces). It works great when splitting multiple lines, but puts superfluous spaces when prints to same line.
First let’s make a way of trying out documents at every width starting with a maximum, and only print the ones that are different. This will help check the Doc behaves as you hope.
What I (now) think you want
Now let’s take advantage of the extra info in your comments. Sorry I misinterpreted you the first time round.
I think you mean it’s permissible to all be on one line, but if not, there should be at least three, with the function head on the first, the function body indented and the end unindented. You don’t mind if the
sometextis split across lines at the break, comes after the parameters etc, as long as it’s indented by 4 if it’s not inline.The
nestfunction allows us to indent subsequent lines if there are any, whereasindentdefinitely puts spaces, which is why you had the ugly extra 4 lines.So, there are three parts to your function:
with a slightly refactored way of making parameters:
Lay it out with the breaks specified
Let’s specify how we’d like them laid out if we need line breaks:
Which demonstrates the way we want the line breaks to go:
Pop it all on one line if it fits
The pretty printing library has a combinator for getting rid of all line breaks if it fits on one line,
group. Let’s indent the whole lot by 4 and group.Which gives: