mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-08 08:29:42 +02:00
feat(terminal): ease-out smooth scrolling for the local wheel path
The capture-phase handler owns local scrolling (xterm's smooth scroller is bypassed for the stale-dimensions reasons documented there), which made every notch an instant multi-line jump. Wheel deltas now accumulate into a pending line count drained ~35% per animation frame with a one-line floor, so scrolling glides and extra notches mid-glide read as acceleration. Pending momentum is dropped on session switch so it never scrolls the tab the user just switched to. Verified on the beta: a 20-line notch eases over 9 frames to an exact landing, and the 9-check scroll matrix still passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -457,8 +457,7 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._noteTerminalUserScroll(lines);
|
this._noteTerminalUserScroll(lines);
|
||||||
this.terminal.scrollLines(lines);
|
this._smoothScrollBy(lines);
|
||||||
this._maybeLoadMoreHistoryOnScroll(lines);
|
|
||||||
},
|
},
|
||||||
{ passive: false, capture: true }
|
{ passive: false, capture: true }
|
||||||
);
|
);
|
||||||
@@ -2077,6 +2076,40 @@ Object.assign(CodemanApp.prototype, {
|
|||||||
if (this.terminal?.buffer?.active?.viewportY === 0) this._maybeRefetchFullHistory?.();
|
if (this.terminal?.buffer?.active?.viewportY === 0) this._maybeRefetchFullHistory?.();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ease-out smooth scrolling for the local wheel path. The capture-phase
|
||||||
|
* wheel handler owns local scrolling (xterm's own smooth scroller is
|
||||||
|
* bypassed, see the listener comment), so without this every notch was an
|
||||||
|
* instant multi-line jump. Wheel deltas accumulate into a pending line
|
||||||
|
* count and drain ~35% per animation frame (minimum one line, so it always
|
||||||
|
* terminates); more notches mid-glide just deepen the pending count, which
|
||||||
|
* reads as natural acceleration. Direction reversals cancel arithmetically.
|
||||||
|
* The pending amount is dropped when the active session changes mid-glide —
|
||||||
|
* leftover momentum must never scroll the tab the user just switched to.
|
||||||
|
*/
|
||||||
|
_smoothScrollBy(lines) {
|
||||||
|
if (!lines) return;
|
||||||
|
this._smoothScrollPending = (this._smoothScrollPending || 0) + lines;
|
||||||
|
this._smoothScrollSession = this.activeSessionId;
|
||||||
|
if (this._smoothScrollFrame) return;
|
||||||
|
const step = () => {
|
||||||
|
this._smoothScrollFrame = null;
|
||||||
|
const pending = this._smoothScrollPending || 0;
|
||||||
|
if (!pending) return;
|
||||||
|
if (this.activeSessionId !== this._smoothScrollSession) {
|
||||||
|
this._smoothScrollPending = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const move =
|
||||||
|
pending > 0 ? Math.max(1, Math.floor(pending * 0.35)) : Math.min(-1, Math.ceil(pending * 0.35));
|
||||||
|
this._smoothScrollPending = pending - move;
|
||||||
|
this.terminal.scrollLines(move);
|
||||||
|
this._maybeLoadMoreHistoryOnScroll(move);
|
||||||
|
if (this._smoothScrollPending) this._smoothScrollFrame = requestAnimationFrame(step);
|
||||||
|
};
|
||||||
|
this._smoothScrollFrame = requestAnimationFrame(step);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hand a scroll gesture (wheel tick or touch drag, already converted to
|
* Hand a scroll gesture (wheel tick or touch drag, already converted to
|
||||||
* lines) to the CLI as synthetic SGR wheel reports. SGR coordinates address
|
* lines) to the CLI as synthetic SGR wheel reports. SGR coordinates address
|
||||||
|
|||||||
Reference in New Issue
Block a user