From 01ecb8c4e3bbf8176ca9d4085734ed2ec0774c80 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Wed, 12 Aug 2026 11:49:40 +0200 Subject: feat(worker): count messages as well as threads requestCounts counts threads, which is right for the placeholder pane. A tagging rule tags messages, so a dry run over rules needs the message count or it understates every rule that matches part of a thread. --- src/notmuchworker.cpp | 31 +++++++++++++++++++++++++++++++ src/notmuchworker.h | 13 +++++++++++++ 2 files changed, 44 insertions(+) (limited to 'src') diff --git a/src/notmuchworker.cpp b/src/notmuchworker.cpp index 24f3fd9..94fb79c 100644 --- a/src/notmuchworker.cpp +++ b/src/notmuchworker.cpp @@ -647,3 +647,34 @@ void NotmuchWorker::requestCounts(const QStringList &queries, quint64 generation emit countsReady(counts, generation); } + +void NotmuchWorker::requestMessageCounts(const QStringList &queries, + quint64 generation) +{ + if (!openReadOnly()) + return; + + QVector counts; + counts.reserve(queries.size()); + + for (const QString &query : queries) { + NmQuery nmQuery(notmuch_query_create(m_db, query.toUtf8().constData())); + + unsigned int count = 0; + // -1 rather than a skipped entry, matching requestCounts: the caller + // pairs these with its own rules positionally, so a dropped answer + // would put a real number against the wrong rule. + if (!nmQuery || + notmuch_query_count_messages(nmQuery.get(), &count) + != NOTMUCH_STATUS_SUCCESS) { + counts.append(-1); + continue; + } + + // Messages, not threads: a rule tags messages, so counting threads + // would understate a rule matching part of a large thread. + counts.append(static_cast(count)); + } + + emit messageCountsReady(counts, generation); +} diff --git a/src/notmuchworker.h b/src/notmuchworker.h index 2dd766f..b3fbed3 100644 --- a/src/notmuchworker.h +++ b/src/notmuchworker.h @@ -130,6 +130,14 @@ public slots: /// refreshing one nobody is looking at is work for nothing. void requestCounts(const QStringList &queries, quint64 generation); + /// Message counts for each query, positionally paired with the input. + /// + /// Beside requestCounts rather than replacing it: that one counts THREADS, + /// which is right for the placeholder pane because a click there produces + /// thread rows. A tagging rule tags messages, so a thread count would + /// understate any rule matching part of a large thread. + void requestMessageCounts(const QStringList &queries, quint64 generation); + /// Database-level facts for the Maildir overview (item 34): total messages, /// total threads, and the number of tags. /// @@ -158,6 +166,11 @@ signals: /// positional correspondence the caller relies on always holds. void countsReady(const QVector &counts, quint64 generation); + /// The same positional contract as countsReady, over messages rather than + /// threads. A dry run over tagging rules pairs these with its own rules by + /// index, so an entry is never dropped. + void messageCountsReady(const QVector &counts, quint64 generation); + /// Fields left at -1 are ones notmuch could not answer, which the dialog /// renders as unknown rather than as zero. void databaseStatsReady(const DatabaseStats &stats, quint64 generation); -- cgit v1.2.3