Select several inbox messages with shift+arrows and mark them read - #39
Draft
williammartin wants to merge 2 commits into
Draft
williammartin wants to merge 2 commits into
williammartin wants to merge 2 commits into
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Rows inside the list panel were sized to listWidth(), the same width the panel style is given. Lip Gloss counts a style's horizontal padding inside that width, so a row that filled its budget was two columns too wide and got wrapped, dropping the received time onto a line of its own. contentWidth() now reserves those two columns for everything drawn inside the panel. Found while recording the multi-select demo; the scripts that produce that recording live in the pull request description rather than the tree. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
williammartin
force-pushed
the
williammartin-mail-multiselect-mark-read
branch
from
August 4, 2026 09:16
b42a5af to
3cb6f25
Compare
williammartin
marked this pull request as ready for review
August 4, 2026 09:19
williammartin
marked this pull request as draft
August 4, 2026 09:25
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.
Reviewer Notes
You better believe this was vibe coded and I haven't read anything. It does seem to work in my local jamming. Unfortunately, it's not that useful for me without server side mark as read, but might be a useful feature for something else?
On place I found an issue just now:
Given I have used
shift+downto select an item in multi select modeWhen I press
shift+upThen it should unselect that item
Right now it doesn't unselect at all. I'm also not sure exactly on the behaviour of shift+modifier in this mode - it selects the existing item not the one you're navigating to. That feels wrong.
I'm happy to work on these if you want this feature but otherwise I'll just leave it here as an artifact.
Why
Clearing a morning inbox is one message at a time: move,
r, move,r. There is no way to say "these five, mark them all read".What
shift+↑/shift+↓select messages in the interactive inbox, andrmarks the whole selection read.Shift is a momentary modifier, not a mode. Each shift-arrow selects the message the cursor is on and then moves, so holding shift and repeating an arrow builds up a run. A plain arrow moves without selecting, which passes over a message and leaves it out while keeping everything selected so far — so a non-contiguous set needs no extra keys.
In the recording: four messages are selected, "Workplace Team" is deliberately passed over with a plain
↓, andrmarks the four read while the skipped message keeps its orangeNEWmarker.Selected rows carry a
✓and the header shows the count.rclears the selection after applying;esc,tab, andRclear it without acting; archiving prunes the archived message from it. With nothing selected,rstill toggles the current row exactly as before.J/Kare bound to the same actions for terminals that do not send modified arrow keys.Read state stays local to the running TUI, matching the existing
rbinding — the WorkIQ broker exposes no mark-as-read action, so there is nothing to write back to Microsoft 365. Bulk mark-as-read against Graph would needPATCH /me/messages/{id}, anddo_actionis POST-only.Also fixed
Recording the demo surfaced rows wrapping onto a second line, dropping the received time onto its own line and breaking the column alignment. Rows were sized to
listWidth()— the same width handed to the panel style — but Lip Gloss counts a style's horizontal padding inside that width, so a full-width row was two columns too wide and the panel wrapped it.contentWidth()now reserves those columns for everything drawn inside the panel.This predates the feature (the new mark gutter does not change row totals), but it is the exact width math this PR touches, so it is fixed here rather than left to make the recording look broken.
Acceptance criteria
Each of these is an executable test in
internal/tui/multiselect_test.go.shift+↓shift+↑↓thenshift+↓↓twiceshift+↓shift+↑shift+↓rmarked 2 as read, and the selection is emptyrresctabto calendar andtabbackRaand the archive completes2 selectedshift+↓ris applied, the selected messages lose theirNEWmarker, and the skipped message keeps its ownNotes for the reviewer
The recording is scripted through
expect, not VHS keystrokes. VHS 0.11 cannot send shift-modified arrows:Shift+Downis a parse error, and theEscape+Type "[1;2B"workaround arrives as six separate keystrokes that Bubble Tea parses individually. I confirmed both failure modes with a throwaway key probe before settling on this.docs/multiselect.tapetherefore runsdocs/multiselect.exp, which spawns the TUI in a pty and writes the raw CSI bytes, so the recording exercises the real bindings rather than a stand-in. The script uses anexpect-basedpauseinstead ofsleep, becausesleepstops draining the pty and freezes the TUI mid-frame.