diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-01 10:31:51 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-01 10:31:51 +0200 |
| commit | b12aada52d682c45aa1e66e13dc448dc894aee79 (patch) | |
| tree | e41ded20c908ee458e44171c6f4f7088ee613639 /AGENTS.md | |
| parent | 236ac86ca09a24300e724c2372f3576bf3f6ff84 (diff) | |
| download | qtmaildir-b12aada52d682c45aa1e66e13dc448dc894aee79.tar.gz qtmaildir-b12aada52d682c45aa1e66e13dc448dc894aee79.zip | |
fix: double a quote in a search term, as notmuch expects
SearchTerm::quote() escaped an embedded double quote with a backslash.
notmuch has no backslash escape inside a quoted term: it doubles the
quote, and a backslash-escaped one ENDS the term. Selected text holding
a quote therefore let the rest of the selection reach the query as
syntax. Measured on a throwaway index: under a `tag:nomatch and` scope,
the backslash form of `x " or tag:inbox or id:"` matched every message,
while the doubled form matched none.
quote() now doubles the quote and leaves a backslash alone, since
notmuch reads it literally. Truncation still runs first, so a cut
cannot split a doubled pair.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'AGENTS.md')
| -rw-r--r-- | AGENTS.md | 8 |
1 files changed, 5 insertions, 3 deletions
@@ -472,9 +472,11 @@ labelled Sent that shows the whole Maildir. (`src/searchterm.h`), and that is what stops five surfaces growing five quoting rules.** It holds no widget, so the grammar is tested without a painter or a web engine. Two of its rules are load-bearing rather than cosmetic. `quote()` -escapes backslashes BEFORE quotes, since the other order escapes the -backslashes it just added; it truncates before escaping, so a cut cannot land -mid-escape. And `extend()` parenthesises BOTH sides, because the query bar can +DOUBLES an embedded quote, because notmuch has no backslash escape: a +backslash-escaped quote ends the term, and a selection holding +`x \" or tag:inbox or id:"` walked out of a `tag:nomatch and` scope and matched +every message, measured, where the doubled form matched none. It truncates +before doubling, so a cut cannot land mid-pair. And `extend()` parenthesises BOTH sides, because the query bar can hold a hand-written disjunction and `a or b AND c` binds as `a or (b AND c)`, which widens a search the user asked to narrow, reporting nothing. This is the same trap the `post-new` hook handles when it scopes a rule with `tag:new`. |
