From a6f73f77890d801ecd7209e97ba948c06fdd35c2 Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Mon, 3 Aug 2026 20:56:59 +0200 Subject: feat(completion): select candidates per context tag: and is: share the tag list, since notmuch aliases them. path: offers each account maildir in both bare and recursive forms, the latter being what Account::scopedQuery builds and not something a user would guess. Co-Authored-By: Claude Opus 5 --- src/querycompleter.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) (limited to 'src/querycompleter.cpp') diff --git a/src/querycompleter.cpp b/src/querycompleter.cpp index 77c62c1..6b4c69a 100644 --- a/src/querycompleter.cpp +++ b/src/querycompleter.cpp @@ -18,6 +18,8 @@ #include "querycompleter.h" +#include "config.h" + #include namespace { @@ -186,3 +188,83 @@ CompletionContext completionContext(const QString &text, int cursor) } return ctx; } + +QueryCompleter::QueryCompleter(QLineEdit *edit, const Config &config, + QObject *parent) + : QObject(parent), m_edit(edit), m_config(config) +{ +} + +void QueryCompleter::setTags(const QStringList &tags) +{ + m_tags = tags; +} + +QList QueryCompleter::entriesFor( + const CompletionContext &context) const +{ + if (context.kind == CompletionContext::None) + return {}; + + if (context.kind == CompletionContext::Prefix) + return prefixVocabulary(); + + // notmuch treats is:x as a synonym for tag:x, so both take the tag list. + if (context.prefix == QStringLiteral("tag") + || context.prefix == QStringLiteral("is")) { + QList entries; + entries.reserve(m_tags.size()); + for (const QString &tag : m_tags) + entries.append({ tag, QString() }); + return entries; + } + + if (context.prefix == QStringLiteral("date")) { + QList entries; + const QList vocabulary = dateVocabulary(); + for (const CompletionEntry &entry : vocabulary) { + // Entries that are themselves ranges cannot go inside a range. + if (!context.allowRangeEntries + && entry.value.contains(QStringLiteral(".."))) + continue; + entries.append(entry); + } + return entries; + } + + if (context.prefix == QStringLiteral("mimetype")) { + QList entries = mimetypeVocabulary(); + entries.append(m_config.extraMimetypes()); + return entries; + } + + if (context.prefix == QStringLiteral("path")) { + QList entries; + const QList accounts = m_config.accounts(); + for (const Account &account : accounts) { + if (account.maildir.isEmpty()) + continue; + entries.append({ account.maildir, + VocabularyStrings::tr("account directory") }); + entries.append({ account.maildir + QStringLiteral("/**"), + VocabularyStrings::tr("and everything below it") }); + } + return entries; + } + + // from:, to:, folder:, subject:, attachment:, thread:, id: complete no + // values. Addresses need an enumerator libnotmuch does not expose; + // folder: matches a Maildir folder name that config cannot enumerate, and + // the rest are free text. + return {}; +} + +QStringList QueryCompleter::candidatesFor(const CompletionContext &context) const +{ + QStringList values; + const QList entries = entriesFor(context); + values.reserve(entries.size()); + for (const CompletionEntry &entry : entries) + values.append(entry.value); + return values; +} -- cgit v1.2.3