Skip to content

keep terminal tabs rendered - #147

Merged
Kitenite merged 1 commit into
mainfrom
pearl-mountain-56
Nov 26, 2025
Merged

Kitenite merged 1 commit into
mainfrom
pearl-mountain-56

Conversation

@Kitenite

@Kitenite Kitenite commented Nov 26, 2025 •

Copy link
Copy Markdown
Member

Summary by CodeRabbit

Release Notes

Bug Fixes

  • Terminal startup now properly initializes environment profiles from package managers
  • Tab rendering improved to maintain terminal history for all open tabs

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Nov 26, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Terminal-manager now spawns shell processes as login shells by computing platform-specific arguments (zsh/bash use "-l") and passing them to pty.spawn. TabsContent refactors tab rendering to compute all workspace tabs within a memo, determine the active tab's display hierarchy, and render all workspace tabs while hiding non-active ones to preserve terminal scrollback.

Changes

Cohort / File(s) Summary
Terminal login shell initialization
apps/desktop/src/main/lib/terminal-manager.ts
Computes shellArgs based on shell type (zsh/bash get ["-l"], others get []) and passes them to pty.spawn to ensure profile scripts initialize before shell rc files.
Tab rendering and workspace state
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
Refactors tabToRender computation to collect all workspace tabs, handle tab hierarchy (parent/child relationships), determine active tab display state, and render all workspace tabs as hidden components (except active) to preserve terminal scrollback. Updates drop overlay scoping to active tab only.

Sequence Diagram(s)

sequenceDiagram
    participant Spawner as Terminal Spawner
    participant PTY as pty.spawn
    participant Shell as Shell Process
    
    rect rgb(200, 220, 255)
    note over Spawner,Shell: New Login Shell Flow
    Spawner->>Spawner: Detect shell type (zsh/bash/other)
    Spawner->>Spawner: Compute shellArgs (["-l"] or [])
    Spawner->>PTY: spawn(shell, shellArgs, options)
    PTY->>Shell: Execute shell with args
    Shell->>Shell: Load profile scripts (pyenv, nvm, etc.)
    Shell->>Shell: Load rc files
    end
Loading
sequenceDiagram
    participant Render as TabsContent Render
    participant Memo as useMemo
    participant Logic as Tab Logic
    participant DOM as DOM Render
    
    rect rgb(220, 240, 220)
    note over Render,DOM: New Tab Rendering Flow
    Render->>Memo: Compute tabToRender + workspaceTabs
    Memo->>Logic: Collect all workspace tabs for active workspace
    Logic->>Logic: Find active tab, resolve parent hierarchy
    Logic->>Memo: Return {tabToRender, workspaceTabs}
    Memo->>DOM: Render active tab (visible)
    Memo->>DOM: Render hidden workspace tabs (preserve scrollback)
    DOM->>DOM: Apply drop overlay only to active tab
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • TabsContent refactoring requires careful verification of tab hierarchy resolution, null-handling edge cases (no activeWorkspaceId, no activeTabId, parent lookup), and confirmation that hidden tab rendering preserves scrollback without performance degradation.
  • Drop overlay scoping needs validation that conditional drop zone logic correctly isolates to the active tab only.
  • Terminal shell args addition is straightforward but verify shellArgs logic handles all shell types correctly and passes arguments in the expected format to pty.spawn.

Possibly related PRs

  • PR #120: Rewrites TerminalManager.createOrAttach to be async and add history/wasRecovered, directly overlaps with this PR's modifications to the same terminal spawning function.
  • PR #106: Refactors TabsContent UI/drag-drop/DropOverlay logic, touching the same rendering component and drop zone behavior.
  • PR #105: Modifies the same file (TabsContent/index.tsx) and changes tab rendering logic, directly related at code level.

Poem

