Skip to content

spec: horizontal scrolling per terminal pane (#9828)#10231

Open
lonexreb wants to merge 6 commits intowarpdotdev:masterfrom
lonexreb:spec/9828-horizontal-scroll
Open

spec: horizontal scrolling per terminal pane (#9828)#10231
lonexreb wants to merge 6 commits intowarpdotdev:masterfrom
lonexreb:spec/9828-horizontal-scroll

Conversation

@lonexreb
Copy link
Copy Markdown
Contributor

@lonexreb lonexreb commented May 6, 2026

Spec for #9828. Per-pane horizontal scroll when line-wrap is off and content exceeds pane width. Trackpad swipe, Shift-wheel, and a bottom scrollbar all drive it. Snaps to offset 0 on new output by default. Selection copies logical text.

Closes (spec-only) #9828.

@cla-bot cla-bot Bot added the cla-signed label May 6, 2026
@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 6, 2026
@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 6, 2026

@lonexreb

I'm starting a first review of this spec-only pull request.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines per-pane horizontal scrolling for terminal panes when line-wrap is disabled, with trackpad, Shift-wheel, and scrollbar controls.

Concerns

  • The behavior contract does not define how horizontal offsets are clamped or reset when the visible long-line set changes, the pane resizes, line-wrap is toggled, or vertical scroll moves to shorter content.
  • The snap-on-new-output behavior is ambiguous for terminal output patterns like partial line updates, prompt redraws, tailing logs, and alternate-screen/TUI updates.
  • The new snap setting needs a small implementation/discovery note so implementers know where it is exposed and persisted.

Found: 0 critical, 2 important, 1 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9828/tech.md
Comment on lines +21 to +25
- B1. Horizontal scrolling is gated on:
- The pane's `terminal.line_wrap = false` setting (existing).
- At least one visible row exceeding pane width.
When either condition is false, the pane behaves as today (no
horizontal scroll, no scrollbar).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] Define how h_offset is clamped or reset when the visible long-line set changes, the pane resizes, line-wrap toggles, or vertical scrolling moves to shorter content; otherwise implementations can show blank shifted columns or stale scrollbars.

Comment thread specs/GH9828/SPEC.md Outdated
Comment on lines +38 to +42
- B6. Auto-scroll on new output: by default the pane snaps back
to horizontal offset 0 when new output arrives at the bottom
(new prompt, new line). User-controlled snap behavior can be
disabled via `terminal.h_scroll_snap_on_new_output` (default
`true`).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] Specify the exact snap trigger and exceptions for partial-line updates, prompt redraws, tailing output, alternate-screen/TUI updates, and when the user is viewing scrollback; new output arrives at the bottom is too broad to implement consistently.

Comment thread specs/GH9828/SPEC.md Outdated
- B6. Auto-scroll on new output: by default the pane snaps back
to horizontal offset 0 when new output arrives at the bottom
(new prompt, new line). User-controlled snap behavior can be
disabled via `terminal.h_scroll_snap_on_new_output` (default
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] Add where terminal.h_scroll_snap_on_new_output is exposed and persisted, plus a test or acceptance criterion for disabling it.

@tpmbenny
Copy link
Copy Markdown
Member

tpmbenny commented May 6, 2026

@lonexreb thanks a ton for your contributions! I work on the Talent team at Warp (https://www.linkedin.com/in/mac-bennett-7936a6a6/) and I'm wondering if you'd be interested in exploring a role with us?!? If so, I'd love to jump on a call with you. Shot you a Linkedin connection request with my availability link :-).

Co-Authored-By: Warp <agent@warp.dev>
@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 7, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 7, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines per-pane horizontal scrolling for terminal output when line-wrap is disabled, including input methods, offset clamping, snap-on-new-output behavior, settings persistence, acceptance criteria, and tests.

Concerns

  • The offset model does not define how terminal grid columns map across wide glyphs, combining marks, tabs, and other multi-cell content, which can make rendering, hit-testing, and selection inconsistent.
  • Trackpad support is specified only for native macOS/Windows, leaving Linux behavior ambiguous even though the rest of the feature is platform-agnostic and Warp has Linux windowing support.

Verdict

Found: 0 critical, 2 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9828/tech.md
- At least one visible row exceeding pane width.
When either condition is false, the pane behaves as today (no
horizontal scroll, no scrollbar).
- B1a. `h_offset` is a logical column offset clamped to
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] Define whether h_offset is measured in terminal grid cells and how it behaves for wide glyphs, combining marks, tabs, and other multi-cell content; otherwise render, hit-testing, and selection paths can map the same visible column differently.

