aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-14 13:40:17 +0200
committerDanilo M. <danix@danix.xyz>2026-08-14 13:40:17 +0200
commitbbf3c570215688c553fd70d8f372ae215725ca02 (patch)
tree8ca944300b3f8e2650940154df73aa8b561bb3b8 /docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
parentfef6d7be1f70cb51431afef608b037b85029c3c2 (diff)
downloadqtmaildir-bbf3c570215688c553fd70d8f372ae215725ca02.tar.gz
qtmaildir-bbf3c570215688c553fd70d8f372ae215725ca02.zip
docs: close item 85, searching from the message pane
Five surfaces in the message pane offer a search built from what they show, replacing the query or narrowing it. The details dialog became rows along the way, which the user wanted independently of this feature. Item 78 is narrowed to the rule shortcut alone and drops to S: item 85 built the menus and item 81 the seeded dialog, so both halves already exist. Its approach text is corrected too, since it claimed the thread list holds a usable sender and notmuch_thread_get_authors returns a display summary, not an address. Three traps recorded in CLAUDE.md: a modal dialog must close before the action it asked for runs, Qt::RFC2822Date validates the weekday against the date, and every query goes through SearchTerm so five surfaces cannot grow five quoting rules.
Diffstat (limited to 'docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md')
-rw-r--r--docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md61
1 files changed, 61 insertions, 0 deletions
diff --git a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
index 8cfa6b0..8ae8dff 100644
--- a/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
+++ b/docs/superpowers/plans/2026-08-03-post-0.1.0-usability-closed.md
@@ -4741,3 +4741,64 @@ how this was found: the suite ran past its two-minute timeout with no output.
The cause is not the account at all, it is `showWarnings()` raising a modal
from the MainWindow constructor for any config problem, with nothing offscreen
to dismiss it. Filed as item 84.
+
+## 85. Nothing on screen can be searched for by right-clicking it
+
+**Observed (2026-08-14).** The user asked, while discussing item 78, to be able
+to right-click a sender, a subject, a date, a tag chip or a piece of selected
+body text and be offered a search built from it, both replacing the query bar
+and narrowing what is already in it. The narrowing case decided the shape: a
+query returning a thousand threads is refined by adding a second condition, and
+before this that meant retyping a query the user never typed.
+
+**Cause.** Not a defect, unbuilt. `MessageView` had no context menu on any
+surface, and `TagStrip` painted chips with no hit test and no signals.
+
+**Done 2026-08-14**, designed in
+`specs/2026-08-14-search-from-message-design.md` and built over eight tasks.
+Five surfaces offer **Search for this** and **Add to search**: the header's
+subject and date, its From/To/Cc for a single-message thread, a tag chip, a
+body selection, and every header per message in the details dialog.
+
+**What is worth keeping from it.**
+
+`SearchTerm` (`src/searchterm.h`) owns the whole query grammar and holds no
+widget, so the quoting is tested without a painter or a web engine. That
+matters because **a mis-quoted notmuch query is not an error, it matches zero**:
+nothing downstream would ever report the feature being broken. `extend()`
+parenthesises both sides, since `a or b AND c` binds as `a or (b AND c)` and
+silently WIDENS a search the user asked to narrow.
+
+**`Qt::RFC2822Date` validates the weekday against the date**, so `Thu, 14 Aug
+2026` parses as invalid: that day is a Friday. Two test fixtures carried a wrong
+weekday, one of them pre-existing, and the failure is indistinguishable from the
+trailing-comment trap `MimeParser::parseDate` exists to handle. Check a date
+fixture with `date -d <yyyy-mm-dd> +%A` rather than writing one from memory.
+
+The Date: parse was **extracted** into `MimeParser::parseDate` rather than
+rewritten, because the existing copy inside a file-local function already
+carried the fix for `Qt::RFC2822Date` rejecting a string with a trailing
+timezone comment. A second parser without it would have lost the date on a
+large share of real mail, showing up only as a menu entry that never appears.
+
+**The header lists its fields rather than hit-testing them.** It is one
+rich-text `QLabel` of up to four lines, and mapping a point through laid-out
+rich text breaks as soon as the label wraps. From/To/Cc are offered exactly when
+the header displays them, which is a single-message thread, so the menu can
+never name a value the header is withholding.
+
+**The details dialog stopped being a `QPlainTextEdit`**, which the user had
+disliked independently. Its plain-textness was a security property rather than a
+style: header values come from strangers and plain text cannot interpret markup.
+Every value label therefore states `Qt::PlainText` explicitly, because a
+`QLabel` guesses under `Qt::AutoText`, and a test enumerates every label and
+asserts the format.
+
+**A modal dialog must close BEFORE the search it asked for runs.** The
+connection is direct, so emitting first runs the query synchronously: the model
+clears and the pane blanks while the dialog is still up, holding the `m_items`
+it was built from. Caught by a test whose mutation check HUNG rather than
+failed, which is what a missing `accept()` does to `exec()`.
+
+**Item 78 stays open**, carrying the rule shortcut alone. The road from a search
+to a rule already exists: save the query, then create a rule from it.