[Analysis API] rework renderer

^KTIJ-23268 fixed
This commit is contained in:
Ilya Kirillov
2022-10-28 10:35:23 +02:00
parent f8ed993307
commit d1eb7c51f1
110 changed files with 3814 additions and 181 deletions
@@ -5,13 +5,27 @@
package org.jetbrains.kotlin.analysis.utils.printer
import java.lang.Appendable
import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf
import org.jetbrains.kotlin.utils.addToStdlib.ifTrue
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
public class PrettyPrinter(private val indentSize: Int = 2) : Appendable {
private val builder = StringBuilder()
public var indent: Int = 0
@OptIn(ExperimentalContracts::class)
public class PrettyPrinter(public val indentSize: Int = 2) : Appendable {
@PublishedApi
internal val builder: StringBuilder = StringBuilder()
@PublishedApi
internal var prefixesToPrint: PersistentList<String> = persistentListOf()
@PublishedApi
internal var indent: Int = 0
override fun append(seq: CharSequence): Appendable = apply {
if (seq.isEmpty()) return@apply
printPrefixes()
seq.split('\n').forEachIndexed { index, line ->
if (index > 0) {
builder.append('\n')
@@ -26,12 +40,21 @@ public class PrettyPrinter(private val indentSize: Int = 2) : Appendable {
}
override fun append(c: Char): Appendable = apply {
printPrefixes()
if (c != '\n') {
appendIndentIfNeeded()
}
builder.append(c)
}
private fun printPrefixes() {
if (prefixesToPrint.isNotEmpty()) {
appendIndentIfNeeded()
prefixesToPrint.forEach { builder.append(it) }
prefixesToPrint = persistentListOf()
}
}
public inline fun withIndent(block: PrettyPrinter.() -> Unit) {
indent += 1
block(this)
@@ -99,7 +122,86 @@ public class PrettyPrinter(private val indentSize: Int = 2) : Appendable {
override fun toString(): String {
return builder.toString()
}
public inline fun checkIfPrinted(render: () -> Unit): Boolean {
val initialSize = builder.length
render()
return initialSize != builder.length
}
public inline operator fun invoke(print: PrettyPrinter.() -> Unit) {
this.print()
}
public inline fun String.separated(p1: () -> Unit, p2: () -> Unit) {
contract {
callsInPlace(p1, InvocationKind.EXACTLY_ONCE)
callsInPlace(p2, InvocationKind.EXACTLY_ONCE)
}
val firstRendered = checkIfPrinted { p1() }
if (firstRendered) {
withPrefix(this, p2)
} else {
p2()
}
}
public inline fun String.separated(p1: () -> Unit, p2: () -> Unit, p3: () -> Unit) {
contract {
callsInPlace(p1, InvocationKind.EXACTLY_ONCE)
callsInPlace(p2, InvocationKind.EXACTLY_ONCE)
callsInPlace(p3, InvocationKind.EXACTLY_ONCE)
}
separated({ separated(p1, p2) }, p3)
}
public inline fun String.separated(p1: () -> Unit, p2: () -> Unit, p3: () -> Unit, p4: () -> Unit) {
contract {
callsInPlace(p1, InvocationKind.EXACTLY_ONCE)
callsInPlace(p2, InvocationKind.EXACTLY_ONCE)
callsInPlace(p3, InvocationKind.EXACTLY_ONCE)
callsInPlace(p4, InvocationKind.EXACTLY_ONCE)
}
separated({ separated(p1, p2, p3) }, p4)
}
public inline fun String.separated(p1: () -> Unit, p2: () -> Unit, p3: () -> Unit, p4: () -> Unit, p5: () -> Unit) {
contract {
callsInPlace(p1, InvocationKind.EXACTLY_ONCE)
callsInPlace(p2, InvocationKind.EXACTLY_ONCE)
callsInPlace(p3, InvocationKind.EXACTLY_ONCE)
callsInPlace(p5, InvocationKind.EXACTLY_ONCE)
}
separated({ separated(p1, p2, p3, p4) }, p5)
}
public inline fun withPrefix(prefix: String, print: () -> Unit) {
contract {
callsInPlace(print, InvocationKind.EXACTLY_ONCE)
}
val currentPrefixes = prefixesToPrint
prefixesToPrint = prefixesToPrint.add(prefix)
try {
print()
} finally {
if (prefixesToPrint.isNotEmpty()) {
prefixesToPrint = currentPrefixes
}
}
}
public inline fun withSuffix(suffix: String, p1: () -> Unit) {
checkIfPrinted { p1() }.ifTrue { append(suffix) }
}
}
public inline fun prettyPrint(body: PrettyPrinter.() -> Unit): String =
PrettyPrinter().apply(body).toString()
PrettyPrinter().apply(body).toString()
@OptIn(ExperimentalContracts::class)
public inline fun prettyPrintWithSettingsFrom(other: PrettyPrinter, body: PrettyPrinter.() -> Unit): String {
contract {
callsInPlace(body, InvocationKind.EXACTLY_ONCE)
}
return PrettyPrinter(other.indentSize).apply(body).toString()
}