Preserve existing panes when applying a preset
Previously: clicking 1 / 2H / 3H / 2V / 2×2 in the titlebar replaced the whole tree with brand-new empty leaves, killing every shell — and the only safeguard was a window.confirm() that's easy to miss-click. The user lost work whenever they reached for a preset. New behaviour via `reshapeToPreset`: - The preset's shape is built fresh (1, 2, 3, or 4 slots), then existing leaves are spliced into those slots in DFS order. Their id / distro / cwd / label / broadcast all carry over, so the same PaneId is still mapped — the PTY keeps running. - If the preset has MORE slots than existing leaves (e.g. 1 pane → 2×2), the extra slots stay as fresh empty leaves and new shells spawn there. No prompt — pure additive change. - If the preset has FEWER slots than existing leaves (e.g. 8 panes → 2×2), the overflow leaves are returned in `dropped`. We confirm with the user, and if they accept, kill those PTYs explicitly. Tradeoff: split ratios reset to 0.5 (the whole point of "apply preset" is to use its layout). That's an acceptable cost. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
2a0c096095
commit
8c3af8f9ee
2 changed files with 68 additions and 10 deletions
36
src/App.tsx
36
src/App.tsx
|
|
@ -22,6 +22,7 @@ import {
|
|||
changeLabel,
|
||||
toggleBroadcast as toggleBroadcastInTree,
|
||||
setAllBroadcast,
|
||||
reshapeToPreset,
|
||||
serialize,
|
||||
deserialize,
|
||||
presetSingle,
|
||||
|
|
@ -264,18 +265,33 @@ export default function App() {
|
|||
|
||||
const applyPreset = useCallback(
|
||||
(make: (d: { distro?: string }) => TreeNode) => {
|
||||
const count = leafCount(tree);
|
||||
if (
|
||||
count > 1 &&
|
||||
!window.confirm(
|
||||
`Replace current layout (${count} panes)? This kills all open shells.`,
|
||||
)
|
||||
) {
|
||||
return;
|
||||
const { tree: nextTree, dropped } = reshapeToPreset(tree, make, {
|
||||
distro: defaultDistro,
|
||||
});
|
||||
|
||||
if (dropped.length > 0) {
|
||||
const ok = window.confirm(
|
||||
`This preset has fewer slots than your current ${leafCount(tree)} panes. ${dropped.length} pane${dropped.length === 1 ? "" : "s"} will be closed (their shells will be killed). Continue?`,
|
||||
);
|
||||
if (!ok) return;
|
||||
|
||||
for (const id of dropped) {
|
||||
const paneId = paneIdByLeafRef.current.get(id);
|
||||
if (paneId != null) {
|
||||
void killPane(paneId).catch((e) =>
|
||||
console.warn("killPane failed:", e),
|
||||
);
|
||||
paneIdByLeafRef.current.delete(id);
|
||||
}
|
||||
}
|
||||
if (activeLeafId && dropped.includes(activeLeafId)) {
|
||||
setActiveLeafId(null);
|
||||
}
|
||||
}
|
||||
setTree(make({ distro: defaultDistro }));
|
||||
|
||||
setTree(nextTree);
|
||||
},
|
||||
[tree, defaultDistro],
|
||||
[tree, defaultDistro, activeLeafId],
|
||||
);
|
||||
|
||||
const paletteLeaves = useMemo<LeafNode[]>(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue