Uppercase mailbox action keys, universal undo, quick peek - #30
Closed
RooseveltAdvisors wants to merge 17 commits into
Closed
RooseveltAdvisors wants to merge 17 commits into
RooseveltAdvisors wants to merge 17 commits into
Conversation
…ion, and screening
feat: add per-email reminders
…instant actions (#5) Drive the client from the home row, and make every action land immediately. Bindings (inbox + reader, guarded behind the existing input-mode returns so they never fire inside the filter, `:` command line, IMAP search, or the reminder prompt): e archive / mark done h remind me s start an email ; snippets / templates picker Case reconciliation — email actions are now lowercase (i/o/p/b/t/v replace I/O/P/B/T/V, uppercase kept as aliases, as are A and c). Six keys stay uppercase because their lowercase letter is load-bearing: F (f=forward), S (s=compose), U (u=page up), X (x=trash), N (n=toggle read), R (r=reply). Two visible moves: `h` no longer exits the reader (q/esc do), and the reader's read-only $EDITOR view moved from `e` to `<space>e`. Instant actions — archive/delete/screen/move/remind apply to the list on the keystroke via Model.optimisticAct, reconcile in place on the server ack (no folder re-fetch, which is what made every keypress feel like a page load), and roll back visibly on failure. Batches carry an optID so overlapping actions never consume each other's rollback snapshot. Infinite scroll — reaching the bottom appends the next page via the new imap.Client.FetchHeadersBefore UID cursor; the list cursor stays put, an empty page latches the folder exhausted, and cross-folder views are not paged. Snippets — `;` reads <config dir>/snippets/*.md at open time; an optional leading `Subject:` line sets the subject and the rest is staged into the $EDITOR buffer through the existing mailto-body path. Tests: TestEmailBindingMap, TestEmailBindingsGuardedInsideInputFields, TestReaderArchiveAndRemindKeys, TestOptimisticArchiveIsInstant, TestOptimisticArchiveRollsBackVisiblyOnFailure, TestOverlappingOptimisticBatchesRollBackIndependently, TestOptimisticRemindMovesRowsAtOnce, TestScrollToBottomTriggersNextPage, TestNextPageAppendsAndKeepsScrollPosition, TestScrollLatchSurvivesTheKeyHandler, TestScrollDoesNotPageAdHocViews, TestEmptyNextPageMarksFolderExhausted, TestNextPageForAnotherFolderIsDropped, TestFullFolderLoadResetsPagingState, TestSnippetParseSplitsSubjectAndBody, TestSnippetPickerComposesPrefilled. Claude-Session: https://claude.ai/code/session_014hpboaND66f8HSC1LG43Rn Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…erminal (#11) The reader yank menu (`y` then `m`) put nothing on the clipboard. The shared helper only shelled out to a local clipboard tool, which cannot work when neomd runs over ssh: on the gpu box `xclip` is on PATH but DISPLAY is empty, so it was invoked and failed with a bare `exit status 1`. Even a successful local tool would have set the remote machine's clipboard rather than the terminal the user pastes from. copyToClipboard now writes an OSC 52 sequence to the terminal first and only then falls back to a local tool; either succeeding is a success. Inside tmux the sequence is emitted twice — plain, and DCS-passthrough wrapped with every ESC doubled — so it lands under either `set-clipboard on` or `allow-passthrough on`. A local tool whose display variable is unset is now skipped rather than run and failed, and a tool that does fail reports its stderr instead of an opaque exit status. The helper moved from internal/ui/contacts_picker.go to internal/ui/clipboard.go alongside its tests, so the contacts picker's `y`/`Y` is fixed by the same change. Verified on a real pty: copyToClipboard emits ESC ]52;c;<base64> BEL decoding to neomd://mid/%3Cabc@example.com%3E and exits 0 on this headless host, where the old path returned exit status 1. Claude-Session: https://claude.ai/code/session_014ojr1K5YFUvGwx5KNp4cLY Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Add a read-only CLI path for resolving copied neomd:// links and bare Message-IDs across configured IMAP accounts. Preserve the widget UID reader while exposing text, JSON, raw, and stdin batch output.
Share one calendar-aware parser between reminders and send-later, and restore the visible cursor after local filtering so actions target the highlighted result.
- Mailbox action keys are uppercase in the inbox: I approve, O screen-out, P papertrail, B work (F feed and $ spam unchanged). Lowercase i/p/b no longer fire; core e/h/s/; keys are untouched. - u is now a universal undo backed by an action journal (undoAction): batchScreenerCmd previously dropped its undo data on success, so F/I/P/O moves could not be reversed. The journal records moves AND \Seen flag changes (n toggle, ctrl+n mark-all-read), pops LIFO, and reports server-side undo failures in the status line. - Leader+space toggles a quick-peek pane (From/To/Subject/body) for the highlighted email without leaving the inbox list; esc or the chord closes it, the cursor stays put, j/k re-targets the preview, and the body is fetched with BODY.PEEK so peeking never marks mail read. Tests: TestLowercaseMailboxActionsAreDead, TestUndoJournal*, TestPeek*, docs/keys.md + hint bar + ? overlay kept in sync via TestDocumentedKeyBindings.
Author
|
Opened against the wrong repository by an automated agent; closing. The identical PR lives at RooseveltAdvisors/neomd. |
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.
Summary
Three inbox TUI changes per the captain's intent:
Uppercase mailbox action keys -
Iapprove/screen-in,Oscreen-out,Ppapertrail,Bwork,Ffeed,$spam. The lowercasei/p/bforms no longer fire. The four core keys (earchive,hremind,scompose,;snippets) stay lowercase by contract, as dooopen,tthread, andnread toggle.docs/keys.md, the bottom hint bar, and the?overlay are all updated from the same source of truth (internal/ui/keys.go,make docs).Universal undo -
unow reverses the most recent action of any journaled type:F/I/O/P/$): previouslybatchScreenerCmdbuilt the undo data but silently dropped it on success - the bug behind "u does not un-move after F/I". Fixed.ntoggle and ctrl+n mark-all-read journal the old\Seenstate, soutoggles back.maxUndoStack, and mixed move+flag actions reverse in one command. Server-side undo failures surface in the status line (never silent). Screener classification lists are intentionally kept on undo (mail moves back, sender lists do not); permanentXdelete is never journaled since it cannot be reversed.Quick peek - leader+space (
<space><space>) toggles a preview pane (From/To/Subject + body) of the highlighted email without leaving the inbox list.escor the chord again closes it; the cursor never moves;j/kre-targets the preview to the new row; the pane is exactlypeekPaneHeightlines so the status bar never overflows; the body is fetched withBODY.PEEKso peeking never marks mail read. Works in read-only profiles (it mutates nothing).Tests
TestLowercaseMailboxActionsAreDead- lowercase i/p/b are dead keysTestEmailBindingMap- updated to the uppercase contract; read-only blocking extended to I/O/P/BTestUndoJournalScreenerMove,TestUndoJournalReadToggle,TestUndoJournalMarkAllRead,TestUndoJournalMostRecentFirst,TestUndoJournalCap,TestUndoNothingToDo,TestUndoRefusesInReadOnlyTestPeekOpensAndClosesWithStableSelection,TestPeekStaleResultDropped,TestPeekResizesListgo test ./...andgo test ./... -run Hardeningpass;make docsregenerated.Docs:
docs/keys.md,README.mdscreener walkthrough, generated keybindings docs,AGENTS.mdkeyboard contract updated.