mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-09-30 12:39: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;
|
||||
}
|
||||
this._noteTerminalUserScroll(lines);
|
||||
this.terminal.scrollLines(lines);
|
||||
this._maybeLoadMoreHistoryOnScroll(lines);
|
||||
this._smoothScrollBy(lines);
|
||||
},
|
||||
{ passive: false, capture: true }
|
||||
);
|
||||
@@ -2077,6 +2076,40 @@ Object.assign(CodemanApp.prototype, {
|
||||
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
|
||||
* lines) to the CLI as synthetic SGR wheel reports. SGR coordinates address
|
||||
|
||||
Reference in New Issue
Block a user