Open steinybot opened 1 month ago
Ohhh I can use Doc.fill
.
Doc.fill("{" +: Doc.line, Seq(Doc.text("def foo ="), Doc.text("bar")))
Man this stuff takes me ages to get my head around. I've literally been staring at it for hours.
Wait no I'm being dumb. That will always add the {
. Damn it.
Well this does it although it uses private stuff. Is there a better way?
package org.typelevel.paiges
import org.typelevel.paiges.Doc.FlatAlt
object Docx {
implicit class DocOps(val doc: Doc) extends AnyVal {
def orEmpty: Doc =
flatAlt(doc, Doc.empty)
def bracketIfLong(left: Doc, leftSep: Doc, rightSep: Doc, right: Doc, indent: Int = 2): Doc =
left + (((leftSep + Doc.hardLine).orEmpty + doc).nested(indent) + (Doc.hardLine + rightSep).orEmpty + right).grouped
}
def bracketIfLong(left: Doc, leftSep: Doc, doc: Doc, rightSep: Doc, right: Doc, indent: Int = 2): Doc =
doc.bracketIfLong(left, leftSep, rightSep, right, indent)
def flatAlt(default: Doc, whenFlat: Doc): Doc =
if (default == whenFlat) default
else FlatAlt(default, whenFlat)
}
import org.scalatest.freespec.AnyFreeSpec
import org.typelevel.paiges.Doc
import org.typelevel.paiges.Docx
class MethodBuilderTest extends AnyFreeSpec {
"MethodBuilder" - {
"should add {} when the body is too long" in {
val sig = Doc.text("def foo = ")
val body = Doc.text("howlongcanyougo")
val doc = Docx.bracketIfLong(sig, Doc.char('{'), body, Doc.char('}'), Doc.empty)
val result = doc.render(24)
val expected =
"""def foo = {
| howlongcanyougo
|}""".stripMargin
assert(result == expected)
}
"should not add {} when the body fits" in {
val sig = Doc.text("def foo = ")
val body = Doc.text("howlongcanyougo")
val doc = Docx.bracketIfLong(sig, Doc.char('{'), body, Doc.char('}'), Doc.empty)
val result = doc.render(25)
val expected = """def foo = howlongcanyougo""".stripMargin
assert(result == expected)
}
}
}
This is a good solution.
Flatly was not directly exposed because it can break the invariants. It only makes sense for certain pairs of Docs. For instance if you flatten the resulting Doc should have lines as long or longer, not shorter.
That said, I think you .orEmpty combinator is safe and doesn't break invariants.
However, composing two such as you have done should only be done with a .grouped (the whole thing flattens or not at all) so a comment should be made around the method.
If you would make a PR I'd be happy to review and I think we could merge it.
Flatly was not directly exposed because it can break the invariants. It only makes sense for certain pairs of Docs. For instance if you flatten the resulting Doc should have lines as long or longer, not shorter.
orEmpty
in general would break the invariant width(default) <= width(whenFlat)
wouldn't it?
So then I think bracketIfLong
would be safe to use orEmpty
if and only if width(leftSep) <= width(doc)
.
However, composing two such as you have done should only be done with a .grouped (the whole thing flattens or not at all) so a comment should be made around the method. Sorry, what should be grouped?
Are you suggesting a PR for just orEmpty
or bracketIfLong
too?
I would like to do:
if it fits, otherwise do:
Is this possible?
Seems like I need
FlatAlt("{" +: Doc.hardLine, doc)
but there is no way to create a customFlatAlt
.