Skip to content

PrettyStrings.kt

src/jvmMain/kotlin/afield/ui/output/PrettyStrings.kt · 76 lines

@file:afield.runtime.completion.CompletionCategory("Internal")

package afield.ui.output

import afield.data.collections.get
import afield.data.collections.invoke
import afield.data.collections.times
import afield.document.graph.minusAssign
import afield.document.graph.plusAssign
import afield.document.properties.compareTo
import afield.document.workspace.file
import afield.graphics.render.rangeTo
import afield.math.autodiff.compareTo
import afield.math.autodiff.div
import afield.math.autodiff.minus
import afield.math.autodiff.plus
import afield.math.autodiff.times
import afield.math.linalg.f
import afield.math.linalg.invoke
import afield.math.linalg.remAssign
import afield.math.linalg.set
import afield.math.linalg.times
import afield.math.units.div
import afield.math.units.minus
import afield.math.units.plus
import afield.math.units.times

import afield.audio.synth.*
private const val PRETTY_LIMIT = 4
private const val STRING_LIMIT = 48

internal fun prettySummary(name: String, vararg fields: Pair<String, Any?>): String

internal fun prettySummary(name: String, vararg fields: Pair<String, Any?>): String {
    if (fields.isEmpty()) return name
    val body = fields.joinToString(", ") { (key, value) -> "$key=${prettyValue(value)}" }
    return "$name($body)"
}

internal fun prettyValue(value: Any?): String

internal fun prettyValue(value: Any?): String = when (value) {
    null -> "null"
    is String -> "\"${value.prettyText()}\""
    is CharSequence -> "\"${value.toString().prettyText()}\""
    is Number, is Boolean, is Char -> value.toString()
    is Enum<*> -> value.name
    is FloatArray -> prettyArray("FloatArray", value.size, value.take(PRETTY_LIMIT))
    is DoubleArray -> prettyArray("DoubleArray", value.size, value.take(PRETTY_LIMIT))
    is IntArray -> prettyArray("IntArray", value.size, value.take(PRETTY_LIMIT))
    is LongArray -> prettyArray("LongArray", value.size, value.take(PRETTY_LIMIT))
    is Iterable<*> -> {
        val items = value.take(PRETTY_LIMIT).joinToString(", ") { prettyValue(it) }
        val suffix = if (value.drop(PRETTY_LIMIT).any()) ", ..." else ""
        "[$items$suffix]"
    }
    is Map<*, *> -> {
        val items = value.entries.take(PRETTY_LIMIT).joinToString(", ") { (k, v) -> "${prettyValue(k)}=${prettyValue(v)}" }
        val suffix = if (value.size > PRETTY_LIMIT) ", ..." else ""
        "{$items$suffix}"
    }
    is Function<*> -> "<lambda>"
    else -> value.toString()
}

internal fun prettyNumber(value: Double, decimals: Int = 4): String

internal fun prettyNumber(value: Double, decimals: Int = 4): String =
    String.format(java.util.Locale.US, "%.${decimals}f", value).trimEnd('0').trimEnd('.')

internal fun prettyNumber(value: Float, decimals: Int = 3): String

internal fun prettyNumber(value: Float, decimals: Int = 3): String =
    String.format(java.util.Locale.US, "%.${decimals}f", value).trimEnd('0').trimEnd('.')

private fun prettyArray(type: String, size: Int, values: List<Any>): String {
    val preview = values.joinToString(", ")
    val suffix = if (size > values.size) ", ..." else ""
    return "$type($size)[$preview$suffix]"
}

private fun String.prettyText(limit: Int = STRING_LIMIT): String =
    if (length <= limit) this else take(limit - 3) + "..."