diff --git a/richtext-ui/src/commonMain/kotlin/com/halilibo/richtext/ui/string/RichTextString.kt b/richtext-ui/src/commonMain/kotlin/com/halilibo/richtext/ui/string/RichTextString.kt index b408ffbc..1adf5008 100644 --- a/richtext-ui/src/commonMain/kotlin/com/halilibo/richtext/ui/string/RichTextString.kt +++ b/richtext-ui/src/commonMain/kotlin/com/halilibo/richtext/ui/string/RichTextString.kt @@ -361,6 +361,9 @@ public class RichTextString internal constructor( public class Builder(capacity: Int = 16) { private val builder = AnnotatedString.Builder(capacity) private val formatObjects = mutableMapOf() + // Tracks formats pushed via pushFormat along with the underlying builder index, + // so we can compute the current SpanStyle without materializing an AnnotatedString. + private val activeFormatStack = mutableListOf>() public fun addFormat( format: Format, @@ -373,12 +376,27 @@ public class RichTextString internal constructor( public fun pushFormat(format: Format): Int { val tag = format.registerTag(formatObjects) - return builder.pushStringAnnotation(FormatAnnotationScope, tag) + val idx = builder.pushStringAnnotation(FormatAnnotationScope, tag) + activeFormatStack.add(idx to format) + return idx } - public fun pop(): Unit = builder.pop() + public fun pop(): Unit { + builder.pop() + if (activeFormatStack.isNotEmpty()) activeFormatStack.removeAt(activeFormatStack.lastIndex) + } + + public fun pop(index: Int): Unit { + builder.pop(index) - public fun pop(index: Int): Unit = builder.pop(index) + if (activeFormatStack.isNotEmpty()) { + var i = activeFormatStack.lastIndex + while (i >= 0 && activeFormatStack[i].first >= index) { + activeFormatStack.removeAt(i) + i-- + } + } + } public fun append(text: String): Unit = builder.append(text) @@ -407,6 +425,28 @@ public class RichTextString internal constructor( builder.toAnnotatedString(), formatObjects.toMap() ) + + /** + * Returns the [SpanStyle] that would currently apply to newly appended text, based on + * the formats that are pushed (but not yet popped) on this builder. + * + * Only formats added via [pushFormat] are considered; any direct operations performed + * via [withAnnotatedString] or [addFormat] are not reflected in the result by design. + */ + public fun getCurrentSpanStyle( + style: RichTextStringStyle, + contentColor: Color + ): SpanStyle { + val resolvedStyle = style.resolveDefaults() + var current = SpanStyle() + // Only consider formats that are currently pushed (and not yet popped). + // Ignore formats added via addFormat, by design. + for ((_, format) in activeFormatStack) { + val annotation = format.getAnnotation(resolvedStyle, contentColor) + if (annotation is SpanStyle) current = current.merge(annotation) + } + return current + } } }