Repository navigation
test(list): red cases for a page that hides the cursor after a jump - #680
Merged
Merged
Conversation
Two cases in `app::render::grid_settle_tests`, ignored as red until the fix (#679) removes the ignores: - `a_search_jump_draws_the_cursor_bar_on_the_match`: a `/` search to row 240 of a 16-row list draws no cursor bar. - `l_off_the_last_column_opens_the_next_page_at_its_first_column`: `l` from a page's last column lands in the second column of the next page. Refs #679 Co-Authored-By: Claude <noreply@anthropic.com>
DerekMarshall
added a commit
that referenced
this pull request
Oct 15, 2026
…681) 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 - #680's red cases now pass, with their `ignore`s 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](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Red cases for #679. After a jump, the list can settle on a page that doesn't hold the cursor, and
loff a page's last column can land in the second column of the next page.The bug, seen while dogfooding rc.3: at 238×60, in a large directory with mixed-length names, a
/search to a file further down left no row highlighted, though the cursor was on the match.lthen landed in the second column of the next page.Cause (details in #679):
stabilize_gridsnapsview_topto a multiple of the page size it just measured. Pages fit different numbers of columns, so it alternates between two starts, and its cycle-breaker keeps the lower one without checking that the cursor is on it.Two cases in the new
app::render::grid_settle_tests, each marked#[ignore = "red: …"]until the fix PR removes the ignores. Both use synthetic names and press the keys a user would.a_search_jump_draws_the_cursor_bar_on_the_match: 16-row list,/n0240-then Enter. Expected: the cursor bar on row 240's name.Today:
left: None. The settle keeps the page from 192, which ends at 239.l_off_the_last_column_opens_the_next_page_at_its_first_column: 58-row list, search to row 464 (last column of the page 348–521), thenl. Expected: the bar on row 522, in the first column, same row.Today: drawn at x=67, the second column.
Each test first asserts the page layout its case needs, so a change to the fixture fails loudly rather than letting the test pass. Bite-checked the other way: with the cycle-breaker temporarily keeping the higher start instead, both pass. That isn't the fix; #679 records the chosen design, fixed pages counted from the top.
cargo test --lib -- grid_settle_tests --include-ignored: 2 failed, for the reasons above.make check-cipasses with them ignored.Generated with Claude Code