Skip to content

Halt a running glide before a landing that finds the pane already in place - #188

Merged
ben-dev-au merged 1 commit into
mainfrom
fix/rapid-nav-landing
Oct 6, 2026
Merged

ben-dev-au merged 1 commit into
mainfrom
fix/rapid-nav-landing

Conversation

@ben-dev-au

Copy link
Copy Markdown
Owner

Problem

  • Down then Up in the results list, with the second press landing before the first glide had moved the pane, left the preview on the first target (the table) while the cursor sat on the section above it.
  • Cause: a match landing scrolls with Textual's scroll_to_region, which measures from the pane's live position and issues nothing on a zero delta. Textual stops a running scroll animation only inside _scroll_to, which a zero-delta call never reaches, so the earlier glide ran on.
  • A scroll trace of a failing run: the second landing's scroll_to_region(y=65) is followed by no scroll call, while the first landing's was followed by scroll_relative and scroll_to.

Fix

  • MatchAwareScroll.halt_glide() drops a running scroll_y animation where it is: animating to the current value makes Textual pop it, which avoids force_stop_animation's jump to the old target. It also resets scroll_target_y, which Reading View's j/k step from.
  • The match landing (StructuralScrollStrategy._scroll_pane_to_match_region) and the n/b stop scroll (MatchNavigator._scroll_to_stop) call it first.
  • On a non-zero delta the landing ends at the same row as before. It now glides from where the pane was halted; main painted a one-frame jump to the old glide's end first.

Tests

  • New, test_a_scroll_to_where_the_pane_already_is_still_ends_a_glide[landing|nb_stop]: main fails it 3 of 3 (assert 0 == 52), this branch passes 3 of 3.
  • Down then Up under the test harness, 7 gaps from 30 to 150 ms with 4 runs each: main mislanded 2 of 4 at 50 ms, this branch 0 of 28.
  • make batch-close: ruff, pyright, 4916 passed / 3 skipped, tmux harness green.
  • Reviewed adversarially: no blocker.

Known limits

  • A live terminal did not reproduce the bug on main in 83 tries (gaps 0 to 120 ms, and both keys in one input burst). There the glide has usually moved before the second landing is computed, so this fixes a real defect at the Textual level rather than an observed live symptom.
  • A glide that has been committed but not yet started is not halted. An animated landing's _scroll_to is queued with call_after_refresh, so for 1 to 17 ms it is neither running nor scheduled, and halt_glide sees nothing to stop. The review confirmed this at a seam that starts the first glide the production way, but could not trigger it from key presses. Closing it means MatchAwareScroll dropping a stale queued scroll when a new landing arrives, which changes deferred-scroll behaviour for every caller, so it is left out of this change.
  • Dropping the animation skips its on_complete, so Textual's _realtime_animation_count gains one per halt. That count only gates PAUSE_GC_ON_SCROLL, which is off and never set in fnd.

…place

A match landing scrolls with `scroll_to_region`, which measures from the
pane's live position and issues nothing when the delta is zero. Textual only
stops a running scroll animation inside `_scroll_to`, so a landing that found
the pane already where it wanted it left an earlier glide running, and the
preview ended on the earlier target. Down then Up in the results list, the
second press landing before the first glide had moved the pane, left the
preview on the table with the cursor on the section above it.

`MatchAwareScroll.halt_glide` drops a running `scroll_y` animation where it
is (animating to the current value, which avoids `force_stop_animation`'s
jump to the old target), and the match landing and the n/b stop scroll call
it first. Under the test harness the race reproduces at a 50 ms gap (2 of 4
on main, 0 of 28 with this change); a live terminal did not hit it in 83
tries, since there the glide has usually moved before the second landing.
@coderabbitai

coderabbitai Bot commented Oct 6, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: c566c525-bc6c-4874-8b45-dc8ec04725ae
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ben-dev-au
ben-dev-au merged commit 843d972 into main Oct 6, 2026
22 checks passed
@ben-dev-au
ben-dev-au deleted the fix/rapid-nav-landing branch October 7, 2026 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant