86 lines
3.0 KiB
TypeScript
86 lines
3.0 KiB
TypeScript
import type { Accessor, JSXElement } from "solid-js"
|
|
import type { ToolState } from "@opencode-ai/sdk/v2"
|
|
import type { TextPart } from "../../types/message"
|
|
import { Markdown } from "../markdown"
|
|
import type { MarkdownRenderOptions, ToolScrollHelpers } from "./types"
|
|
|
|
export function createMarkdownContentRenderer(params: {
|
|
toolState: Accessor<ToolState | undefined>
|
|
partId: Accessor<string>
|
|
partVersion?: Accessor<number | undefined>
|
|
instanceId: string
|
|
sessionId: string
|
|
isDark: Accessor<boolean>
|
|
scrollHelpers: ToolScrollHelpers
|
|
handleScrollRendered: () => void
|
|
onContentRendered?: () => void
|
|
}) {
|
|
const registerTracked = (element: HTMLDivElement | null) => {
|
|
params.scrollHelpers.registerContainer(element)
|
|
}
|
|
|
|
const registerUntracked = (element: HTMLDivElement | null) => {
|
|
params.scrollHelpers.registerContainer(element, { disableTracking: true })
|
|
}
|
|
|
|
function renderMarkdownContent(options: MarkdownRenderOptions): JSXElement | null {
|
|
if (!options.content) {
|
|
return null
|
|
}
|
|
|
|
const size = options.size || "default"
|
|
const disableHighlight = options.disableHighlight || false
|
|
const messageClass = `message-text tool-call-markdown${size === "large" ? " tool-call-markdown-large" : ""}`
|
|
const disableScrollTracking = options.disableScrollTracking || false
|
|
const registerRef = disableScrollTracking ? registerUntracked : registerTracked
|
|
|
|
const state = params.toolState()
|
|
const shouldDeferMarkdown = Boolean(state && (state.status === "running" || state.status === "pending") && disableHighlight)
|
|
if (shouldDeferMarkdown) {
|
|
return (
|
|
<div
|
|
class={messageClass}
|
|
ref={registerRef}
|
|
onScroll={disableScrollTracking ? undefined : params.scrollHelpers.handleScroll}
|
|
>
|
|
<pre class="whitespace-pre-wrap break-words text-sm font-mono">{options.content}</pre>
|
|
{params.scrollHelpers.renderSentinel({ disableTracking: disableScrollTracking })}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const cacheKey = typeof options.cacheKey === "string" && options.cacheKey.length > 0 ? options.cacheKey : undefined
|
|
const markdownPart: TextPart = {
|
|
id: cacheKey ? `${params.partId()}:${cacheKey}` : params.partId(),
|
|
type: "text",
|
|
text: options.content,
|
|
version: params.partVersion?.(),
|
|
}
|
|
|
|
const handleMarkdownRendered = () => {
|
|
params.handleScrollRendered()
|
|
params.onContentRendered?.()
|
|
}
|
|
|
|
return (
|
|
<div
|
|
class={messageClass}
|
|
ref={registerRef}
|
|
onScroll={disableScrollTracking ? undefined : params.scrollHelpers.handleScroll}
|
|
>
|
|
<Markdown
|
|
part={markdownPart}
|
|
instanceId={params.instanceId}
|
|
sessionId={params.sessionId}
|
|
isDark={params.isDark()}
|
|
disableHighlight={disableHighlight}
|
|
onRendered={handleMarkdownRendered}
|
|
/>
|
|
{params.scrollHelpers.renderSentinel({ disableTracking: disableScrollTracking })}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return { renderMarkdownContent }
|
|
}
|