From 0f97e50a49e48fc956e59fe6eca5c9c5e0d1fcef Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:20:04 +0200 Subject: [PATCH] perf: memoize message HTML to avoid re-parsing on every keystroke marked.parse runs on all messages each render. With long conversations this makes typing sluggish. useMemo caches rendered HTML per message, only recomputing when messages or cwd change. Also deferred textarea resize to requestAnimationFrame. --- src/components/ChatPane.tsx | 15 ++++++++++++--- src/components/PromptBar.tsx | 7 +++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/components/ChatPane.tsx b/src/components/ChatPane.tsx index ce4f202..1ef1b83 100644 --- a/src/components/ChatPane.tsx +++ b/src/components/ChatPane.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'preact/hooks' +import { useEffect, useRef, useState, useMemo } from 'preact/hooks' import { marked } from 'marked' import mermaid from 'mermaid' @@ -201,6 +201,15 @@ export function ChatPane({ session, cfg, messages, onSend, onStop, browsePath, b const [renaming, setRenaming] = useState(false) const [renameVal, setRenameVal] = useState('') + // Pre-render message HTML so typing in PromptBar doesn't re-parse everything + const renderedHtml = useMemo(() => + messages.map(msg => + (msg.role === 'user' || msg.role === 'assistant') + ? linkifyPaths((marked.parse(msg.content) as string), session.cwd) + : ''), + [messages, session.cwd] + ) + const startRename = () => { setRenaming(true); setRenameVal(sid) } const commitRename = () => { setRenaming(false) @@ -251,7 +260,7 @@ export function ChatPane({ session, cfg, messages, onSend, onStop, browsePath, b