🐰 A shell springs forth in login attire,
Profile scripts load, as dreams inspire,
Tabs hidden beneath, their scrollback preserved,
The active one gleams—each interaction served!
~CodeRabbit 🌿

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, leaving all required sections from the template (Description, Related Issues, Type of Change, Testing, Screenshots, Additional Notes) completely empty. Add a comprehensive description following the repository template, including what changes were made, related issues, the type of change, testing performed, and any additional context.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title 'keep terminal tabs rendered' is specific and directly related to the main change in the TabsContent component, which replaces single-tab rendering with multi-tab rendering to preserve terminal scrollback behavior.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pearl-mountain-56

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Kitenite Kitenite changed the title pearl mountain 56 keep terminal tabs rendered Nov 26, 2025
@Kitenite
Kitenite merged commit bf95d1a into main Nov 26, 2025
0 of 5 checks passed
@Kitenite
Kitenite deleted the pearl-mountain-56 branch November 26, 2025 07:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b8473d and 26bd1db.

📒 Files selected for processing (2)
  • apps/desktop/src/main/lib/terminal-manager.ts (1 hunks)
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx,js,jsx,json}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Biome formatting, linting, and import organization at the root level for all code files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/main/lib/terminal-manager.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid using any type; use type-safe approaches instead, unless necessary
Ensure TypeScript type checking passes across all packages using bun run typecheck

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/main/lib/terminal-manager.ts
apps/**/*.{tsx,ts}

📄 CodeRabbit inference engine (AGENTS.md)

apps/**/*.{tsx,ts}: Structure React applications with one folder per component following the pattern: ComponentName/ComponentName.tsx with index.ts barrel export
Co-locate component dependencies (hooks, utils, constants, tests, stories) next to the file using them

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/main/lib/terminal-manager.ts
apps/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Use one component per file; do not create multi-component files

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
apps/desktop/src/renderer/**/*.tsx

📄 CodeRabbit inference engine (AGENTS.md)

Define keyboard shortcuts using the centralized system in apps/desktop/src/renderer/lib/shortcuts.ts with Arc Browser-inspired shortcut definitions

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
apps/desktop/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/main/lib/terminal-manager.ts
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: Please use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
  • apps/desktop/src/main/lib/terminal-manager.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (3)
apps/desktop/src/main/lib/terminal-manager.ts (1)

90-94: LGTM! Login shell spawning logic is correct.

The -l flag for zsh/bash ensures profile files like .zprofile/.bash_profile are sourced, which is necessary for tools like pyenv, nvm, and rbenv that modify PATH in profile files. The includes() check correctly matches shell paths (e.g., /bin/zsh, /usr/bin/bash), and the fallback to an empty array for other shells (fish, PowerShell) is appropriate since they handle initialization differently.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx (2)

16-41: LGTM! Well-structured memoized computation.

The memo correctly computes both tabToRender and workspaceTabs with proper guards for missing workspace/tab IDs. The dependency array is complete, and the parent group resolution logic correctly handles nested tabs.


67-91: LGTM! Effective approach for preserving terminal scrollback.

Using visibility: hidden instead of conditional rendering keeps xterm.js instances mounted, preserving their internal state and scrollback buffer. The isDropZone prop is correctly scoped to only the active tab, and the single DropOverlay render at the end avoids duplication.

Comment on lines 47 to 64
<div ref={attachDrop} className="flex-1 h-full">
<EmptyTabView />
{/* Render all workspace tabs hidden to preserve terminal scrollback */}
{workspaceTabs.map((tab) => (
<div
key={tab.id}
className="w-full h-full absolute inset-0"
style={{ visibility: "hidden", pointerEvents: "none" }}
>
{tab.type === TabType.Single ? (
<SingleTabView tab={tab} isDropZone={false} />
) : (
<GroupTabView tab={tab} />
)}
</div>
))}
</div>
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing relative class on container for absolute-positioned children.

The hidden tabs use absolute inset-0 positioning, but this container lacks relative positioning (unlike the container on line 68). This could cause the hidden tabs to position incorrectly relative to an unintended ancestor.

-			<div ref={attachDrop} className="flex-1 h-full">
+			<div ref={attachDrop} className="flex-1 h-full relative">
🤖 Prompt for AI Agents
In
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/index.tsx
around lines 47 to 64, the container div wrapping EmptyTabView and the hidden
workspace tab divs is missing the "relative" class so its absolutely-positioned
children (absolute inset-0) may be positioned relative to an unintended
ancestor; add the "relative" class to that container's className (e.g., include
"relative" alongside "flex-1 h-full") so the absolute-positioned tab panes are
correctly contained and positioned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant