git.iko.soy/opencode-android
on master help sign in
Reduce allocation churn from token formatting and markdown escaping
6a5c9f0iko
app/src/main/java/soy/iko/opencode/ui/chat/ConversationExport.kt+11−7
@@ -40,10 +40,14 @@ fun buildConversationMarkdown(messages: List<MessageWithParts>, title: String?):
40}
40}
41
41
42/** Escape markdown special characters so user/model text doesn't produce malformed markdown. */
42/** Escape markdown special characters so user/model text doesn't produce malformed markdown. */
43−private fun escapeMarkdown(text: String): String =
43+private fun escapeMarkdown(text: String): String {
44− text.replace("\\", "\\\\")
44+ if (text.isEmpty()) return text
45− .replace("*", "\\*")
45+ val sb = StringBuilder(text.length + 16)
46− .replace("_", "\\_")
46+ for (c in text) {
47− .replace("#", "\\#")
47+ when (c) {
48− .replace("`", "\\`")
48+ '\\', '*', '_', '#', '`', '>' -> sb.append('\\')
49− .replace(">", "\\>")
49+ }
50+ sb.append(c)
51+ }
52+ return sb.toString()
53+}
app/src/main/java/soy/iko/opencode/ui/chat/MessageBubble.kt+10−1
@@ -106,8 +106,17 @@ private fun MessageTimestamp(info: soy.iko.opencode.data.model.MessageInfo) {
106 }
106 }
107}
107}
108
108
109+// NumberFormat.getNumberInstance performs an expensive ICU locale lookup + object
110+// construction on every call. Reuse a thread-local instance so repeated calls (e.g.
111+// when the message list re-seeds after a reconnect and every visible assistant bubble
112+// recomposes at once) don't each pay that cost. Thread-local because NumberFormat is
113+// not thread-safe.
114+private val tokenNumberFormat: ThreadLocal<java.text.NumberFormat> = ThreadLocal.withInitial {
115+ java.text.NumberFormat.getNumberInstance(java.util.Locale.US)
116+}
117+
109private fun formatTokens(tokens: Tokens, format: String): String {
118private fun formatTokens(tokens: Tokens, format: String): String {
110− val nf = java.text.DecimalFormat.getNumberInstance(java.util.Locale.US)
119+ val nf = tokenNumberFormat.get()!!
111 return format.format(nf.format(tokens.input), nf.format(tokens.output))
120 return format.format(nf.format(tokens.input), nf.format(tokens.output))
112}
121}
113
122