fix(desktop): restore terminal scroll position when reattaching#698
fix(desktop): restore terminal scroll position when reattaching#698
Conversation
|
Warning Rate limit exceeded@Kitenite has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 25 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThis PR introduces viewport scroll position preservation to terminal sessions. It adds an optional Changes
Sequence DiagramsequenceDiagram
participant UI as Terminal UI
participant Router as TRPC Router
participant Mgr as TerminalManager
participant XTerm as XTerm Instance
rect rgb(200, 220, 240)
Note over UI,XTerm: Reattach Flow - Restore Scroll Position
UI->>Router: createOrAttach({ paneId, ... })
Router->>Mgr: createOrAttach(...)
Mgr->>Mgr: Reuse existing session<br/>Extract viewportY
Mgr-->>Router: Return SessionResult<br/>{ ..., viewportY }
Router-->>UI: Return { ..., viewportY }
UI->>UI: applyInitialState({ ..., viewportY })
UI->>XTerm: write(scrollback)
UI->>XTerm: scrollToLine(viewportY)
end
rect rgb(240, 200, 220)
Note over UI,XTerm: Detach Flow - Capture Scroll Position
UI->>XTerm: Get currentViewportY
UI->>Router: detach({ paneId, viewportY })
Router->>Mgr: detach({ paneId, viewportY })
Mgr->>Mgr: session.viewportY = viewportY<br/>session.lastActive = now()
Mgr-->>UI: Complete
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/desktop/src/main/lib/terminal/manager.ts (1)
242-256: Consider clearing viewportY when scrollback is cleared.The detach implementation correctly stores the viewport position. However, the
clearScrollbackmethod (line 258-278) recreates the headless terminal without resettingsession.viewportY. This could result in an attempt to restore an invalid scroll position after the buffer is cleared.♻️ Suggested fix to clear viewportY in clearScrollback
clearScrollback(params: { paneId: string }): void { const { paneId } = params; const session = this.sessions.get(paneId); if (!session) { console.warn( `Cannot clear scrollback for terminal ${paneId}: session not found`, ); return; } // Recreate headless (xterm writes are async, so clear() alone is unreliable) session.headless.dispose(); const { headless, serializer } = createHeadlessTerminal({ cols: session.cols, rows: session.rows, }); session.headless = headless; session.serializer = serializer; + // Clear saved scroll position since buffer was reset + session.viewportY = undefined; session.lastActive = Date.now(); }
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/desktop/src/lib/trpc/routers/terminal/terminal.tsapps/desktop/src/main/lib/terminal/manager.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
🧰 Additional context used
📓 Path-based instructions (6)
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/lib/trpc/routers/terminal/terminal.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/terminal/manager.tsapps/desktop/src/main/lib/terminal/types.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid usinganytype - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness
Files:
apps/desktop/src/lib/trpc/routers/terminal/terminal.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/terminal/manager.tsapps/desktop/src/main/lib/terminal/types.ts
apps/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Drizzle ORM for all database operations - never use raw SQL
Files:
apps/desktop/src/lib/trpc/routers/terminal/terminal.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/terminal/manager.tsapps/desktop/src/main/lib/terminal/types.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use Biome for formatting and linting - run at root level with
bun run lint:fixorbiome check --write
Files:
apps/desktop/src/lib/trpc/routers/terminal/terminal.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/terminal/manager.tsapps/desktop/src/main/lib/terminal/types.ts
apps/desktop/src/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
One component per file - do not create multi-component files
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
⏰ 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 (6)
apps/desktop/src/lib/trpc/routers/terminal/terminal.ts (2)
99-99: LGTM - Viewport position properly propagated.The viewportY is correctly returned from the terminal manager result, enabling scroll position restoration on reattach.
155-155: LGTM - Optional viewportY accepted for persistence.The detach input schema correctly accepts an optional viewportY parameter, allowing the UI to save scroll position when detaching.
apps/desktop/src/main/lib/terminal/types.ts (1)
22-23: LGTM - Type definitions properly extended.The optional viewportY fields are correctly added to both TerminalSession and SessionResult with clear documentation. The optional nature is appropriate since new sessions won't have saved scroll positions.
Also applies to: 43-44
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (2)
374-391: LGTM - Scroll restoration correctly implemented.The use of xterm.write callback ensures the scrollback content is fully rendered before restoring the scroll position. This prevents race conditions where scrollToLine might be called on an incomplete buffer.
570-574: LGTM - Scroll position properly captured on detach.The viewport position is correctly captured from
xterm.buffer.active.viewportYbefore detachment and passed as an object parameter following the coding guidelines.apps/desktop/src/main/lib/terminal/manager.ts (1)
44-44: LGTM - Saved scroll position returned on reattach.When reusing an existing session, the stored viewportY is correctly returned to enable scroll position restoration.
Save the viewport scroll position when detaching a terminal and restore it when reattaching. This prevents losing the scroll position when switching between tabs. - Add viewportY to TerminalSession and SessionResult types - Store viewportY in session on detach - Return viewportY from createOrAttach when reattaching - Use xterm.write callback to restore scroll after content is rendered 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
b4cfe85 to
1f12237
Compare
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
* fix(desktop): restore terminal scroll position when reattaching Save the viewport scroll position when detaching a terminal and restore it when reattaching. This prevents losing the scroll position when switching between tabs. - Add viewportY to TerminalSession and SessionResult types - Store viewportY in session on detach - Return viewportY from createOrAttach when reattaching - Use xterm.write callback to restore scroll after content is rendered
Summary
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.