From 8ed6a172b35708428f84f30af44fa81c12852e43 Mon Sep 17 00:00:00 2001 From: David Bremner Date: Thu, 24 Feb 2022 22:41:03 -0400 Subject: [PATCH] lib: do not phrase parse prefixed bracketed subexpressions Since Xapian does not preserve quotes when passing the subquery to a field processor, we have to make a guess as to what the user intended. Here the added assumption is that a string surrounded by parens is not intended to be a phrase. --- doc/man7/notmuch-search-terms.rst | 6 ++++-- lib/regexp-fields.cc | 3 ++- test/T650-regexp-query.sh | 13 ++++++++++--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/doc/man7/notmuch-search-terms.rst b/doc/man7/notmuch-search-terms.rst index e80cc7d0..f8ad1edb 100644 --- a/doc/man7/notmuch-search-terms.rst +++ b/doc/man7/notmuch-search-terms.rst @@ -275,11 +275,13 @@ the same phrase. - a.list.of.words Both parenthesised lists of terms and quoted phrases are ok with -probabilistic prefixes such as **to:**, **from:**, and **subject:**. In particular +probabilistic prefixes such as **to:**, **from:**, and **subject:**. +For prefixes supporting regex search, the parenthesised list should be +quoted. In particular :: - subject:(pizza free) + subject:"(pizza free)" is equivalent to diff --git a/lib/regexp-fields.cc b/lib/regexp-fields.cc index 7e9d959c..539915d8 100644 --- a/lib/regexp-fields.cc +++ b/lib/regexp-fields.cc @@ -227,7 +227,8 @@ RegexpFieldProcessor::operator() (const std::string & str) * phrase parsing, when possible */ std::string query_str; - if (*str.rbegin () != '*' || str.find (' ') != std::string::npos) + if ((str.at (0) != '(' || *str.rbegin () != ')') && + (*str.rbegin () != '*' || str.find (' ') != std::string::npos)) query_str = '"' + str + '"'; else query_str = str; diff --git a/test/T650-regexp-query.sh b/test/T650-regexp-query.sh index 4ee6b171..a9844501 100755 --- a/test/T650-regexp-query.sh +++ b/test/T650-regexp-query.sh @@ -66,23 +66,30 @@ EOF test_expect_equal_file EXPECTED OUTPUT test_begin_subtest "bracketed subject search (with dquotes)" -test_subtest_known_broken notmuch search subject:notmuch and subject:show > EXPECTED notmuch search 'subject:"(show notmuch)"' > OUTPUT test_expect_equal_file_nonempty EXPECTED OUTPUT test_begin_subtest "bracketed subject search (with dquotes and operator 'or')" -test_subtest_known_broken notmuch search subject:notmuch or subject:show > EXPECTED notmuch search 'subject:"(notmuch or show)"' > OUTPUT test_expect_equal_file_nonempty EXPECTED OUTPUT test_begin_subtest "bracketed subject search (with dquotes and operator 'and')" -test_subtest_known_broken notmuch search subject:notmuch and subject:show > EXPECTED notmuch search 'subject:"(notmuch and show)"' > OUTPUT test_expect_equal_file_nonempty EXPECTED OUTPUT +test_begin_subtest "bracketed subject search (with phrase, operator 'or')" +notmuch search 'subject:"mailing list"' or subject:FreeBSD > EXPECTED +notmuch search 'subject:"(""mailing list"" or FreeBSD)"' > OUTPUT +test_expect_equal_file_nonempty EXPECTED OUTPUT + +test_begin_subtest "bracketed subject search (with phrase, operator 'and')" +notmuch search search 'subject:"notmuch show"' and subject:commands > EXPECTED +notmuch search 'subject:"(""notmuch show"" and commands)"' > OUTPUT +test_expect_equal_file_nonempty EXPECTED OUTPUT + test_begin_subtest "xapian wildcard search for from:" notmuch search --output=messages 'from:cwo*' > OUTPUT test_expect_equal_file cworth.msg-ids OUTPUT