Repository navigation
iOS terminal: keep live tail pinned through keyboard/font layout resizes - #700
Conversation
A keyboard-driven view shrink stranded the viewport above the live tail in sessions with large scrollback: SwiftTerm only re-snaps to the bottom when cols/rows change, and a mouse-mode TUI (Claude Code) repaints in place afterward, so no scroll event ever self-healed the offset — the prompt stayed hidden behind the keyboard with no Live pill to escape. - Re-assert the live tail (resumeAutoScroll) one runloop after any layout size change or pinch font change while pinned; users who scrolled up keep their spot and the Live pill flow is untouched. - Guard scrollViewDidScroll on isDragging (not isTracking) so a programmatic bottom snap landing during a stationary tap-to-focus can't be misread as a user scroll. - Extract the pure isAtLiveTail predicate + regression tests anchoring the keyboard-shrink geometry flip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
Warning Review limit reached
Next review available in: 12 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
|
@copilot review but do not make fixes |
Summary
Fixes the user-reported iOS bug where tapping to type in a CLI session terminal raised the keyboard but the terminal content did not follow — in sessions with large scrollback (e.g. long-running Claude Code sessions) the prompt/input line stayed hidden behind the keyboard.
Root cause. When the keyboard shrinks the SwiftTerm view, SwiftTerm only re-snaps the viewport to the bottom when the resize changes cols/rows (partly via a deferred main-queue hop), and a mouse-mode TUI like Claude Code repaints in place afterward — no scroll events ever arrive to self-heal a stranded offset. With
isPinnedToBottomstill true there was not even a "↓ Live" pill to escape with. Short transcripts survived because the content fits the shrunken viewport anyway.Fix (surgical, no pinning redesign):
resumeAutoScroll) one runloop later — after SwiftTerm's own deferred scroller sync. Same re-assert after pinch-zoom font changes (content height changes without a bounds change).scrollViewDidScrollnow gates onisDragginginstead ofisTracking, so a programmatic bottom snap landing during a stationary tap-to-focus can't be misread as a user scroll-up.isAtLiveTailpredicate (namedliveTailSlackconstant) used byupdatePinState, with regression tests anchoring the keyboard-shrink geometry flip.Real scroll-up behavior is unchanged: dragging up during output still un-pins and shows the "↓ Live N" pill; tapping it returns to the tail; readers who scrolled up keep their spot through keyboard transitions.
Validation
xcodebuildDebug build: BUILD SUCCEEDEDADETests/TerminalLiveTailPinningTests(3 tests): pass on iPhone 17 Pro simulatorios-companion.mdterminal-viewer prose updated with the new invariant🤖 Generated with Claude Code
Greptile Summary
This PR keeps the iOS terminal pinned to the live tail during keyboard and layout changes. The main changes are:
Confidence Score: 5/5
Safe to merge with low risk.
The changes are narrowly scoped to terminal scroll-pinning behavior and include regression coverage for the key keyboard-shrink case.
No files require special attention.
What T-Rex did
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Layout as SwiftTerm layout/font change participant Controller as TerminalSessionController participant SwiftTerm as ADESwiftTermView participant User as User scroll input Layout->>Controller: handleTerminalLayout() / handlePinch() Controller->>Controller: sendResizeIfNeeded(cols, rows) alt viewport size changed or font metrics changed Controller->>Controller: reassertLiveTailIfPinned() Controller-->>SwiftTerm: resumeAutoScroll() on next runloop end User->>SwiftTerm: drag/decelerate scroll SwiftTerm->>Controller: scrollViewDidScroll() Controller->>Controller: updatePinState() only for isDragging/isDecelerating alt user returns near live tail Controller-->>SwiftTerm: allow output auto-scroll else user scrolls up Controller-->>SwiftTerm: hold scroll on output end%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Layout as SwiftTerm layout/font change participant Controller as TerminalSessionController participant SwiftTerm as ADESwiftTermView participant User as User scroll input Layout->>Controller: handleTerminalLayout() / handlePinch() Controller->>Controller: sendResizeIfNeeded(cols, rows) alt viewport size changed or font metrics changed Controller->>Controller: reassertLiveTailIfPinned() Controller-->>SwiftTerm: resumeAutoScroll() on next runloop end User->>SwiftTerm: drag/decelerate scroll SwiftTerm->>Controller: scrollViewDidScroll() Controller->>Controller: updatePinState() only for isDragging/isDecelerating alt user returns near live tail Controller-->>SwiftTerm: allow output auto-scroll else user scrolls up Controller-->>SwiftTerm: hold scroll on output endReviews (1): Last reviewed commit: "docs: note layout-resize live-tail re-as..." | Re-trigger Greptile