Disable syntax highlighting while tool calls stream

This commit is contained in:
Shantur Rathore
2025-11-03 16:23:51 +00:00
parent 618729e1e3
commit 5cd9bca97f
3 changed files with 58 additions and 6 deletions

View File

@@ -6,6 +6,7 @@ interface MarkdownProps {
part: TextPart
isDark?: boolean
size?: "base" | "sm" | "tight"
disableHighlight?: boolean
}
export function Markdown(props: MarkdownProps) {
@@ -19,11 +20,30 @@ export function Markdown(props: MarkdownProps) {
const text = decodeHtmlEntities(rawText)
const dark = Boolean(props.isDark)
const themeKey = dark ? "dark" : "light"
const highlightEnabled = !props.disableHighlight
latestRequestedText = text
await initMarkdown(dark)
if (!highlightEnabled) {
part.renderCache = undefined
try {
const rendered = await renderMarkdown(text, { suppressHighlight: true })
if (latestRequestedText === text) {
setHtml(rendered)
}
} catch (error) {
console.error("Failed to render markdown:", error)
if (latestRequestedText === text) {
setHtml(text)
}
}
return
}
const cache = part.renderCache
if (cache && cache.text === text && cache.theme === themeKey) {
setHtml(cache.html)
@@ -72,6 +92,10 @@ export function Markdown(props: MarkdownProps) {
// Register listener for language loading completion
const cleanupLanguageListener = onLanguagesLoaded(async () => {
if (props.disableHighlight) {
return
}
const part = props.part
const rawText = typeof part.text === "string" ? part.text : ""
const text = decodeHtmlEntities(rawText)

View File

@@ -290,10 +290,15 @@ export default function ToolCall(props: ToolCallProps) {
const isLarge = toolName === "edit" || toolName === "write" || toolName === "patch"
const messageClass = `message-text tool-call-markdown${isLarge ? " tool-call-markdown-large" : ""}`
const disableHighlight = state?.status === "running"
return (
<div class={messageClass}>
<Markdown part={{ type: "text", text: content }} isDark={isDark()} />
<Markdown
part={{ type: "text", text: content }}
isDark={isDark()}
disableHighlight={disableHighlight}
/>
</div>
)
}

View File

@@ -5,6 +5,7 @@ let highlighter: Highlighter | null = null
let highlighterPromise: Promise<Highlighter> | null = null
let currentTheme: "light" | "dark" = "light"
let isInitialized = false
let highlightSuppressed = false
// Track loaded languages and queue for on-demand loading
const loadedLanguages = new Set<string>()
@@ -81,6 +82,9 @@ function resolveLanguage(token: string): { canonical: string | null; raw: string
}
async function ensureLanguages(content: string) {
if (highlightSuppressed) {
return
}
// Parse code fences to extract language tokens
// Updated regex to capture optional language tokens and handle trailing annotations
const codeBlockRegex = /```[ \t]*([A-Za-z0-9_.+#-]+)?[^`]*?```/g
@@ -228,6 +232,10 @@ function setupRenderer(isDark: boolean) {
</div>
`.trim()
if (highlightSuppressed) {
return `<div class="markdown-code-block" data-language="${escapedLang}" data-code="${encodedCode}">${header}<pre><code class="language-${escapedLang}">${escapeHtml(decodedCode)}</code></pre></div>`
}
// Skip highlighting for "text" language or when highlighter is not available
if (resolvedLang === "text" || !highlighter) {
return `<div class="markdown-code-block" data-language="${escapedLang}" data-code="${encodedCode}">${header}<pre><code>${escapeHtml(decodedCode)}</code></pre></div>`
@@ -281,18 +289,33 @@ export function isMarkdownReady(): boolean {
return isInitialized && highlighter !== null
}
export async function renderMarkdown(content: string): Promise<string> {
export async function renderMarkdown(
content: string,
options?: {
suppressHighlight?: boolean
},
): Promise<string> {
if (!isInitialized) {
await initMarkdown(currentTheme === "dark")
}
const suppressHighlight = options?.suppressHighlight ?? false
const decoded = decodeHtmlEntities(content)
// Queue language loading but don't wait for it to complete
await ensureLanguages(decoded)
if (!suppressHighlight) {
// Queue language loading but don't wait for it to complete
await ensureLanguages(decoded)
}
// Proceed to parse immediately - highlighting will be available on next render
return marked.parse(decoded) as Promise<string>
const previousSuppressed = highlightSuppressed
highlightSuppressed = suppressHighlight
try {
// Proceed to parse immediately - highlighting will be available on next render
return marked.parse(decoded) as Promise<string>
} finally {
highlightSuppressed = previousSuppressed
}
}
export async function getSharedHighlighter(): Promise<Highlighter> {