fix(terminal): prevent doomscroll when reviewing scrollback (#1616)
The synchronizeScrollView() method was constantly resetting the scroll position to match the terminal's scrollbar state, even when the user had manually scrolled up to review scrollback. This caused the 'doomscroll' bug where panes would fight the user's scroll position. - Add userScrolledAwayFromBottom flag to track scroll intent - Only auto-scroll when at bottom or when scrollbar indicates following - Reset flag when user scrolls back to bottom - Add 5-point threshold to tolerate minor float drift Fixes #1577 Co-authored-by: BillionClaw <267901332+BillionClaw@users.noreply.github.com>
This commit is contained in:
parent
c0fd15cdd7
commit
1fabe9f33c
1 changed files with 36 additions and 2 deletions
|
|
@ -6106,6 +6106,12 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
private var windowObservers: [NSObjectProtocol] = []
|
||||
private var isLiveScrolling = false
|
||||
private var lastSentRow: Int?
|
||||
/// Tracks whether the user has scrolled away from the bottom to review scrollback.
|
||||
/// When true, auto-scroll should be suspended to prevent the "doomscroll" bug
|
||||
/// where the terminal fights the user's scroll position.
|
||||
private var userScrolledAwayFromBottom = false
|
||||
/// Threshold in points from bottom to consider "at bottom" (allows for minor float drift)
|
||||
private static let scrollToBottomThreshold: CGFloat = 5.0
|
||||
private var isActive = true
|
||||
private var lastFocusRefreshAt: CFTimeInterval = 0
|
||||
private var activeDropZone: DropZone?
|
||||
|
|
@ -6433,6 +6439,8 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
queue: .main
|
||||
) { [weak self] _ in
|
||||
self?.isLiveScrolling = false
|
||||
// Final scroll position check to update userScrolledAwayFromBottom state
|
||||
self?.handleLiveScroll()
|
||||
})
|
||||
|
||||
observers.append(NotificationCenter.default.addObserver(
|
||||
|
|
@ -8349,11 +8357,29 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
let offsetY =
|
||||
CGFloat(scrollbar.total - scrollbar.offset - scrollbar.len) * cellHeight
|
||||
let targetOrigin = CGPoint(x: 0, y: offsetY)
|
||||
if !pointApproximatelyEqual(scrollView.contentView.bounds.origin, targetOrigin) {
|
||||
|
||||
// Check if we're currently at the bottom (with threshold for float drift)
|
||||
let currentOrigin = scrollView.contentView.bounds.origin
|
||||
let documentHeight = documentView.frame.height
|
||||
let viewportHeight = scrollView.contentView.bounds.height
|
||||
let distanceFromBottom = documentHeight - currentOrigin.y - viewportHeight
|
||||
let isAtBottom = distanceFromBottom <= Self.scrollToBottomThreshold
|
||||
|
||||
// Update userScrolledAwayFromBottom based on current position
|
||||
if isAtBottom {
|
||||
userScrolledAwayFromBottom = false
|
||||
}
|
||||
|
||||
// Only auto-scroll if user hasn't manually scrolled away from bottom
|
||||
// or if we're following terminal output (scrollbar shows we're at bottom)
|
||||
let shouldAutoScroll = !userScrolledAwayFromBottom ||
|
||||
(scrollbar.offset + scrollbar.len >= scrollbar.total)
|
||||
|
||||
if shouldAutoScroll && !pointApproximatelyEqual(currentOrigin, targetOrigin) {
|
||||
#if DEBUG
|
||||
logDragGeometryChange(
|
||||
event: "scrollOrigin",
|
||||
old: scrollView.contentView.bounds.origin,
|
||||
old: currentOrigin,
|
||||
new: targetOrigin
|
||||
)
|
||||
#endif
|
||||
|
|
@ -8380,6 +8406,14 @@ final class GhosttySurfaceScrollView: NSView {
|
|||
let visibleRect = scrollView.contentView.documentVisibleRect
|
||||
let documentHeight = documentView.frame.height
|
||||
let scrollOffset = documentHeight - visibleRect.origin.y - visibleRect.height
|
||||
|
||||
// Track if user has scrolled away from bottom to review scrollback
|
||||
if scrollOffset > Self.scrollToBottomThreshold {
|
||||
userScrolledAwayFromBottom = true
|
||||
} else if scrollOffset <= 0 {
|
||||
userScrolledAwayFromBottom = false
|
||||
}
|
||||
|
||||
let row = Int(scrollOffset / cellHeight)
|
||||
|
||||
guard row != lastSentRow else { return }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue