lib/parse-sexp: add '*' as syntactic sugar for '(starts-with "")'

Users that insist on using a literal '*' as a tag, can continue to do
so by quoting it when searching.
This commit is contained in:
David Bremner 2021-08-24 08:17:25 -07:00
parent 011d06f4d6
commit 0ca4ad2670
3 changed files with 70 additions and 2 deletions

View file

@ -36,8 +36,11 @@ An s-expression query is either an atom, the empty list, or a
a *field*, *logical operation*, or *modifier*, and 0 or more a *field*, *logical operation*, or *modifier*, and 0 or more
subqueries. subqueries.
``*`` ``()`` ``*``
Match all messages. "*" matches any non-empty string in the current field.
``()``
The empty list matches all messages
*term* *term*
@ -138,6 +141,15 @@ from terms, operators, and modifiers, but not other fields.
MODIFIERS MODIFIERS
````````` `````````
*Modifiers* refer to any prefixes (first elements of compound queries)
that are neither operators nor fields.
``(starts-with`` *subword* ``)``
Matches any term starting with *subword*. This applies in either
phrase or term :any:`fields <fields>`, or outside of fields [#not-body]_. Note that
a ``starts-with`` query cannot be part of a phrase. The
atom ``*`` is a synonym for ``(starts-with "")``.
EXAMPLES EXAMPLES
======== ========
@ -181,6 +193,9 @@ EXAMPLES
"mallory@example.org", and also "bob@example.com.au" since it "mallory@example.org", and also "bob@example.com.au" since it
contains the adjacent triple "bob", "example", "com". contains the adjacent triple "bob", "example", "com".
``(not (to *))``
Match messages with an empty or invalid 'To' and 'Cc' field.
NOTES NOTES
===== =====

View file

@ -176,6 +176,11 @@ _sexp_to_xapian_query (notmuch_database_t *notmuch, const _sexp_prefix_t *parent
std::string term = Xapian::Unicode::tolower (sx->val); std::string term = Xapian::Unicode::tolower (sx->val);
Xapian::Stem stem = *(notmuch->stemmer); Xapian::Stem stem = *(notmuch->stemmer);
std::string term_prefix = parent ? _find_prefix (parent->name) : ""; std::string term_prefix = parent ? _find_prefix (parent->name) : "";
if (sx->aty == SEXP_BASIC && strcmp (sx->val, "*") == 0) {
return _sexp_parse_wildcard (notmuch, parent, "", output);
}
if (parent && (parent->flags & SEXP_FLAG_BOOLEAN)) { if (parent && (parent->flags & SEXP_FLAG_BOOLEAN)) {
output = Xapian::Query (term_prefix + sx->val); output = Xapian::Query (term_prefix + sx->val);
return NOTMUCH_STATUS_SUCCESS; return NOTMUCH_STATUS_SUCCESS;

View file

@ -386,6 +386,46 @@ thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unr
EOF EOF
test_expect_equal_file EXPECTED OUTPUT test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "wildcard search for 'is'"
notmuch search not id:${notag_mid} > EXPECTED
notmuch search --query=sexp '(is *)' > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "negated wildcard search for 'is'"
notmuch search id:${notag_mid} > EXPECTED
notmuch search --query=sexp '(not (is *))' > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "wildcard search for 'property'"
notmuch search property:foo=bar > EXPECTED
notmuch search --query=sexp '(property *)' > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "wildcard search for 'tag'"
notmuch search not id:${notag_mid} > EXPECTED
notmuch search --query=sexp '(tag *)' > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "negated wildcard search for 'tag'"
notmuch search id:${notag_mid} > EXPECTED
notmuch search --query=sexp '(not (tag *))' > OUTPUT
test_expect_equal_file EXPECTED OUTPUT
add_message '[subject]="message with tag \"*\""'
notmuch tag '+*' id:${gen_msg_id}
test_begin_subtest "search for 'tag' \"*\""
output=$(notmuch search --query=sexp --output=messages '(tag "*")')
test_expect_equal "$output" "id:$gen_msg_id"
test_begin_subtest "search for missing / empty to"
add_message [to]="undisclosed-recipients:"
notmuch search --query=sexp '(not (to *))' | notmuch_search_sanitize > OUTPUT
cat <<EOF > EXPECTED
thread:XXX 2001-01-05 [1/1] Notmuch Test Suite; search for missing / empty to (inbox unread)
EOF
test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "Unbalanced parens" test_begin_subtest "Unbalanced parens"
# A code 1 indicates the error was handled (a crash will return e.g. 139). # A code 1 indicates the error was handled (a crash will return e.g. 139).
test_expect_code 1 "notmuch search --query=sexp '('" test_expect_code 1 "notmuch search --query=sexp '('"
@ -454,4 +494,12 @@ notmuch search: Syntax error in query
EOF EOF
test_expect_equal_file EXPECTED OUTPUT test_expect_equal_file EXPECTED OUTPUT
test_begin_subtest "wildcard, illegal field"
notmuch search --query=sexp '(body *)' >OUTPUT 2>&1
cat <<EOF > EXPECTED
notmuch search: Syntax error in query
'body' does not support wildcard queries
EOF
test_expect_equal_file EXPECTED OUTPUT
test_done test_done