diff options
| author | Danilo M. <danix@danix.xyz> | 2026-08-14 12:42:38 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-08-14 12:42:38 +0200 |
| commit | 441b93a75b9941d395edfe4b65ed0af2da9e0021 (patch) | |
| tree | 7690c00dd355ad75fc59484f2cda2bf185c7b87e /src/searchterm.cpp | |
| parent | e876e509b0770a243725b63ea55c9ccf3e41b1bf (diff) | |
| download | qtmaildir-441b93a75b9941d395edfe4b65ed0af2da9e0021.tar.gz qtmaildir-441b93a75b9941d395edfe4b65ed0af2da9e0021.zip | |
feat(search): build notmuch terms for the right-click actions
One place for the query grammar behind every search surface, with no widget
involved so it is tested without a painter or a web engine.
extend() parenthesises both sides. The query bar may hold a hand-written
disjunction, and 'a or b AND c' binds as 'a or (b AND c)', which widens a
search meant to narrow it and reports nothing.
Diffstat (limited to 'src/searchterm.cpp')
| -rw-r--r-- | src/searchterm.cpp | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/src/searchterm.cpp b/src/searchterm.cpp new file mode 100644 index 0000000..acc64c6 --- /dev/null +++ b/src/searchterm.cpp @@ -0,0 +1,93 @@ +/* + * qtmaildir - a Qt6 mail client for notmuch-indexed Maildirs + * Copyright (C) 2026 Danilo M. <danix@danix.xyz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "searchterm.h" + +#include <algorithm> + +namespace SearchTerm { + +QString quote(const QString &value) +{ + // simplified() collapses every run of whitespace, newlines and tabs + // included, and trims the ends. A selection spanning paragraphs arrives + // full of newlines, which would otherwise reach the query bar verbatim. + QString cleaned = value.simplified(); + if (cleaned.isEmpty()) + return {}; + + if (cleaned.size() > kMaxValueLength) + cleaned.truncate(kMaxValueLength); + + // Backslashes first: escaping the quotes first would then escape the + // backslashes this step adds, doubling them. + cleaned.replace(QLatin1Char('\\'), QStringLiteral("\\\\")); + cleaned.replace(QLatin1Char('"'), QStringLiteral("\\\"")); + + return QLatin1Char('"') + cleaned + QLatin1Char('"'); +} + +QString field(const QString &name, const QString &value) +{ + const QString quoted = quote(value); + if (quoted.isEmpty()) + return {}; + return name + QLatin1Char(':') + quoted; +} + +QString onDate(const QDate &day) +{ + if (!day.isValid()) + return {}; + const QString text = day.toString(QStringLiteral("yyyy-MM-dd")); + return QStringLiteral("date:%1..%1").arg(text); +} + +QString tag(const QString &name) +{ + const QString trimmed = name.simplified(); + if (trimmed.isEmpty()) + return {}; + + // A tag is a token from a vocabulary the user chose, so it reads better + // unquoted in the bar they are about to edit. Quoted only when it holds + // something that would not survive. + const bool needsQuoting = + std::any_of(trimmed.cbegin(), trimmed.cend(), [](QChar ch) { + return !(ch.isLetterOrNumber() || ch == QLatin1Char('-') + || ch == QLatin1Char('_') || ch == QLatin1Char('.') + || ch == QLatin1Char('/')); + }); + + return QStringLiteral("tag:") + (needsQuoting ? quote(trimmed) : trimmed); +} + +QString extend(const QString &existing, const QString &addition) +{ + const QString left = existing.trimmed(); + const QString right = addition.trimmed(); + + if (right.isEmpty()) + return left; + if (left.isEmpty()) + return right; + + return QStringLiteral("(%1) AND (%2)").arg(left, right); +} + +} // namespace SearchTerm |
