In a drill, tile select's fallback is a Label or _Index, not _Measure (improvise-h3cv)

command.md said the fallback is always _Measure. In _Drill, drill_steps
puts _Measure on Filter and tileable_cats drops Filter, so it is not a
tile. The Label rank and the _Index fallback are live exactly there.

Two TUI tests drive a real drill (>) and T: with a Label on None the
cursor opens on it, without one on _Index. Rivals: #231's
first-regular-else-zero and a Label ranked below _Index both fail the
first. They are not lockstep tests: a browser declines >.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Edward Langley
2026-09-23 10:54:36 -07:00
parent ce7a57bb1f
commit 9975347b38
3 changed files with 83 additions and 2 deletions
+10 -2
View File
@@ -3028,8 +3028,16 @@ which is the original bug (improvise-bqm0, confirmed on a document holding only
decision. `_Measure` is the fallback, not the primary: it is on an axis in every
shipped document, and `Enter` reads as "confirm" on the user's own dimension. It
ranks above a Label because a Label is a high-cardinality per-row field, and
cycling it onto Row would explode the grid rather than empty it. In practice the
fallback is always `_Measure`, which every document has.
cycling it onto Row would explode the grid rather than empty it. The fallback is
**not** always `_Measure` (improvise-h3cv). In the `_Drill` view `drill_steps`
puts every coordinate of the drilled key on `Axis::Filter`, `_Measure` included,
and `tileable_cats` drops Filter, so `_Measure` is not a tile there. A drill's
tiles are `_Index`, `_Dim` and whatever sits on None, so the Label rank and the
`_Index` fallback are live exactly in a drill: a Label opens if there is one,
and otherwise `_Index`, because nothing better is on offer.
`in_a_drill_tile_select_opens_on_a_label_not_on_index` and
`in_a_drill_with_nothing_better_tile_select_opens_on_index` drive both through
the TUI's own keys. They are not lockstep tests, because a browser declines `>`.
**The tests had to separate the rule from its neighbours** (improvise-52od). In
every early fixture the first Regular tile was also the first tile on Row, so a
+21
View File
@@ -6151,3 +6151,24 @@ case fails. Second, the ticket's suggested fix, which drops the asker's
reset and the client never heard. That rival also fails
`a_geometry_command_relays_the_cursor_reset_to_the_asker_too` and the
ws-server's `the_other_document_would_also_have_a_cursor_to_invalidate`.
### in_a_drill_tile_select_opens_on_a_label_not_on_index
improvise-h3cv. `context/code/command.md` claimed tile select's fallback is
always `_Measure`. In a drill `_Measure` is on Filter and is not a tile, so the
tiles are `_Index`, `_Dim` and a Label `Note` on None. The test drills with `>`
on a one-cell document, asserts `_Measure` really is on Filter (so the fixture
cannot silently stop being a drill), presses `T`, and requires the cursor on
`Note`. Two rivals, each injected into `opening_tile` and restored after: #231's
`position(kind == Regular).unwrap_or(0)` opens on `_Index` and fails; ranking a
Label below `_Index`/`_Dim` also opens on `_Index` and fails. Neither rival fails
the companion test below.
### in_a_drill_with_nothing_better_tile_select_opens_on_index
improvise-h3cv's other half. The same drill with no Label leaves only `_Index`
and `_Dim`, so the ranking has nothing better and the cursor opens on `_Index`,
the first of the two. This pins that the ranking does not panic or pick `_Dim`
when every tile has the lowest rank. It is a characterization, not a bug guard.
Neither this nor its sibling is a lockstep test, because the browser declines
`>` (drill-into-cell), so only the TUI can reach a drill.
+52
View File
@@ -5122,3 +5122,55 @@ mod formula_edit_tests {
assert_eq!(buffer(&app), Some("Sum = East + West"));
}
}
/// Where `T` opens inside a drill, where `_Measure` is on Filter and so is no tile
/// (improvise-h3cv). `context/test-evidence/command.md`.
#[cfg(test)]
mod drill_tile_select {
use super::*;
use crate::command::key::{KeyCode, KeyEvent, KeyModifiers};
use crate::model::cell::{CellKey, CellValue};
use crate::view::Axis;
use crate::workbook::Workbook;
fn drilled(with_label: bool) -> App {
let mut wb = Workbook::new("Drill");
wb.add_category("Region").unwrap();
wb.add_item("Region", "North").unwrap();
wb.add_item("_Measure", "Revenue").unwrap();
if with_label {
wb.add_label_category("Note").unwrap();
}
wb.active_view_mut().set_axis("Region", Axis::Row);
wb.active_view_mut().set_axis("_Measure", Axis::Column);
wb.model.set_cell(
CellKey::new(vec![
("Region".into(), "North".into()),
("_Measure".into(), "Revenue".into()),
]),
CellValue::Number(5.0),
);
let mut app = App::new(wb, None);
let key = |c| KeyEvent::new(KeyCode::Char(c), KeyModifiers::NONE);
app.handle_key(key('>')).expect("drill");
assert_eq!(app.view().axis_of("_Measure"), Axis::Filter, "a real drill");
app.handle_key(key('T')).expect("tile select");
app
}
fn opened_on(app: &App) -> String {
let names = app.model_state.workbook.model.category_names();
let tiles = app.view().tileable_cats(&names);
tiles[app.view_state.tile_cat_idx].to_string()
}
#[test]
fn in_a_drill_tile_select_opens_on_a_label_not_on_index() {
assert_eq!(opened_on(&drilled(true)), "Note");
}
#[test]
fn in_a_drill_with_nothing_better_tile_select_opens_on_index() {
assert_eq!(opened_on(&drilled(false)), "_Index");
}
}