aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-02 17:52:17 +0200
committerDanilo M. <danix@danix.xyz>2026-08-02 17:52:17 +0200
commitcb3ab1a1f8bb0a982f4ce7e9e371ed316a77c84c (patch)
tree37b58b4b859d2e47317c4b47c4c0dbe7b3da3be3
parent6d4fcb8fd597c39ba0b7f404e64f500b11b75e1c (diff)
downloadqtmaildir-cb3ab1a1f8bb0a982f4ce7e9e371ed316a77c84c.tar.gz
qtmaildir-cb3ab1a1f8bb0a982f4ce7e9e371ed316a77c84c.zip
feat: add cross-thread value types and notmuch RAII wrappers
ThreadSummary, MessageRef, and TagChange are plain-value structs that carry query results across the worker/UI thread boundary via queued signals. NmHandle<T, Destroy> wraps libnotmuch's C handles (query, threads, messages, thread, message, tags) so early returns in the query paths can't leak.
-rw-r--r--src/nmraii.h51
-rw-r--r--src/types.h51
2 files changed, 102 insertions, 0 deletions
diff --git a/src/nmraii.h b/src/nmraii.h
new file mode 100644
index 0000000..22ad4ae
--- /dev/null
+++ b/src/nmraii.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <notmuch.h>
+
+#include <utility>
+
+/// Generic owner for a notmuch handle with a destroy function.
+template <typename T, void (*Destroy)(T *)>
+class NmHandle
+{
+public:
+ NmHandle() = default;
+ explicit NmHandle(T *handle) : m_handle(handle) {}
+
+ ~NmHandle() { reset(); }
+
+ NmHandle(const NmHandle &) = delete;
+ NmHandle &operator=(const NmHandle &) = delete;
+
+ NmHandle(NmHandle &&other) noexcept
+ : m_handle(std::exchange(other.m_handle, nullptr)) {}
+
+ NmHandle &operator=(NmHandle &&other) noexcept
+ {
+ if (this != &other) {
+ reset();
+ m_handle = std::exchange(other.m_handle, nullptr);
+ }
+ return *this;
+ }
+
+ void reset(T *handle = nullptr)
+ {
+ if (m_handle)
+ Destroy(m_handle);
+ m_handle = handle;
+ }
+
+ T *get() const { return m_handle; }
+ explicit operator bool() const { return m_handle != nullptr; }
+
+private:
+ T *m_handle = nullptr;
+};
+
+using NmQuery = NmHandle<notmuch_query_t, notmuch_query_destroy>;
+using NmThreads = NmHandle<notmuch_threads_t, notmuch_threads_destroy>;
+using NmMessages = NmHandle<notmuch_messages_t, notmuch_messages_destroy>;
+using NmThread = NmHandle<notmuch_thread_t, notmuch_thread_destroy>;
+using NmMessage = NmHandle<notmuch_message_t, notmuch_message_destroy>;
+using NmTags = NmHandle<notmuch_tags_t, notmuch_tags_destroy>;
diff --git a/src/types.h b/src/types.h
new file mode 100644
index 0000000..da71e19
--- /dev/null
+++ b/src/types.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <QDateTime>
+#include <QMetaType>
+#include <QString>
+#include <QStringList>
+
+struct ThreadSummary
+{
+ QString threadId;
+ QString subject;
+ QString authors;
+ QDateTime date;
+ int totalCount = 0;
+ int matchedCount = 0;
+ QStringList tags;
+
+ bool isUnread() const { return tags.contains(QStringLiteral("unread")); }
+ bool isFlagged() const { return tags.contains(QStringLiteral("flagged")); }
+};
+
+struct MessageRef
+{
+ QString messageId;
+ QString filePath;
+ QStringList tags;
+
+ /// True when the message itself matched the user's query, as opposed to
+ /// being pulled in only because a sibling in its thread matched. Drives
+ /// whether it renders expanded or as a stub.
+ bool matched = true;
+};
+
+/// One tag mutation, kept so it can be inverted for undo.
+struct TagChange
+{
+ QStringList messageIds;
+ QStringList added;
+ QStringList removed;
+ QString description; ///< Shown in the undo action's text.
+
+ TagChange inverted() const
+ {
+ return TagChange{ messageIds, removed, added,
+ QStringLiteral("Undo %1").arg(description) };
+ }
+};
+
+Q_DECLARE_METATYPE(ThreadSummary)
+Q_DECLARE_METATYPE(MessageRef)
+Q_DECLARE_METATYPE(TagChange)