diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineStyler.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineStyler.kt index 79c83b0c..97cc6c41 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineStyler.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineStyler.kt @@ -68,6 +68,9 @@ object MarkdownInlineStyler { val src = text while (i < src.length) { + // Cheap prefix gate: URL_PATTERN only matches at "http(s)://", so skip the regex elsewhere. + val urlMatch = + if (src.startsWith("http", i, ignoreCase = true)) URL_PATTERN.matchAt(src, i) else null when { // Inline code is opaque to emphasis parsing, and delimiters must match by run length. src[i] == '`' -> { @@ -312,9 +315,8 @@ object MarkdownInlineStyler { } // bare URL - URL_PATTERN.matchAt(src, i) != null -> { - val match = URL_PATTERN.matchAt(src, i)!! - val url = match.value + urlMatch != null -> { + val url = urlMatch.value val urlToAppend = if (isRtl) BidiUtils.wrapLtrIsolate(url) else url pushLink(LinkAnnotation.Url(url)) withStyle( @@ -326,7 +328,7 @@ object MarkdownInlineStyler { append(urlToAppend) } pop() - i = match.range.last + 1 + i = urlMatch.range.last + 1 } // Plain text / words in RTL diff --git a/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineText.kt b/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineText.kt index 167ca1e1..6270472b 100644 --- a/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineText.kt +++ b/app/src/main/java/com/m57/hermescontrol/ui/chat/markdown/MarkdownInlineText.kt @@ -66,38 +66,56 @@ fun MarkdownInlineText( } val config = - LatexConfig( - fontSize = style.fontSize, - theme = LatexTheme.light(color = textColor, backgroundColor = Color.Transparent), - accessibilityEnabled = true, - ) - val inlineContent = mutableMapOf() - segments.forEachIndexed { index, segment -> - if (segment is InlineMathSegment.Math) { - latexMeasurer.inlineContent(segment.latex, config)?.let { inlineContent["latex-$index"] = it } + remember(style.fontSize, textColor) { + LatexConfig( + fontSize = style.fontSize, + theme = LatexTheme.light(color = textColor, backgroundColor = Color.Transparent), + accessibilityEnabled = true, + ) } - } - val annotated = - buildAnnotatedString { + val inlineContent = + remember(segments, latexMeasurer, config) { + val map = mutableMapOf() segments.forEachIndexed { index, segment -> - when (segment) { - is InlineMathSegment.Math -> { - val id = "latex-$index" - if (id in inlineContent) appendInlineContent(id, segment.latex) else append(segment.latex) - } + if (segment is InlineMathSegment.Math) { + latexMeasurer.inlineContent(segment.latex, config)?.let { map["latex-$index"] = it } + } + } + map + } + val annotated = + remember( + segments, + inlineContent, + textColor, + searchQuery, + isCurrentMatch, + linkColor, + highlights, + isRtl, + ) { + buildAnnotatedString { + segments.forEachIndexed { index, segment -> + when (segment) { + is InlineMathSegment.Math -> { + val id = "latex-$index" + val measured = id in inlineContent + if (measured) appendInlineContent(id, segment.latex) else append(segment.latex) + } - is InlineMathSegment.Text -> { - append( - MarkdownInlineStyler.parseInlineSource( - text = segment.value, - textColor = textColor, - searchQuery = searchQuery, - isCurrentMatch = isCurrentMatch, - linkColor = linkColor, - highlights = highlights, - isRtl = isRtl, - ), - ) + is InlineMathSegment.Text -> { + append( + MarkdownInlineStyler.parseInlineSource( + text = segment.value, + textColor = textColor, + searchQuery = searchQuery, + isCurrentMatch = isCurrentMatch, + linkColor = linkColor, + highlights = highlights, + isRtl = isRtl, + ), + ) + } } } }