multi-mail selection with Ctrl #186

Closed
opened 2026-09-01 20:47:04 +00:00 by unknown · 1 comment
unknown commented 2026-09-01 20:47:04 +00:00

The original description was not recovered.

Rebuilt from: session transcript. Opening date is approximate.

*The original description was not recovered.* <sub>Rebuilt from: session transcript. Opening date is approximate.</sub>
Owner

Fixed in #188, and live now on ihasmail.com as 2026.9.1+pr188.

You had the diagnosis right, and it was more literally right than you probably intended: Shift-click was not merely the better-behaved of the two, it was the correct implementation of a rule that Ctrl-click had a second, divergent copy of. Putting them next to each other makes it obvious —

shift:  select(ids.slice(start, end + 1), true)   // the whole run, including the row it started from
ctrl:   select([rowId], !selected[rowId])         // only the row clicked

— two branches of one handler that had drifted apart, with nothing anywhere asserting they agreed.

Your note about the presentation being misleading is the part that made this worth doing quickly rather than tidily. The first message was highlighted because it was the one open, which is a different state that happens to wear a similar colour; it was never in the selection at all. So the screen showed two picked messages, one was, and Archive or Delete then applied to half of what you were looking at without saying so. A wrong action taken confidently is worse than an obvious failure, which is why this went out ahead of the feature requests.

Ctrl-click now brings the current message with it while nothing is selected yet. Once there is a selection it toggles exactly one row, which is what it is for — so building a selection up or picking one out of it both behave as they do elsewhere. Shift-click is unchanged, including keeping its anchor put so that extending a range a second time grows it from the same place rather than from wherever it last reached.

The two rules are one function now rather than two branches, with tests. The one that matters asserts the property that actually failed rather than either branch: whichever modifier begins a selection, the message it started from is in it. Each branch was defensible on its own — what was missing was anything checking they agreed with each other.

Thanks for the screenshot. Highlighted-but-unticked is exactly the kind of thing that reads as a rendering quirk until somebody notices the actions are following the ticks.

Fixed in #188, and live now on ihasmail.com as 2026.9.1+pr188. You had the diagnosis right, and it was more literally right than you probably intended: Shift-click was not merely the better-behaved of the two, it was the correct implementation of a rule that Ctrl-click had a second, divergent copy of. Putting them next to each other makes it obvious — ``` shift: select(ids.slice(start, end + 1), true) // the whole run, including the row it started from ctrl: select([rowId], !selected[rowId]) // only the row clicked ``` — two branches of one handler that had drifted apart, with nothing anywhere asserting they agreed. Your note about the presentation being misleading is the part that made this worth doing quickly rather than tidily. The first message was highlighted because it was the one *open*, which is a different state that happens to wear a similar colour; it was never in the selection at all. So the screen showed two picked messages, one was, and Archive or Delete then applied to half of what you were looking at without saying so. A wrong action taken confidently is worse than an obvious failure, which is why this went out ahead of the feature requests. Ctrl-click now brings the current message with it while nothing is selected yet. Once there *is* a selection it toggles exactly one row, which is what it is for — so building a selection up or picking one out of it both behave as they do elsewhere. Shift-click is unchanged, including keeping its anchor put so that extending a range a second time grows it from the same place rather than from wherever it last reached. The two rules are one function now rather than two branches, with tests. The one that matters asserts the property that actually failed rather than either branch: whichever modifier begins a selection, the message it started from is in it. Each branch was defensible on its own — what was missing was anything checking they agreed with each other. Thanks for the screenshot. Highlighted-but-unticked is exactly the kind of thing that reads as a rendering quirk until somebody notices the actions are following the ticks.
This repo is archived. You cannot comment on issues.