I frequently have to generate very big function bodies where some individual statements are huge. And it's actually pretty difficult to generate reasonably looking output. The fix for this might be as simple as providing examples in the documentation.
Let me describe the problem first.
Generating code:
val lambda = CodeBlock.of(
"""
{ foo -> println(foo + %S + %S) }
""".trimIndent(),
"A".repeat(50),
"B".repeat(50),
)
val cb1 = buildCodeBlock {
addStatement("if (foo) { longFunctionCall(%S, %L, %S) }", "X".repeat(50), lambda, "Y".repeat(50))
}
val cb2 = buildCodeBlock {
addStatement(
"""
if (foo) {
longFunctionCall(
%S,
%L,
%S
)
}
""".trimIndent(),
"X".repeat(50), lambda, "Y".repeat(50))
}
val cb3 = buildCodeBlock {
add(
"""
if (foo) {
longFunctionCall(
%S,
⇥%L⇤,
%S
)
}
""".trimIndent(),
"X".repeat(50), lambda, "Y".repeat(50))
}
FileSpec.builder("com.test", "HelloWorld")
.addType(
TypeSpec.classBuilder("HelloWorld")
.addFunction(FunSpec.builder("hello1").addCode(cb1).build())
.addFunction(FunSpec.builder("hello2").addCode(cb2).build())
.addFunction(FunSpec.builder("hello3").addCode(cb3).build())
.build()
)
.build()
.writeTo(System.out)
It prints:
package com.test
public class HelloWorld {
public fun hello1() {
if (foo) { longFunctionCall("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", { foo ->
println(foo + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") },
"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY") }
}
public fun hello2() {
if (foo) {
longFunctionCall(
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
{ foo -> println(foo + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") },
"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
)
}
}
public fun hello3() {
if (foo) {
longFunctionCall(
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
{ foo -> println(foo + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB") },
"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
)
}
}
}
The first function looks quite horrible, because the wrapping has no idea about semantics, it just breaks in the middle of the deepest level of nesting if it feels like it. My naive attempt at fixing that is the second code block where I do the wrapping by hand, using Kotlin's lovely triple-quoted string. But it still looks bad because of addStatement's behavior. It indents all lines after the first, but in Kotlin the last line of a block should be indented the same as the first line. My third attempt is to use add instead of addStatement and also using the indentation magic characters. The output of that looks very good.
The proper fix for addStatement's bad wrapping would be to count opening and closing braces and parentheses but I understand it could be difficult. So we could just say that addStatement has this limitation and people should live with it and use add instead.
The problem with add is that when I add my own indentation, it's not compatible with KotlinPoet's indentation. But I figured that if I use indentation magic characters around composition points, it works really great. One fix would be to detect the current indentation when embedding a nested CodeBlock into another nested CodeBlock, but again it could be difficult. So instead it could be just added to the documentation how people should deal with the indentation.
I frequently have to generate very big function bodies where some individual statements are huge. And it's actually pretty difficult to generate reasonably looking output. The fix for this might be as simple as providing examples in the documentation.
Let me describe the problem first.
Generating code:
It prints:
The first function looks quite horrible, because the wrapping has no idea about semantics, it just breaks in the middle of the deepest level of nesting if it feels like it. My naive attempt at fixing that is the second code block where I do the wrapping by hand, using Kotlin's lovely triple-quoted string. But it still looks bad because of addStatement's behavior. It indents all lines after the first, but in Kotlin the last line of a block should be indented the same as the first line. My third attempt is to use add instead of addStatement and also using the indentation magic characters. The output of that looks very good.
The proper fix for addStatement's bad wrapping would be to count opening and closing braces and parentheses but I understand it could be difficult. So we could just say that addStatement has this limitation and people should live with it and use add instead.
The problem with add is that when I add my own indentation, it's not compatible with KotlinPoet's indentation. But I figured that if I use indentation magic characters around composition points, it works really great. One fix would be to detect the current indentation when embedding a nested CodeBlock into another nested CodeBlock, but again it could be difficult. So instead it could be just added to the documentation how people should deal with the indentation.