mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
refactor(terminal): fold the owned-leaf rule into its only consumer
The leaf-claims module had two functions for two readers; with the hydration heal gone, one has no reader and the other has exactly one. Inline it, keeping the empty-binding filter and the reason for it, and drop the module. Also rewords the comments that explained an unbound leaf by the heal. A pane keeps its leaf after its PTY exits, which is the reason that outlives this change.
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
import type { TerminalPaneLayoutNode } from '../../../../shared/terminal-tab-types'
|
||||
import { collectLeafIdsInOrder } from './terminal-layout-leaf-ids'
|
||||
|
||||
export type TerminalLayoutLeafClaims = {
|
||||
root: TerminalPaneLayoutNode | null
|
||||
activeLeafId?: string | null
|
||||
ptyIdsByLeafId?: Record<string, string>
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaf ids a rootless layout actually binds. The persisted map types its values as a plain
|
||||
* string, so an empty one survives the schema and is not a binding: counting it would let a
|
||||
* layout look like it holds a leaf no session is attached to.
|
||||
*/
|
||||
function boundLeafIds(layout: TerminalLayoutLeafClaims): string[] {
|
||||
return Object.entries(layout.ptyIdsByLeafId ?? {})
|
||||
.filter(([, ptyId]) => Boolean(ptyId))
|
||||
.map(([leafId]) => leafId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaf ids this layout holds, read generously: its tree, or — for a rootless layout, which binds
|
||||
* its sole pane off-tree — every leaf it binds. Use this to ask "does some pane already hold
|
||||
* this?", where over-counting only costs a reveal that adopts instead of minting.
|
||||
*
|
||||
* A binding whose leaf has left a rooted tree reattaches nothing, so it is excluded either way.
|
||||
*/
|
||||
export function collectOwnedLeafIds(layout: TerminalLayoutLeafClaims): Set<string> {
|
||||
return new Set(layout.root ? collectLeafIdsInOrder(layout.root) : boundLeafIds(layout))
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaf ids this layout may take from another tab, read narrowly. Same as the owned set for a
|
||||
* rooted layout, but a rootless one proves only its sole off-tree pane, or the one its
|
||||
* `activeLeafId` names: a never-pruned map holds more than it owns, and claiming those evicts
|
||||
* the live row that really owns them (#13098). Mirrors the `owned`/`claimable` split in
|
||||
* `terminal-session-row-hydration.ts`, which is the guard that caught #13060.
|
||||
*/
|
||||
export function collectClaimableLeafIds(layout: TerminalLayoutLeafClaims): Set<string> {
|
||||
if (layout.root) {
|
||||
return new Set(collectLeafIdsInOrder(layout.root))
|
||||
}
|
||||
const leafIds = boundLeafIds(layout)
|
||||
const provenLeafId = leafIds.length === 1 ? leafIds[0] : layout.activeLeafId
|
||||
return new Set(leafIds.filter((leafId) => leafId === provenLeafId))
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { collectOwnedLeafIds } from '@/components/terminal-pane/terminal-layout-leaf-claims'
|
||||
import { collectLeafIdsInOrder } from '@/components/terminal-pane/terminal-layout-leaf-ids'
|
||||
import type { TerminalLayoutSnapshot } from '../../../shared/terminal-tab-types'
|
||||
import type { AppState } from '@/store/types'
|
||||
|
||||
/** No `tabsByWorktree`: ownership is tab-keyed, so no worktree key participates. */
|
||||
@@ -22,6 +23,26 @@ export type TerminalPtyPaneOwnerOptions = {
|
||||
preferTabId?: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaf ids this layout holds: its tree, or — for a rootless layout, which binds its sole pane
|
||||
* off-tree — every leaf it actually binds. A binding whose leaf has left a rooted tree reattaches
|
||||
* nothing, so it must not outrank a live pane (#13098).
|
||||
*
|
||||
* Why the truthiness check: the persisted map types its values as a plain string, so an empty one
|
||||
* survives the schema and is not a binding. Counting it would name a leaf no session is attached
|
||||
* to, and a reveal that adopted that tab would show nothing.
|
||||
*/
|
||||
function collectOwnedLeafIds(layout: TerminalLayoutSnapshot): Set<string> {
|
||||
if (layout.root) {
|
||||
return new Set(collectLeafIdsInOrder(layout.root))
|
||||
}
|
||||
return new Set(
|
||||
Object.entries(layout.ptyIdsByLeafId ?? {})
|
||||
.filter(([, ptyId]) => Boolean(ptyId))
|
||||
.map(([leafId]) => leafId)
|
||||
)
|
||||
}
|
||||
|
||||
/** The leaf a tab's layout binds to `ptyId`, or null when no leaf it owns holds that binding. */
|
||||
function findLayoutBoundLeafId(
|
||||
state: TerminalPtyPaneOwnerState,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Which tab owns a leaf id decides whether a reveal adopts a pane or mints a second one
|
||||
// (STA-7961). Two layouts can name the same leaf: one that still mounts it, and one left
|
||||
// holding the id by a detach or by the hydration self-heal.
|
||||
// holding the id by a detach.
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { findTerminalTabIdBindingLeafId } from './terminal-reveal-tab-adoption'
|
||||
import type { AppState } from '@/store/types'
|
||||
@@ -47,7 +47,7 @@ describe('findTerminalTabIdBindingLeafId', () => {
|
||||
})
|
||||
|
||||
it('prefers the tab that binds the leaf over one that only carries it unbound', () => {
|
||||
// The hydration self-heal unbinds the losing single-leaf tab but leaves the id in its tree.
|
||||
// A pane keeps its leaf in the tree after its PTY exits, so the id outlives the binding.
|
||||
const bound = layout(leaf(SHARED_LEAF_ID), { [SHARED_LEAF_ID]: 'pty-a' })
|
||||
const unbound = layout(leaf(SHARED_LEAF_ID))
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ export type TerminalRevealTabAdoption =
|
||||
| { kind: 'mint' }
|
||||
|
||||
/**
|
||||
* The tab whose layout owns a leaf id. Bound-and-in-tree beats in-tree-unbound, because the
|
||||
* hydration self-heal leaves a losing single-leaf tab carrying its leaf with no session to adopt.
|
||||
* The tab whose layout owns a leaf id. Bound-and-in-tree beats in-tree-unbound, because a pane
|
||||
* keeps its leaf after its PTY exits or is cleared, and such a tab has no session to adopt.
|
||||
* Every layout is scanned, including ones whose row is gone: a leaf id is a pane identity for its
|
||||
* lifetime, and re-minting one an orphan layout still holds is how the STA-7961 pair was created.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user