Comment thread specs/GH9828/SPEC.md Outdated
shrinks but remains positive, clamp `h_offset` down to the new
maximum so blank shifted columns are never rendered.
- B2. Horizontal scroll inputs:
- Trackpad two-finger horizontal swipe (native macOS/Windows).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This only names native macOS/Windows trackpad swipes, but the feature otherwise reads as platform-agnostic; specify whether Linux horizontal scroll events are supported in V1 or explicitly excluded, and mirror that in acceptance tests.

Round-1 fixes for oz-for-oss bot review:
- Add Offset Clamping & Reset Rules covering pane resize, vertical
  scroll, line-wrap toggle, and long-line set changes
- Define Snap-on-New-Output precisely: excludes alt-screen, prompt
  redraws, partial-line tailing; only true line-append-below triggers
- Rename setting to terminal.horizontal_scroll.snap_on_new_output and
  add Settings UI surface plus per-pane override
- Define offset model in terminal grid columns with explicit handling
  of wide glyphs, combining marks, and tab stops
- Add Linux trackpad support via libinput two-finger horizontal
  swipe with Shift+wheel and scrollbar drag fallback
@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-1 fixes for oz-for-oss review: (1) added Offset Clamping & Reset Rules covering pane resize, vertical scroll, line-wrap toggle, and long-line set changes; (2) precise Snap-on-New-Output definition excluding alt-screen, prompt redraws, and partial-line tailing — only true line-append-below triggers snap; (3) added implementation/discovery note: setting terminal.horizontal_scroll.snap_on_new_output in Settings → Terminal → Scrolling; (4) defined offset model in terminal grid columns with explicit handling of wide glyphs, combining marks, and tab-stops; (5) added Linux trackpad support via libinput two-finger horizontal swipe with Shift+wheel/scrollbar fallback.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 8, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This spec defines per-pane horizontal scrolling for terminal panes when line wrap is disabled, including input methods, snap behavior, settings, column semantics, acceptance criteria, and tests.

Concerns

  • The line-wrap toggle behavior is internally contradictory: one section resets h_offset to 0 when line wrap is enabled, while a later section preserves it and restores it when line wrap is disabled again.

Verdict

Found: 1 critical, 0 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9828/SPEC.md Outdated
`max(visible_longest_line_columns - visible_pane_columns, 0)`.
Recompute that maximum whenever the visible buffer range changes,
the pane resizes, line-wrap toggles, or rendered line contents
change. If the maximum becomes 0 or line-wrap is enabled, reset
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [CRITICAL] This conflicts with the later line-wrap rule that preserves h_offset internally and restores it when line-wrap is disabled again. Choose one behavior so implementation and tests know whether toggling wrap resets or preserves the horizontal position.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-2 fix: CRITICAL resolved — chose PRESERVE-AND-RESTORE for line-wrap toggle. h_offset persists internally when wrap is enabled (offset not applied) and is restored (clamped to current max_observed) when wrap is disabled. Rationale: matches user intent — toggling wrap on/off shouldn't lose horizontal scroll position. All spec references aligned (B1a, dedicated 'Line-wrap toggle: preserve-and-restore' section, A_WRAP_TOGGLE_PRESERVE / RESTORE / NO_RESET acceptance criteria, T_line_wrap_toggle_round_trip / clamps_on_shrink / no_reset tests). Reset-to-0 only happens on explicit user action (scroll to leftmost), snap-on-new-output (intentional per B6), or pane close. Audited resize/vertical-scroll/snap sections — no contradictions remain.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 8, 2026

@lonexreb

I'm re-reviewing this spec-only pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

Reviewed the spec for per-pane horizontal scrolling when line-wrap is disabled. The behavior contract is detailed, and the security pass did not identify design-level security issues.

