Skip to content

fix(list): count pages from the top so a jump never hides the cursor - #681

Merged
DerekMarshall merged 1 commit into
mainfrom
fix/list-pages-from-the-top
Oct 15, 2026
Merged

DerekMarshall merged 1 commit into
mainfrom
fix/list-pages-from-the-top

Conversation

@DerekMarshall

Copy link
Copy Markdown
Member

Closes #679. The list's pages are now counted from the top, so a jump always shows the page holding the cursor, and l off a page's last column opens the next page at its first column.

The bug

The settle snapped view_top to a multiple of the page size it had just measured. A page holds as many columns as fit, and a column is as wide as its longest name, so neighbouring pages differ in length. The settle alternated between two starts and kept the lower one. After a / search no row was lit, and l landed in the next page's second column.

The fix

  • Fixed pages (ui::list_view::Pages): the first page starts at row 0 and each starts where the one before it ends. The starts are found by walking from the top, once per listing and list size, and only as far as asked. settle_page replaces stabilize_grid's loop and places the column on the page holding its cursor.
  • PageDown / PageUp move to the same column and row on the next or previous page, or to its last row when it's shorter. PageDown from the last page wraps to the first. PageUp from the first page goes to the last row, so opening a directory measures only its first two pages.
  • grid_at is now the one geometry the renderer, the hit-test and the page walk share. Commander::ensure_cursor_visible and cursor_move_global are gone, and ARCHITECTURE.md records the decision.

Checks

  • test(list): red cases for a page that hides the cursor after a jump #680's red cases now pass, with their ignores removed. Two more key-driven cases cover PageDown to a narrower page and PageUp to the previous page's first row. All four failed on the old code.
  • Unit tests cover the page walk: pages from the top and their wrap, a row's page not depending on earlier lookups, re-measuring on new rows or size, and the first page measuring only two pages. Each was bite-checked.
  • A temporary sweep, not committed because it takes over two minutes, covered every row of the 600-name fixture at 238×60 and with a 16-row list. It ran a jump, l, h, PageDown and PageUp, and the cursor bar was on the cursor's name every time.
  • In a release build, reaching row 99,999 of a 100k-entry listing takes 3.5 ms once after each listing change; after that a lookup takes 17 ns.
  • make check-ci passes. The owner tested a build and approved it.

Generated with Claude Code

Pages are now fixed: the first starts at row 0 and each starts where the
one before it ends. `ui::list_view::Pages` finds the starts by walking
from the top, once per listing and list size and only as far as asked,
and the settle places the column on the page holding its cursor.

The settle used to snap `view_top` to a multiple of the page size it had
just measured. Pages fit different numbers of columns, so it alternated
between two starts and kept the lower one: after a `/` search no row was
lit, and `l` off a page's last column landed in the next page's second
column.

PageDown / PageUp move to the same column and row on the next or
previous page (its last row when shorter). PageDown from the last page
wraps to the first; PageUp from the first goes to the last row, so
opening a directory never measures past its second page.

Closes #679

Co-Authored-By: Claude <noreply@anthropic.com>
@DerekMarshall
DerekMarshall merged commit f30ac92 into main Oct 15, 2026
4 checks passed
@DerekMarshall
DerekMarshall deleted the fix/list-pages-from-the-top branch October 15, 2026 18:12
DerekMarshall added a commit that referenced this pull request Oct 15, 2026
Sets the version to `2.2.0-rc.4`, made with `make release-prep
VERSION=2.2.0-rc.4`. Only `Cargo.toml` and `Cargo.lock` change. As with
the earlier rcs, it gets no CHANGELOG section, because the 2.2.0 section
covers the whole cycle.

## What rc.4 adds over rc.3

| PR | Change |
|---|---|
| #680 / #681 | fix(list): pages are counted from the top, so a `/` jump
always shows the cursor and `l` off a page's last column opens the next
page at its first column (#679). PageDown/PageUp keep the column and
row. |
| #682 | fix(agent-hud): the first column holds its width through every
state, and row headings are bright and bold (#676). |
| #683 | test(clipboard): the copy-command stubs run through `/bin/sh`,
fixing a local macOS flake that failed this release's first prep. |

The owner tested builds of #681 and #682 before they merged. `main`
stays at `2.2.0-rc.4` through the soak.

**After merge, on `main`:**
1. `make release-tag VERSION=2.2.0-rc.4`
2. Push the tag. `release.yml` verifies the archives reproduce,
publishes a GitHub pre-release, and dispatches the Homebrew tap and apt.
The crates job publishes `spyc 2.2.0-rc.4` and skips `spyc-vt-sys
0.1.0`, which is unchanged.

**Checks:** the release-prep commit hook ran `make check` (3,240 tests
passed).

Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
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.

List: after a jump, the page can hide the cursor, and l lands a column off

1 participant