Conditional OpenOp / CloseOp
In ktfmt, I'd like to format the following:
fun longName() = coroutineScope {
foo()
//
}
but if it doesn't fit in a single line, I'd like to get
fun longName() =
coroutineScope {
foo()
//
}
I only managed to create the first form by not wrapping the lambda in an OpenOp / CloseOp block, while the second form arises naturally from such a block around coroutine { … }.
One way to solve this is to create a conditional OpenOp / CloseOp, similarly to Indent.If, and then emit a block that materializes only if there had been a break after the =.
What do you think?
(I admit this isn't super clear, let me know if I should make another attempt at explaining this)
cc @cushon @bethcutler
Huh, looks like this can't be done, because an Op is used before the Indents are evaluated...
I think there would also be issues in generalizing conditional opens and closes. For example, all levels around the lambda would also need to be conditional, or else you'd still get the unwanted wrapping. The AST forming those levels could be arbitrarily deep.
I propose a different model for achieving this "block-like" formatting. I want two more Ops:
- AllowBlocklike: Specify a point in the token stream where a blocklike might begin, but isn't required to
- MarkBlocklikeHead: Specify where the "head" of a blocklike ends; all the stuff that should stay on the original line if it fits
These ops would be paired up, possibly using a tagging system like conditional indents use. The region marked by a pair would cut across multiple levels. MarkBlocklikeHead is optional, so AllowBlocklike is a no-op on its own.