perf(renderer): index terminal unified tab reads (#8076)
This commit is contained in:
parent
09196ba086
commit
106009a90c
|
|
@ -180,7 +180,10 @@ import {
|
|||
subscribeTerminalPaneAttention
|
||||
} from './terminal-pane-attention-subscriptions'
|
||||
import { getCachedTerminalTabForWorktree } from './terminal-tab-lookup'
|
||||
import { getCachedTerminalGroupIdForWorktree } from './terminal-unified-tab-lookup'
|
||||
import {
|
||||
getCachedTerminalGroupIdForWorktree,
|
||||
getCachedUnifiedTerminalTabForWorktree
|
||||
} from './terminal-unified-tab-lookup'
|
||||
import { resolveNativeChatLeafTitleAgent } from './native-chat-leaf-title-agent'
|
||||
import { useRepoById } from '@/store/selectors'
|
||||
import {
|
||||
|
|
@ -655,23 +658,18 @@ export default function TerminalPane({
|
|||
// communicates the presence-lock inside the chat surface instead (U9/R8).
|
||||
const unifiedTabId = useAppStore(
|
||||
(store) =>
|
||||
(store.unifiedTabsByWorktree[worktreeId] ?? []).find(
|
||||
(t) => t.contentType === 'terminal' && t.entityId === tabId
|
||||
)?.id
|
||||
getCachedUnifiedTerminalTabForWorktree(store.unifiedTabsByWorktree, worktreeId, tabId)?.id
|
||||
)
|
||||
const isChatViewMode = useAppStore(
|
||||
(store) =>
|
||||
(store.unifiedTabsByWorktree[worktreeId] ?? []).find(
|
||||
(t) => t.contentType === 'terminal' && t.entityId === tabId
|
||||
)?.viewMode === 'chat'
|
||||
getCachedUnifiedTerminalTabForWorktree(store.unifiedTabsByWorktree, worktreeId, tabId)
|
||||
?.viewMode === 'chat'
|
||||
)
|
||||
const nativeChatEnabled = useAppStore((store) => store.settings?.experimentalNativeChat === true)
|
||||
const effectiveChatViewMode = nativeChatEnabled && isChatViewMode
|
||||
const unifiedTabLabel = useAppStore(
|
||||
(store) =>
|
||||
(store.unifiedTabsByWorktree[worktreeId] ?? []).find(
|
||||
(t) => t.contentType === 'terminal' && t.entityId === tabId
|
||||
)?.label
|
||||
getCachedUnifiedTerminalTabForWorktree(store.unifiedTabsByWorktree, worktreeId, tabId)?.label
|
||||
)
|
||||
const runtimePaneTitlesByPaneId = useAppStore(
|
||||
useShallow((store) => store.runtimePaneTitlesByTabId[tabId] ?? {})
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { Tab } from '../../../../shared/types'
|
||||
import { getCachedTerminalGroupIdForWorktree } from './terminal-unified-tab-lookup'
|
||||
import {
|
||||
getCachedTerminalGroupIdForWorktree,
|
||||
getCachedUnifiedTerminalTabForWorktree
|
||||
} from './terminal-unified-tab-lookup'
|
||||
|
||||
function makeTerminalTab(entityId: string, groupId: string): Tab {
|
||||
return {
|
||||
|
|
@ -45,8 +48,8 @@ function iterableTabs(tabs: Tab[]): {
|
|||
}
|
||||
}
|
||||
|
||||
describe('getCachedTerminalGroupIdForWorktree', () => {
|
||||
it('reuses the terminal group lookup while the unified tab array is unchanged', () => {
|
||||
describe('terminal unified tab lookup', () => {
|
||||
it('shares one terminal lookup across all pane field and group reads', () => {
|
||||
const tabs = [
|
||||
makeEditorTab('editor-1'),
|
||||
...Array.from({ length: 200 }, (_, index) =>
|
||||
|
|
@ -56,14 +59,23 @@ describe('getCachedTerminalGroupIdForWorktree', () => {
|
|||
const { value, iterator } = iterableTabs(tabs)
|
||||
const unifiedTabsByWorktree = { 'wt-1': value }
|
||||
|
||||
expect(getCachedTerminalGroupIdForWorktree(unifiedTabsByWorktree, 'wt-1', 'terminal-199')).toBe(
|
||||
'group-3'
|
||||
)
|
||||
for (let index = 0; index < 200; index += 1) {
|
||||
const terminalTabId = `terminal-${index}`
|
||||
expect(
|
||||
getCachedUnifiedTerminalTabForWorktree(unifiedTabsByWorktree, 'wt-1', terminalTabId)
|
||||
).toBe(tabs[index + 1])
|
||||
expect(
|
||||
getCachedUnifiedTerminalTabForWorktree(unifiedTabsByWorktree, 'wt-1', terminalTabId)?.id
|
||||
).toBe(terminalTabId)
|
||||
expect(
|
||||
getCachedUnifiedTerminalTabForWorktree(unifiedTabsByWorktree, 'wt-1', terminalTabId)?.label
|
||||
).toBe(terminalTabId)
|
||||
}
|
||||
expect(getCachedTerminalGroupIdForWorktree(unifiedTabsByWorktree, 'wt-1', 'terminal-0')).toBe(
|
||||
'group-0'
|
||||
)
|
||||
expect(
|
||||
getCachedTerminalGroupIdForWorktree(unifiedTabsByWorktree, 'wt-1', 'editor-1')
|
||||
getCachedUnifiedTerminalTabForWorktree(unifiedTabsByWorktree, 'wt-1', 'editor-1')
|
||||
).toBeNull()
|
||||
|
||||
expect(iterator).toHaveBeenCalledTimes(1)
|
||||
|
|
@ -73,9 +85,9 @@ describe('getCachedTerminalGroupIdForWorktree', () => {
|
|||
const first = iterableTabs([makeTerminalTab('terminal-1', 'group-a')])
|
||||
const second = iterableTabs([makeTerminalTab('terminal-1', 'group-b')])
|
||||
|
||||
expect(getCachedTerminalGroupIdForWorktree({ 'wt-1': first.value }, 'wt-1', 'terminal-1')).toBe(
|
||||
'group-a'
|
||||
)
|
||||
expect(
|
||||
getCachedUnifiedTerminalTabForWorktree({ 'wt-1': first.value }, 'wt-1', 'terminal-1')?.groupId
|
||||
).toBe('group-a')
|
||||
expect(
|
||||
getCachedTerminalGroupIdForWorktree({ 'wt-1': second.value }, 'wt-1', 'terminal-1')
|
||||
).toBe('group-b')
|
||||
|
|
|
|||
|
|
@ -1,29 +1,40 @@
|
|||
import type { Tab } from '../../../../shared/types'
|
||||
|
||||
const terminalGroupLookupByUnifiedTabs = new WeakMap<readonly Tab[], Map<string, string>>()
|
||||
const terminalTabLookupByUnifiedTabs = new WeakMap<readonly Tab[], Map<string, Tab>>()
|
||||
|
||||
export function getCachedUnifiedTerminalTabForWorktree(
|
||||
unifiedTabsByWorktree: Record<string, Tab[]>,
|
||||
worktreeId: string,
|
||||
terminalTabId: string
|
||||
): Tab | null {
|
||||
const unifiedTabs = unifiedTabsByWorktree[worktreeId]
|
||||
if (!unifiedTabs) {
|
||||
return null
|
||||
}
|
||||
|
||||
let lookup = terminalTabLookupByUnifiedTabs.get(unifiedTabs)
|
||||
if (!lookup) {
|
||||
// Why: every retained TerminalPane reads this tab on every store update.
|
||||
// Share one immutable-array index instead of repeating linear scans.
|
||||
lookup = new Map()
|
||||
for (const tab of unifiedTabs) {
|
||||
if (tab.contentType === 'terminal') {
|
||||
lookup.set(tab.entityId, tab)
|
||||
}
|
||||
}
|
||||
terminalTabLookupByUnifiedTabs.set(unifiedTabs, lookup)
|
||||
}
|
||||
|
||||
return lookup.get(terminalTabId) ?? null
|
||||
}
|
||||
|
||||
export function getCachedTerminalGroupIdForWorktree(
|
||||
unifiedTabsByWorktree: Record<string, Tab[]>,
|
||||
worktreeId: string,
|
||||
terminalTabId: string
|
||||
): string | null {
|
||||
const unifiedTabs = unifiedTabsByWorktree[worktreeId]
|
||||
if (!unifiedTabs) {
|
||||
return null
|
||||
}
|
||||
|
||||
let lookup = terminalGroupLookupByUnifiedTabs.get(unifiedTabs)
|
||||
if (!lookup) {
|
||||
// Why: every mounted TerminalPane asks for its owning group on store updates.
|
||||
// Cache by immutable tab-array ref so 200 panes do not repeat the same scan.
|
||||
lookup = new Map()
|
||||
for (const tab of unifiedTabs) {
|
||||
if (tab.contentType === 'terminal') {
|
||||
lookup.set(tab.entityId, tab.groupId)
|
||||
}
|
||||
}
|
||||
terminalGroupLookupByUnifiedTabs.set(unifiedTabs, lookup)
|
||||
}
|
||||
|
||||
return lookup.get(terminalTabId) ?? null
|
||||
return (
|
||||
getCachedUnifiedTerminalTabForWorktree(unifiedTabsByWorktree, worktreeId, terminalTabId)
|
||||
?.groupId ?? null
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue