Today — Terminal::drag takes its endpoints as (u16, u16) tuples in column-first order, and Screen::find returns (u16, u16) in row-first order. They are the same type, so feeding one to the other compiles and runs, silently transposed. Measured against 0.9.0:
// terminal.rs:2543
pub fn drag(&mut self, button: impl Into<MouseChord>, from: (u16, u16), to: (u16, u16)) -> Result<()>
let at = screen.find("Drag me").unwrap(); // (row, col)
t.drag(MouseButton::Left, at, elsewhere)?; // read as (col, row) — compiles, drags the wrong cell
Nothing catches it. The endpoints are bounds-checked against the grid, so a transposed pair inside a squarish grid passes that check too, and the application under test receives a well-formed drag across cells nobody asked about.
Its two siblings cannot be misused this way. click(col, row) and click_with(button, col, row) take separate arguments (terminal.rs:2471, 2495), so a find result has to be destructured before it can be passed, and the author sees the order while doing it. drag is the only mouse method that accepts a bare pair.
drag's own rustdoc — forty lines on tracking modes, path interpolation and what each mode delivers — never states the order. The statement lives two files away, in Screen::rect_text's "Panics" section, which lists every column-first API by name (drag among them) and says outright that "swapping the two is therefore the mistake to expect". That was written for #219, about exactly this hazard.
Why it is worth fixing — every other coordinate hazard in this crate is caught by a type, a bounds check, or a panic. This one is caught by nothing, and it is the single place where the crate's own most convenient source of coordinates (find) flows into an input method with the axes reversed. The failure is not a compile error, not a runtime error, and not visibly wrong on the screen — the application simply receives a gesture somewhere else, and the test asserts on whatever that produced.
Fix — decide between the two shapes and say why in the PR. Both are small:
- Match the siblings:
drag(button, from_col, from_row, to_col, to_row). Four u16s is not pretty, but it makes the transposition unwritable and puts drag in line with click, click_with, scroll and scroll_with. A breaking change to one method, which is a minor bump before 1.0.
- Keep the tuples and make the order visible: state "columns first" in the first line of the rustdoc, next to the parameter, rather than only in
rect_text's panic section — and add a doctest that names the order.
Option 1 is the recommendation: the docs already tried option 2 once, in the place a reader of drag never looks.
Either way, drag's rustdoc should carry the same cross-reference rect_text does, and the Screen::find docs should say that its (row, col) result is not directly usable as a mouse position.
Done when — passing a Screen::find result straight into drag either does not compile or is documented on drag itself in its opening lines; the order appears in drag's own rustdoc rather than only in rect_text's; and a test covers a drag whose endpoints came from find, so the intended spelling is exercised.
Today —
Terminal::dragtakes its endpoints as(u16, u16)tuples in column-first order, andScreen::findreturns(u16, u16)in row-first order. They are the same type, so feeding one to the other compiles and runs, silently transposed. Measured against 0.9.0:Nothing catches it. The endpoints are bounds-checked against the grid, so a transposed pair inside a squarish grid passes that check too, and the application under test receives a well-formed drag across cells nobody asked about.
Its two siblings cannot be misused this way.
click(col, row)andclick_with(button, col, row)take separate arguments (terminal.rs:2471, 2495), so afindresult has to be destructured before it can be passed, and the author sees the order while doing it.dragis the only mouse method that accepts a bare pair.drag's own rustdoc — forty lines on tracking modes, path interpolation and what each mode delivers — never states the order. The statement lives two files away, inScreen::rect_text's "Panics" section, which lists every column-first API by name (dragamong them) and says outright that "swapping the two is therefore the mistake to expect". That was written for #219, about exactly this hazard.Why it is worth fixing — every other coordinate hazard in this crate is caught by a type, a bounds check, or a panic. This one is caught by nothing, and it is the single place where the crate's own most convenient source of coordinates (
find) flows into an input method with the axes reversed. The failure is not a compile error, not a runtime error, and not visibly wrong on the screen — the application simply receives a gesture somewhere else, and the test asserts on whatever that produced.Fix — decide between the two shapes and say why in the PR. Both are small:
drag(button, from_col, from_row, to_col, to_row). Fouru16s is not pretty, but it makes the transposition unwritable and putsdragin line withclick,click_with,scrollandscroll_with. A breaking change to one method, which is a minor bump before 1.0.rect_text's panic section — and add a doctest that names the order.Option 1 is the recommendation: the docs already tried option 2 once, in the place a reader of
dragnever looks.Either way,
drag's rustdoc should carry the same cross-referencerect_textdoes, and theScreen::finddocs should say that its(row, col)result is not directly usable as a mouse position.Done when — passing a
Screen::findresult straight intodrageither does not compile or is documented ondragitself in its opening lines; the order appears indrag's own rustdoc rather than only inrect_text's; and a test covers a drag whose endpoints came fromfind, so the intended spelling is exercised.