perf(ui): split right panel and secondary viewer chunks (#239)
## Summary - split the right panel, picker, and tool call secondary viewers into smaller deferred chunks - release hidden right-panel file buffers and stop tracking static tool-call scrollers when they are not needed - keep this branch focused on the remaining secondary viewer chunking work now that the Monaco-specific chunking moved into PR 215 ## Testing - npm run build --workspace @codenomad/ui
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import {
|
||||
Show,
|
||||
Suspense,
|
||||
createEffect,
|
||||
createMemo,
|
||||
createSignal,
|
||||
lazy,
|
||||
onCleanup,
|
||||
type Accessor,
|
||||
type Component,
|
||||
@@ -20,11 +22,6 @@ import type { Session } from "../../../../types/session"
|
||||
import type { DrawerViewState } from "../types"
|
||||
import type { DiffContextMode, DiffViewMode, DiffWordWrapMode, RightPanelTab } from "./types"
|
||||
|
||||
import ChangesTab from "./tabs/ChangesTab"
|
||||
import FilesTab from "./tabs/FilesTab"
|
||||
import GitChangesTab from "./tabs/GitChangesTab"
|
||||
import StatusTab from "./tabs/StatusTab"
|
||||
|
||||
import { getDefaultWorktreeSlug, getOrCreateWorktreeClient, getWorktreeSlugForSession } from "../../../../stores/worktrees"
|
||||
import { requestData } from "../../../../lib/opencode-api"
|
||||
import { buildUnifiedDiffFromSdkPatch, tryReverseApplyUnifiedDiff } from "../../../../lib/unified-diff-reverse"
|
||||
@@ -49,6 +46,15 @@ import {
|
||||
readStoredRightPanelTab,
|
||||
} from "../storage"
|
||||
|
||||
const LazyChangesTab = lazy(() => import("./tabs/ChangesTab"))
|
||||
const LazyGitChangesTab = lazy(() => import("./tabs/GitChangesTab"))
|
||||
const LazyFilesTab = lazy(() => import("./tabs/FilesTab"))
|
||||
const LazyStatusTab = lazy(() => import("./tabs/StatusTab"))
|
||||
|
||||
function RightPanelTabFallback() {
|
||||
return <div class="flex-1 min-h-0" />
|
||||
}
|
||||
|
||||
interface RightPanelProps {
|
||||
t: (key: string, vars?: Record<string, any>) => string
|
||||
|
||||
@@ -565,6 +571,13 @@ const RightPanel: Component<RightPanelProps> = (props) => {
|
||||
void loadBrowserEntries(browserPath())
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (rightPanelTab() === "files") return
|
||||
setBrowserSelectedContent(null)
|
||||
setBrowserSelectedLoading(false)
|
||||
setBrowserSelectedError(null)
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (rightPanelTab() !== "git-changes") return
|
||||
if (gitStatusLoading()) return
|
||||
@@ -572,6 +585,14 @@ const RightPanel: Component<RightPanelProps> = (props) => {
|
||||
void loadGitStatus()
|
||||
})
|
||||
|
||||
createEffect(() => {
|
||||
if (rightPanelTab() === "git-changes") return
|
||||
setGitSelectedBefore(null)
|
||||
setGitSelectedAfter(null)
|
||||
setGitSelectedLoading(false)
|
||||
setGitSelectedError(null)
|
||||
})
|
||||
|
||||
const handleSelectChangesFile = (file: string, closeList: boolean) => {
|
||||
setSelectedFile(file)
|
||||
if (closeList) {
|
||||
@@ -738,101 +759,109 @@ const RightPanel: Component<RightPanelProps> = (props) => {
|
||||
|
||||
<div class="flex-1 overflow-y-auto">
|
||||
<Show when={rightPanelTab() === "changes"}>
|
||||
<ChangesTab
|
||||
t={props.t}
|
||||
instanceId={props.instanceId}
|
||||
activeSessionId={props.activeSessionId}
|
||||
activeSessionDiffs={props.activeSessionDiffs}
|
||||
selectedFile={selectedFile}
|
||||
onSelectFile={handleSelectChangesFile}
|
||||
diffViewMode={diffViewMode}
|
||||
diffContextMode={diffContextMode}
|
||||
diffWordWrapMode={diffWordWrapMode}
|
||||
onViewModeChange={setDiffViewMode}
|
||||
onContextModeChange={setDiffContextMode}
|
||||
onWordWrapModeChange={setDiffWordWrapMode}
|
||||
listOpen={changesListOpen}
|
||||
onToggleList={toggleChangesList}
|
||||
splitWidth={changesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("changes")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("changes")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
<Suspense fallback={<RightPanelTabFallback />}>
|
||||
<LazyChangesTab
|
||||
t={props.t}
|
||||
instanceId={props.instanceId}
|
||||
activeSessionId={props.activeSessionId}
|
||||
activeSessionDiffs={props.activeSessionDiffs}
|
||||
selectedFile={selectedFile}
|
||||
onSelectFile={handleSelectChangesFile}
|
||||
diffViewMode={diffViewMode}
|
||||
diffContextMode={diffContextMode}
|
||||
diffWordWrapMode={diffWordWrapMode}
|
||||
onViewModeChange={setDiffViewMode}
|
||||
onContextModeChange={setDiffContextMode}
|
||||
onWordWrapModeChange={setDiffWordWrapMode}
|
||||
listOpen={changesListOpen}
|
||||
onToggleList={toggleChangesList}
|
||||
splitWidth={changesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("changes")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("changes")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
</Suspense>
|
||||
</Show>
|
||||
|
||||
<Show when={rightPanelTab() === "git-changes"}>
|
||||
<GitChangesTab
|
||||
t={props.t}
|
||||
activeSessionId={props.activeSessionId}
|
||||
entries={gitStatusEntries}
|
||||
statusLoading={gitStatusLoading}
|
||||
statusError={gitStatusError}
|
||||
selectedPath={gitSelectedPath}
|
||||
selectedLoading={gitSelectedLoading}
|
||||
selectedError={gitSelectedError}
|
||||
selectedBefore={gitSelectedBefore}
|
||||
selectedAfter={gitSelectedAfter}
|
||||
mostChangedPath={gitMostChangedPath}
|
||||
scopeKey={gitScopeKey}
|
||||
diffViewMode={diffViewMode}
|
||||
diffContextMode={diffContextMode}
|
||||
diffWordWrapMode={diffWordWrapMode}
|
||||
onViewModeChange={setDiffViewMode}
|
||||
onContextModeChange={setDiffContextMode}
|
||||
onWordWrapModeChange={setDiffWordWrapMode}
|
||||
onOpenFile={(path) => void openGitFile(path)}
|
||||
onRefresh={() => void refreshGitStatus()}
|
||||
listOpen={gitChangesListOpen}
|
||||
onToggleList={toggleGitList}
|
||||
splitWidth={gitChangesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("git-changes")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("git-changes")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
<Suspense fallback={<RightPanelTabFallback />}>
|
||||
<LazyGitChangesTab
|
||||
t={props.t}
|
||||
activeSessionId={props.activeSessionId}
|
||||
entries={gitStatusEntries}
|
||||
statusLoading={gitStatusLoading}
|
||||
statusError={gitStatusError}
|
||||
selectedPath={gitSelectedPath}
|
||||
selectedLoading={gitSelectedLoading}
|
||||
selectedError={gitSelectedError}
|
||||
selectedBefore={gitSelectedBefore}
|
||||
selectedAfter={gitSelectedAfter}
|
||||
mostChangedPath={gitMostChangedPath}
|
||||
scopeKey={gitScopeKey}
|
||||
diffViewMode={diffViewMode}
|
||||
diffContextMode={diffContextMode}
|
||||
diffWordWrapMode={diffWordWrapMode}
|
||||
onViewModeChange={setDiffViewMode}
|
||||
onContextModeChange={setDiffContextMode}
|
||||
onWordWrapModeChange={setDiffWordWrapMode}
|
||||
onOpenFile={(path: string) => void openGitFile(path)}
|
||||
onRefresh={() => void refreshGitStatus()}
|
||||
listOpen={gitChangesListOpen}
|
||||
onToggleList={toggleGitList}
|
||||
splitWidth={gitChangesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("git-changes")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("git-changes")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
</Suspense>
|
||||
</Show>
|
||||
|
||||
<Show when={rightPanelTab() === "files"}>
|
||||
<FilesTab
|
||||
t={props.t}
|
||||
browserPath={browserPath}
|
||||
browserEntries={browserEntries}
|
||||
browserLoading={browserLoading}
|
||||
browserError={browserError}
|
||||
browserSelectedPath={browserSelectedPath}
|
||||
browserSelectedContent={browserSelectedContent}
|
||||
browserSelectedLoading={browserSelectedLoading}
|
||||
browserSelectedError={browserSelectedError}
|
||||
parentPath={browserParentPath}
|
||||
scopeKey={browserScopeKey}
|
||||
onLoadEntries={(path) => void loadBrowserEntries(path)}
|
||||
onOpenFile={(path) => void openBrowserFile(path)}
|
||||
onRefresh={() => void refreshFilesTab()}
|
||||
listOpen={filesListOpen}
|
||||
onToggleList={toggleFilesList}
|
||||
splitWidth={filesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("files")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("files")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
<Suspense fallback={<RightPanelTabFallback />}>
|
||||
<LazyFilesTab
|
||||
t={props.t}
|
||||
browserPath={browserPath}
|
||||
browserEntries={browserEntries}
|
||||
browserLoading={browserLoading}
|
||||
browserError={browserError}
|
||||
browserSelectedPath={browserSelectedPath}
|
||||
browserSelectedContent={browserSelectedContent}
|
||||
browserSelectedLoading={browserSelectedLoading}
|
||||
browserSelectedError={browserSelectedError}
|
||||
parentPath={browserParentPath}
|
||||
scopeKey={browserScopeKey}
|
||||
onLoadEntries={(path: string) => void loadBrowserEntries(path)}
|
||||
onOpenFile={(path: string) => void openBrowserFile(path)}
|
||||
onRefresh={() => void refreshFilesTab()}
|
||||
listOpen={filesListOpen}
|
||||
onToggleList={toggleFilesList}
|
||||
splitWidth={filesSplitWidth}
|
||||
onResizeMouseDown={handleSplitResizeMouseDown("files")}
|
||||
onResizeTouchStart={handleSplitResizeTouchStart("files")}
|
||||
isPhoneLayout={props.isPhoneLayout}
|
||||
/>
|
||||
</Suspense>
|
||||
</Show>
|
||||
|
||||
<Show when={rightPanelTab() === "status"}>
|
||||
<StatusTab
|
||||
t={props.t}
|
||||
instanceId={props.instanceId}
|
||||
instance={props.instance}
|
||||
activeSessionId={props.activeSessionId}
|
||||
activeSession={props.activeSession}
|
||||
activeSessionDiffs={props.activeSessionDiffs}
|
||||
latestTodoState={props.latestTodoState}
|
||||
backgroundProcessList={props.backgroundProcessList}
|
||||
onOpenBackgroundOutput={props.onOpenBackgroundOutput}
|
||||
onStopBackgroundProcess={props.onStopBackgroundProcess}
|
||||
onTerminateBackgroundProcess={props.onTerminateBackgroundProcess}
|
||||
expandedItems={rightPanelExpandedItems}
|
||||
onExpandedItemsChange={handleAccordionChange}
|
||||
onOpenChangesTab={openChangesTabFromStatus}
|
||||
/>
|
||||
<Suspense fallback={<RightPanelTabFallback />}>
|
||||
<LazyStatusTab
|
||||
t={props.t}
|
||||
instanceId={props.instanceId}
|
||||
instance={props.instance}
|
||||
activeSessionId={props.activeSessionId}
|
||||
activeSession={props.activeSession}
|
||||
activeSessionDiffs={props.activeSessionDiffs}
|
||||
latestTodoState={props.latestTodoState}
|
||||
backgroundProcessList={props.backgroundProcessList}
|
||||
onOpenBackgroundOutput={props.onOpenBackgroundOutput}
|
||||
onStopBackgroundProcess={props.onStopBackgroundProcess}
|
||||
onTerminateBackgroundProcess={props.onTerminateBackgroundProcess}
|
||||
expandedItems={rightPanelExpandedItems}
|
||||
onExpandedItemsChange={handleAccordionChange}
|
||||
onOpenChangesTab={openChangesTabFromStatus}
|
||||
/>
|
||||
</Suspense>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { For, Match, Show, Switch, createEffect, createMemo, createSignal, onCleanup, untrack } from "solid-js"
|
||||
import { For, Match, Show, Suspense, Switch, createEffect, createMemo, createSignal, lazy, onCleanup, untrack } from "solid-js"
|
||||
import { ChevronsDownUp, ChevronsUpDown, ExternalLink, FoldVertical, ListStart, Trash } from "lucide-solid"
|
||||
import MessageItem from "./message-item"
|
||||
import ToolCall from "./tool-call"
|
||||
import type { InstanceMessageStore } from "../stores/message-v2/instance-store"
|
||||
import type { ClientPart, MessageInfo } from "../types/message"
|
||||
import { partHasRenderableText } from "../types/message"
|
||||
@@ -29,6 +28,12 @@ const USER_BORDER_COLOR = "var(--message-user-border)"
|
||||
const ASSISTANT_BORDER_COLOR = "var(--message-assistant-border)"
|
||||
const TOOL_BORDER_COLOR = "var(--message-tool-border)"
|
||||
|
||||
const LazyToolCall = lazy(() => import("./tool-call"))
|
||||
|
||||
function ToolCallFallback() {
|
||||
return <div class="tool-call tool-call-loading" />
|
||||
}
|
||||
|
||||
type ToolCallPart = Extract<ClientPart, { type: "tool" }>
|
||||
|
||||
|
||||
@@ -500,16 +505,18 @@ function ToolCallItem(props: ToolCallItemProps) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ToolCall
|
||||
toolCall={resolvedToolPart()}
|
||||
toolCallId={props.partId}
|
||||
messageId={props.messageId}
|
||||
messageVersion={messageVersion()}
|
||||
partVersion={partVersion()}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={props.sessionId}
|
||||
onContentRendered={props.onContentRendered}
|
||||
/>
|
||||
<Suspense fallback={<ToolCallFallback />}>
|
||||
<LazyToolCall
|
||||
toolCall={resolvedToolPart()}
|
||||
toolCallId={props.partId}
|
||||
messageId={props.messageId}
|
||||
messageVersion={messageVersion()}
|
||||
partVersion={partVersion()}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={props.sessionId}
|
||||
onContentRendered={props.onContentRendered}
|
||||
/>
|
||||
</Suspense>
|
||||
</div>
|
||||
)}
|
||||
</Show>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Show, Match, Switch } from "solid-js"
|
||||
import ToolCall from "./tool-call"
|
||||
import { Match, Show, Suspense, Switch, lazy } from "solid-js"
|
||||
import { isItemExpanded, toggleItemExpanded } from "../stores/tool-call-state"
|
||||
import { Markdown } from "./markdown"
|
||||
import { useTheme } from "../lib/theme"
|
||||
@@ -7,6 +6,8 @@ import { partHasRenderableText, SDKPart, TextPart, ClientPart } from "../types/m
|
||||
|
||||
type ToolCallPart = Extract<ClientPart, { type: "tool" }>
|
||||
|
||||
const LazyToolCall = lazy(() => import("./tool-call"))
|
||||
|
||||
interface MessagePartProps {
|
||||
part: ClientPart
|
||||
messageType?: "user" | "assistant"
|
||||
@@ -153,12 +154,14 @@ export default function MessagePart(props: MessagePartProps) {
|
||||
</Match>
|
||||
|
||||
<Match when={partType() === "tool"}>
|
||||
<ToolCall
|
||||
toolCall={props.part as ToolCallPart}
|
||||
toolCallId={props.part?.id}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={props.sessionId}
|
||||
/>
|
||||
<Suspense fallback={<div class="tool-call tool-call-loading" />}>
|
||||
<LazyToolCall
|
||||
toolCall={props.part as ToolCallPart}
|
||||
toolCallId={props.part?.id}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={props.sessionId}
|
||||
/>
|
||||
</Suspense>
|
||||
</Match>
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { For, Show, createMemo, createSignal, createEffect, onCleanup, type Component } from "solid-js"
|
||||
import { For, Show, Suspense, createMemo, createSignal, createEffect, lazy, onCleanup, type Component } from "solid-js"
|
||||
import type { PermissionRequestLike } from "../types/permission"
|
||||
import { getPermissionCallId, getPermissionDisplayTitle, getPermissionKind, getPermissionMessageId, getPermissionSessionId } from "../types/permission"
|
||||
import { getQuestionCallId, getQuestionMessageId, getQuestionSessionId, type QuestionRequest } from "../types/question"
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
} from "../stores/instances"
|
||||
import { ensureSessionParentExpanded, loadMessages, sessions as sessionStateSessions, setActiveSessionFromList } from "../stores/sessions"
|
||||
import { messageStoreBus } from "../stores/message-v2/bus"
|
||||
import ToolCall from "./tool-call"
|
||||
|
||||
const LazyToolCall = lazy(() => import("./tool-call"))
|
||||
|
||||
interface PermissionApprovalModalProps {
|
||||
instanceId: string
|
||||
@@ -408,15 +409,17 @@ const PermissionApprovalModal: Component<PermissionApprovalModalProps> = (props)
|
||||
}
|
||||
>
|
||||
{(data) => (
|
||||
<ToolCall
|
||||
toolCall={data().toolPart}
|
||||
toolCallId={data().toolPart.id}
|
||||
messageId={data().messageId}
|
||||
messageVersion={data().messageVersion}
|
||||
partVersion={data().partVersion}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={data().sessionId}
|
||||
/>
|
||||
<Suspense fallback={<div class="tool-call tool-call-loading" />}>
|
||||
<LazyToolCall
|
||||
toolCall={data().toolPart}
|
||||
toolCallId={data().toolPart.id}
|
||||
messageId={data().messageId}
|
||||
messageVersion={data().messageVersion}
|
||||
partVersion={data().partVersion}
|
||||
instanceId={props.instanceId}
|
||||
sessionId={data().sessionId}
|
||||
/>
|
||||
</Suspense>
|
||||
)}
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { createSignal, Show, onMount, onCleanup, createEffect, on } from "solid-js"
|
||||
import { Suspense, createEffect, createSignal, lazy, on, onCleanup, onMount, Show } from "solid-js"
|
||||
import { ArrowBigUp, ArrowBigDown } from "lucide-solid"
|
||||
import UnifiedPicker from "./unified-picker"
|
||||
import ExpandButton from "./expand-button"
|
||||
import { clearAttachments, removeAttachment } from "../stores/attachments"
|
||||
import { resolvePastedPlaceholders } from "../lib/prompt-placeholders"
|
||||
@@ -20,6 +19,7 @@ import { usePromptAttachments } from "./prompt-input/usePromptAttachments"
|
||||
import { usePromptPicker } from "./prompt-input/usePromptPicker"
|
||||
import { usePromptKeyDown } from "./prompt-input/usePromptKeyDown"
|
||||
const log = getLogger("actions")
|
||||
const LazyUnifiedPicker = lazy(() => import("./unified-picker"))
|
||||
|
||||
function getConsumedPastedTextAttachmentIds(text: string, attachments: Attachment[]): string[] {
|
||||
if (!text || attachments.length === 0) return []
|
||||
@@ -467,18 +467,20 @@ export default function PromptInput(props: PromptInputProps) {
|
||||
onDrop={handleDrop}
|
||||
>
|
||||
<Show when={showPicker() && instance()}>
|
||||
<UnifiedPicker
|
||||
open={showPicker()}
|
||||
mode={pickerMode()}
|
||||
onClose={handlePickerClose}
|
||||
onSelect={handlePickerSelect}
|
||||
agents={instanceAgents()}
|
||||
commands={getCommands(props.instanceId)}
|
||||
instanceClient={instance()!.client}
|
||||
searchQuery={searchQuery()}
|
||||
textareaRef={textareaRef}
|
||||
workspaceId={props.instanceId}
|
||||
/>
|
||||
<Suspense fallback={null}>
|
||||
<LazyUnifiedPicker
|
||||
open={showPicker()}
|
||||
mode={pickerMode()}
|
||||
onClose={handlePickerClose}
|
||||
onSelect={handlePickerSelect}
|
||||
agents={instanceAgents()}
|
||||
commands={getCommands(props.instanceId)}
|
||||
instanceClient={instance()!.client}
|
||||
searchQuery={searchQuery()}
|
||||
textareaRef={textareaRef}
|
||||
workspaceId={props.instanceId}
|
||||
/>
|
||||
</Suspense>
|
||||
</Show>
|
||||
|
||||
<div class="flex flex-1 flex-col">
|
||||
|
||||
@@ -514,6 +514,7 @@ function ToolCallDetails(props: {
|
||||
})
|
||||
|
||||
const { renderDiffContent } = createDiffContentRenderer({
|
||||
toolState: props.toolState,
|
||||
preferences: props.preferences,
|
||||
setDiffViewMode: props.setDiffViewMode,
|
||||
isDark: props.isDark,
|
||||
|
||||
@@ -20,6 +20,14 @@ export function createAnsiContentRenderer(params: {
|
||||
const runningAnsiRenderer = createAnsiStreamRenderer()
|
||||
let runningAnsiSource = ""
|
||||
|
||||
const registerTracked = (element: HTMLDivElement | null) => {
|
||||
params.scrollHelpers.registerContainer(element)
|
||||
}
|
||||
|
||||
const registerUntracked = (element: HTMLDivElement | null) => {
|
||||
params.scrollHelpers.registerContainer(element, { disableTracking: true })
|
||||
}
|
||||
|
||||
const getMode = () => {
|
||||
const version = params.partVersion?.()
|
||||
return typeof version === "number" ? String(version) : undefined
|
||||
@@ -36,6 +44,8 @@ export function createAnsiContentRenderer(params: {
|
||||
const cached = cacheHandle.get<AnsiRenderCache>()
|
||||
const mode = getMode()
|
||||
const isRunningVariant = options.variant === "running"
|
||||
const disableScrollTracking = !isRunningVariant
|
||||
const registerRef = disableScrollTracking ? registerUntracked : registerTracked
|
||||
|
||||
let nextCache: AnsiRenderCache
|
||||
|
||||
@@ -87,9 +97,9 @@ export function createAnsiContentRenderer(params: {
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={messageClass} ref={params.scrollHelpers.registerContainer} onScroll={params.scrollHelpers.handleScroll}>
|
||||
<div class={messageClass} ref={registerRef} onScroll={disableScrollTracking ? undefined : params.scrollHelpers.handleScroll}>
|
||||
<pre class="tool-call-content tool-call-ansi" dir="auto" innerHTML={nextCache.html} />
|
||||
{params.scrollHelpers.renderSentinel()}
|
||||
{params.scrollHelpers.renderSentinel({ disableTracking: disableScrollTracking })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Suspense, lazy, onMount, type Accessor, type JSXElement } from "solid-js"
|
||||
import type { ToolState } from "@opencode-ai/sdk/v2"
|
||||
import type { RenderCache } from "../../types/message"
|
||||
import type { DiffViewMode } from "../../stores/preferences"
|
||||
import type { DiffPayload, DiffRenderOptions, ToolScrollHelpers } from "./types"
|
||||
@@ -31,6 +32,7 @@ type DiffPrefs = {
|
||||
}
|
||||
|
||||
export function createDiffContentRenderer(params: {
|
||||
toolState: Accessor<ToolState | undefined>
|
||||
preferences: Accessor<DiffPrefs>
|
||||
setDiffViewMode: (mode: DiffViewMode) => void
|
||||
isDark: Accessor<boolean>
|
||||
@@ -58,7 +60,10 @@ export function createDiffContentRenderer(params: {
|
||||
const cacheHandle = selectedVariant === "permission-diff" ? params.permissionDiffCache : params.diffCache
|
||||
const diffMode = () => (params.preferences().diffViewMode || "split") as DiffViewMode
|
||||
const themeKey = params.isDark() ? "dark" : "light"
|
||||
const disableScrollTracking = Boolean(options?.disableScrollTracking)
|
||||
const state = params.toolState()
|
||||
const disableScrollTracking = Boolean(
|
||||
options?.disableScrollTracking || (state?.status !== "running" && state?.status !== "pending"),
|
||||
)
|
||||
const registerRef = disableScrollTracking ? registerUntracked : registerTracked
|
||||
|
||||
const baseEntryParams = cacheHandle.params() as any
|
||||
|
||||
@@ -31,10 +31,9 @@ export function createMarkdownContentRenderer(params: {
|
||||
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 disableScrollTracking = options.disableScrollTracking || (state?.status !== "running" && state?.status !== "pending")
|
||||
const registerRef = disableScrollTracking ? registerUntracked : registerTracked
|
||||
const shouldDeferMarkdown = Boolean(state && (state.status === "running" || state.status === "pending") && disableHighlight)
|
||||
if (shouldDeferMarkdown) {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user