diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-23 21:15:13 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-23 21:15:13 +0200 |
| commit | fabcf080652c6e5d57bf234be5e100769a9b965b (patch) | |
| tree | 0de4222c1e2aab58c38d34c9e0e3c37c68298cc8 /CLAUDE.md | |
| parent | c50bea78e036518ce1a2a3eb899bbb5e305affea (diff) | |
| parent | ddcae8d02ef46db522b3cf6c228196c7a66a6432 (diff) | |
| download | qtmaildir-fabcf080652c6e5d57bf234be5e100769a9b965b.tar.gz qtmaildir-fabcf080652c6e5d57bf234be5e100769a9b965b.zip | |
Merge branch 'compose-and-send': composing and sending mail
Item 123, built over 2026-08-20 to 2026-08-23 in thirteen tasks against
docs/superpowers/specs/2026-08-20-compose-and-send-design.md.
The application writes mail now. A composer window per message, markdown as
the body, drafts autosaving into the account's Maildir, and sending through a
per-account command on stdin rather than any network protocol of this
program's own. A countdown with an Undo stands between pressing Send and the
command running.
Two things came in alongside it. The notmuch auto-tagging hooks moved here
from the retiring `mailctl` project and learned that mail this application
files itself never arrived, so sent mail and drafts stop appearing in the
inbox. And the v1/v2 language is retired: semver on the user-visible surface
is the rule, and those labels described a split that composing made obsolete.
Hand tested against a fake send command rather than a real one, deliberately:
New, Reply and Forward all produce correct messages, a forwarded attachment
survives intact, and the sent copy is filed. That testing found the two
defects fixed on this branch, and both were invisible to the suite: a composer
orphaned by quitting the main window, and every sent message tagged `inbox`.
Twenty-two defects were found in the plan document's own draft code while
building it, which is why CLAUDE.md says to treat every code block in a plan
as a draft.
Diffstat (limited to 'CLAUDE.md')
| -rw-r--r-- | CLAUDE.md | 35 |
1 files changed, 29 insertions, 6 deletions
@@ -64,10 +64,19 @@ MainWindow NotmuchWorker │ ONE column of cards; CardDelegate paints each whole, from CardLayout └ MessageView (header QLabel, QWebEngineView, attachment bar, TagStrip) +ComposeWindow (its own top-level window, one per message being written) + ├ MarkdownFormat (namespace: what the formatting buttons do to a selection) + ├ MarkdownRenderer (namespace, cmark-gfm) MessageBuilder (namespace, GMime) + ├ MessageSender (QProcess, the per-account send_command on stdin) + └ SendDialog (the undo countdown) DraftStore (autosave to the drafts folder) + +ComposeContext (a struct: what a Reply or Forward inherits) +ComposeContextBuilder (namespace: fills one, and picks the account) CardLayout (pure geometry, no painting) SearchTerm (pure query strings, no widget) Config (INI) KeyMap MailSync (QProcess) MimeParser (GMime) SyncMonitor (/proc/locks) TagColors QueryCompleter ThreadCidMap +MaildirName (fresh Maildir filenames) ``` The query row and the message-pane header are **built inline in `MainWindow` and @@ -75,11 +84,20 @@ The query row and the message-pane header are **built inline in `MainWindow` and listed `QueryBar`, `SavedQueryBar`, `HeaderWidget` and `AttachmentBar`; none of those types have ever existed, and looking for them wastes a search. The widget classes that do exist are `MessageView`, `ThreadListView`, `TagStrip`, -`TagDialog`, `MessageDetailsDialog`, `RowStyleDelegate` and `CardDelegate`; -`TagChip` is a namespace of painting helpers, not a widget, `SearchTerm` is a -namespace of query builders, and `ThreadCidMap`, `CardLayout`, `SearchOffer` -and `HeaderRow` are structs. `SubjectDelegate` existed until item 53 and is -gone. +`TagDialog`, `MessageDetailsDialog`, `RowStyleDelegate`, `CardDelegate`, +`ComposeWindow`, `SendDialog` and `BusyIndicator`; `TagChip` is a namespace of +painting helpers, not a widget, `SearchTerm` is a namespace of query builders, +and `ThreadCidMap`, `CardLayout`, `SearchOffer` and `HeaderRow` are structs. +`SubjectDelegate` existed until item 53 and is gone. + +**The compose units are mostly NAMESPACES, and the same warning applies to +them.** `MarkdownRenderer`, `MarkdownFormat`, `MessageBuilder`, +`ComposeContextBuilder`, `DraftStore` and `MaildirName` are namespaces of free +functions over values, deliberately, so the markdown, the MIME assembly and +the account-picking are all testable without a widget. `MessageSender` IS a +QObject, because it owns a `QProcess`. There is no `FormatToolbar` class: the +composer's formatting row is built inline in `ComposeWindow` and asks +`MarkdownFormat` what each button does to the selection. **`MessageDetailsDialog` was a `QPlainTextEdit` inside `MessageView` until item 85.** It is rows now so each value can carry its own context menu, and its @@ -925,7 +943,12 @@ test" position — it is the only code that writes to a notmuch index. Work goes directly on `master`, no PR flow. Commits must be GPG-signed (`git commit -S`). `HANDOFF.md` is local-only and gitignored; never stage or commit it. -v1 is read-and-organize only. Compose and send are v2. +**There is no "v1" and no "v2".** The project follows semver on its +user-visible surface, and those labels described a scope split that stopped +being true when compose and send shipped. Reading, organizing and sending are +all part of the application now. The phrase survives in the older spec and +plan documents, which are historical records and are not being rewritten; read +it there as "before compose" and "after compose". ## Cutting a release |