Concerns

  • The spec is added as specs/GH9828/SPEC.md, but the repository's GitHub-issue spec convention uses specs/GH*/product.md and specs/GH*/tech.md; this can make downstream spec discovery and implementation workflows miss the approved spec.
  • The reset/clamping rules are internally inconsistent: one section resets/clamps h_offset to 0 when there is no valid horizontal offset, while the later "reset to 0 ONLY" invariant omits that case.
  • One wrap-toggle test assertion uses >= where equality is needed to verify exact restore-or-clamp behavior.

Verdict

Found: 0 critical, 2 important, 1 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread specs/GH9828/SPEC.md Outdated
@@ -0,0 +1,286 @@
# Spec: Horizontal scrolling per terminal pane (GH-9828)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This repo's GitHub issue specs are expected under specs/GH<issue>/product.md and specs/GH<issue>/tech.md; adding only SPEC.md can make spec-context and implementation workflows miss this spec. Split or rename the file to the expected product/tech spec paths, or document why this PR is an accepted exception.

Comment thread specs/GH9828/tech.md
preserved offset's required range, the offset clamps down (it
is never silently snapped to 0 unless the clamp resolves to
0 because nothing exceeds the viewport).
- **Reset to 0 ONLY on explicit triggers.** `h_offset` is reset
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ [IMPORTANT] This reset to 0 ONLY invariant conflicts with B1a and resize/visible-range clamping, which reset or clamp h_offset to 0 when no visible row exceeds the viewport. Add that no-valid-offset case here, or define it as clamping rather than a reset, so implementers do not preserve stale offsets indefinitely.

Comment thread specs/GH9828/SPEC.md Outdated
Comment on lines +253 to +254
Assertion: post-toggle `h_offset >= min(120, max_valid)` and
is NEVER 0 unless `max_valid == 0`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [SUGGESTION] This assertion should require the exact restored/clamped offset; >= would allow values beyond max_valid and miss clamping bugs.

Suggested change
Assertion: post-toggle `h_offset >= min(120, max_valid)` and
is NEVER 0 unless `max_valid == 0`.
Assertion: post-toggle `h_offset == min(120, max_valid)` and
is NEVER 0 unless `max_valid == 0`.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-3 review fixes (commit c0ef2da):

  • Spec discoverability note: verified the repo convention is specs/GH<N>/product.md + specs/GH<N>/tech.md (sibling specs GH1066, GH849, GH703, GH478, etc. all follow it). Added a top-of-file note: this spec ships as single SPEC.md for size reasons but MUST be split into product.md + tech.md before the implementation PR lands so downstream spec-discovery and the spec-driven-implementation skill find it under the standard names. Until then, spec-driven-implementation should be invoked with --spec specs/GH9828/SPEC.md explicitly.
  • Reset/clamp internal consistency: B1a's max == 0 case is now explicitly labeled the max-cleared clamp — a boundary case of the general clamp where the valid range collapses to {0}, NOT an unconditional reset of arbitrary user state. The 'Reset to 0 ONLY on explicit triggers' invariant lists the canonical reset triggers (manual leftmost scroll, snap-on-new-output per B6, pane close), with an explicit note that the max-cleared clamp is a clamp not a trigger. This removes the contradiction the reviewer flagged.
  • Wrap-toggle test exact-equality: T_line_wrap_toggle_round_trip's assertion now splits into three cases each using == (NOT >=):
    • max_valid >= 120 → h_offset == 120 exactly.
    • 0 < max_valid < 120 → h_offset == max_valid exactly.
    • max_valid == 0 → h_offset == 0 exactly (max-cleared clamp).
      The previous >= would have passed even if the implementation silently snapped low; equality enforces precise restore-or-clamp behavior.

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

Round-4 review addressed: (1) split SPEC.md into product.md (Problem/Goal/AC/Out-of-scope) and tech.md (Behavior contract/Implementation/Tests) per repo convention (matches GH1066, GH849, GH703, GH478). (2) Tightened B1a so the max-cleared boundary is explicitly the GENERAL clamp at its boundary (not a separate rule); 'Reset to 0 ONLY' list is canonical and exhaustive — neither wrap-toggle nor max-cleared appear there. (3) T_line_wrap_toggle_round_trip and T_line_wrap_toggle_clamps_on_shrink now assert with == in every case (no >=).

@lonexreb
Copy link
Copy Markdown
Contributor Author

lonexreb commented May 8, 2026

/oz-review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants