mirror of
https://git.notmuchmail.org/git/notmuch
synced 2024-12-22 09:24:54 +01:00
lib: add sexp: prefix to Xapian (infix) query parser.
This is analogous to the "infix" prefix provided by the s-expression based query parser.
This commit is contained in:
parent
fc3bb11808
commit
a1d139de4d
6 changed files with 129 additions and 2 deletions
|
@ -169,6 +169,12 @@ property:<key>=<value>
|
||||||
can be present on a given message with several different values.
|
can be present on a given message with several different values.
|
||||||
See :any:`notmuch-properties(7)` for more details.
|
See :any:`notmuch-properties(7)` for more details.
|
||||||
|
|
||||||
|
sexp:<subquery>
|
||||||
|
The **sexp:** prefix allows subqueries in the format
|
||||||
|
documented in :any:`notmuch-sexp-queries(7)`. Note that subqueries containing
|
||||||
|
spaces must be quoted, and any embedded double quotes must be escaped
|
||||||
|
(see :any:`quoting`).
|
||||||
|
|
||||||
User defined prefixes are also supported, see :any:`notmuch-config(1)` for
|
User defined prefixes are also supported, see :any:`notmuch-config(1)` for
|
||||||
details.
|
details.
|
||||||
|
|
||||||
|
@ -257,7 +263,7 @@ Boolean
|
||||||
Probabilistic
|
Probabilistic
|
||||||
**body:**, **to:**, **attachment:**, **mimetype:**
|
**body:**, **to:**, **attachment:**, **mimetype:**
|
||||||
Special
|
Special
|
||||||
**from:**, **query:**, **subject:**
|
**from:**, **query:**, **subject:**, **sexp:**
|
||||||
|
|
||||||
Terms and phrases
|
Terms and phrases
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -297,6 +303,8 @@ Both of these will match a subject "Free Delicious Pizza" while
|
||||||
|
|
||||||
will not.
|
will not.
|
||||||
|
|
||||||
|
.. _quoting:
|
||||||
|
|
||||||
Quoting
|
Quoting
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -324,6 +332,13 @@ e.g.
|
||||||
% notmuch search 'folder:"/^.*/(Junk|Spam)$/"'
|
% notmuch search 'folder:"/^.*/(Junk|Spam)$/"'
|
||||||
% notmuch search 'thread:"{from:mallory and date:2009}" and thread:{to:mallory}'
|
% notmuch search 'thread:"{from:mallory and date:2009}" and thread:{to:mallory}'
|
||||||
|
|
||||||
|
Double quotes within query strings need to be doubled to escape them.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
% notmuch search 'tag:"""quoted tag"""'
|
||||||
|
% notmuch search 'sexp:"(or ""wizard"" ""php"")"'
|
||||||
|
|
||||||
DATE AND TIME SEARCH
|
DATE AND TIME SEARCH
|
||||||
====================
|
====================
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,8 @@ libnotmuch_cxx_srcs = \
|
||||||
$(dir)/prefix.cc \
|
$(dir)/prefix.cc \
|
||||||
$(dir)/open.cc \
|
$(dir)/open.cc \
|
||||||
$(dir)/init.cc \
|
$(dir)/init.cc \
|
||||||
$(dir)/parse-sexp.cc
|
$(dir)/parse-sexp.cc \
|
||||||
|
$(dir)/sexp-fp.cc
|
||||||
|
|
||||||
libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
|
libnotmuch_modules := $(libnotmuch_c_srcs:.c=.o) $(libnotmuch_cxx_srcs:.cc=.o)
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "thread-fp.h"
|
#include "thread-fp.h"
|
||||||
#include "regexp-fields.h"
|
#include "regexp-fields.h"
|
||||||
#include "parse-time-vrp.h"
|
#include "parse-time-vrp.h"
|
||||||
|
#include "sexp-fp.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -60,6 +61,8 @@ prefix_t prefix_table[] = {
|
||||||
NOTMUCH_FIELD_PROCESSOR },
|
NOTMUCH_FIELD_PROCESSOR },
|
||||||
{ "query", NULL, NOTMUCH_FIELD_EXTERNAL |
|
{ "query", NULL, NOTMUCH_FIELD_EXTERNAL |
|
||||||
NOTMUCH_FIELD_PROCESSOR },
|
NOTMUCH_FIELD_PROCESSOR },
|
||||||
|
{ "sexp", NULL, NOTMUCH_FIELD_EXTERNAL |
|
||||||
|
NOTMUCH_FIELD_PROCESSOR },
|
||||||
{ "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
|
{ "from", "XFROM", NOTMUCH_FIELD_EXTERNAL |
|
||||||
NOTMUCH_FIELD_PROBABILISTIC |
|
NOTMUCH_FIELD_PROBABILISTIC |
|
||||||
NOTMUCH_FIELD_PROCESSOR },
|
NOTMUCH_FIELD_PROCESSOR },
|
||||||
|
@ -138,6 +141,8 @@ _setup_query_field (const prefix_t *prefix, notmuch_database_t *notmuch)
|
||||||
fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
|
fp = (new QueryFieldProcessor (*notmuch->query_parser, notmuch))->release ();
|
||||||
else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
|
else if (STRNCMP_LITERAL (prefix->name, "thread") == 0)
|
||||||
fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
|
fp = (new ThreadFieldProcessor (*notmuch->query_parser, notmuch))->release ();
|
||||||
|
else if (STRNCMP_LITERAL (prefix->name, "sexp") == 0)
|
||||||
|
fp = (new SexpFieldProcessor (notmuch))->release ();
|
||||||
else
|
else
|
||||||
fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
|
fp = (new RegexpFieldProcessor (prefix->name, prefix->flags,
|
||||||
*notmuch->query_parser, notmuch))->release ();
|
*notmuch->query_parser, notmuch))->release ();
|
||||||
|
|
40
lib/sexp-fp.cc
Normal file
40
lib/sexp-fp.cc
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
/* sexp-fp.cc - "sexp:" field processor glue
|
||||||
|
*
|
||||||
|
* This file is part of notmuch.
|
||||||
|
*
|
||||||
|
* Copyright © 2022 David Bremner
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, see https://www.gnu.org/licenses/ .
|
||||||
|
*
|
||||||
|
* Author: David Bremner <david@tethera.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "database-private.h"
|
||||||
|
#include "sexp-fp.h"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
Xapian::Query
|
||||||
|
SexpFieldProcessor::operator() (const std::string & query_string)
|
||||||
|
{
|
||||||
|
notmuch_status_t status;
|
||||||
|
Xapian::Query output;
|
||||||
|
|
||||||
|
status = _notmuch_sexp_string_to_xapian_query (notmuch, query_string.c_str (), output);
|
||||||
|
if (status) {
|
||||||
|
throw Xapian::QueryParserError ("error parsing " + query_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
|
||||||
|
}
|
41
lib/sexp-fp.h
Normal file
41
lib/sexp-fp.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
/* sexp-fp.h - sexp field processor glue
|
||||||
|
*
|
||||||
|
* This file is part of notmuch.
|
||||||
|
*
|
||||||
|
* Copyright © 2022 David Bremner
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* 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, see https://www.gnu.org/licenses/ .
|
||||||
|
*
|
||||||
|
* Author: David Bremner <david@tethera.net>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef NOTMUCH_SEXP_FP_H
|
||||||
|
#define NOTMUCH_SEXP_FP_H
|
||||||
|
|
||||||
|
#include <xapian.h>
|
||||||
|
#include "notmuch.h"
|
||||||
|
|
||||||
|
class SexpFieldProcessor : public Xapian::FieldProcessor {
|
||||||
|
protected:
|
||||||
|
notmuch_database_t *notmuch;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SexpFieldProcessor (notmuch_database_t *notmuch_) : notmuch (notmuch_)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
Xapian::Query operator() (const std::string & query_string);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* NOTMUCH_SEXP_FP_H */
|
|
@ -46,6 +46,14 @@ thread:XXX 2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "or of exact terms via field processor"
|
||||||
|
notmuch search 'sexp:"(or ""php"" ""wizard"")"' | notmuch_search_sanitize > OUTPUT
|
||||||
|
cat <<EOF > EXPECTED
|
||||||
|
thread:XXX 2010-12-29 [1/1] François Boulogne; [aur-general] Guidelines: cp, mkdir vs install (inbox unread)
|
||||||
|
thread:XXX 2009-11-18 [1/3] Carl Worth| Jan Janak; [notmuch] What a great idea! (inbox unread)
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "single term in body"
|
test_begin_subtest "single term in body"
|
||||||
notmuch search --query=sexp 'wizard' | notmuch_search_sanitize>OUTPUT
|
notmuch search --query=sexp 'wizard' | notmuch_search_sanitize>OUTPUT
|
||||||
cat <<EOF > EXPECTED
|
cat <<EOF > EXPECTED
|
||||||
|
@ -714,6 +722,11 @@ notmuch search property:foo=bar > EXPECTED
|
||||||
notmuch search --query=sexp '(property (rx foo=.*))' > OUTPUT
|
notmuch search --query=sexp '(property (rx foo=.*))' > OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "regexp 'property' search via field processor"
|
||||||
|
notmuch search property:foo=bar > EXPECTED
|
||||||
|
notmuch search 'sexp:"(property (rx foo=.*))"' > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "anchored 'tag' search"
|
test_begin_subtest "anchored 'tag' search"
|
||||||
notmuch search tag:signed > EXPECTED
|
notmuch search tag:signed > EXPECTED
|
||||||
notmuch search --query=sexp '(tag (rx ^si))' > OUTPUT
|
notmuch search --query=sexp '(tag (rx ^si))' > OUTPUT
|
||||||
|
@ -750,6 +763,13 @@ thread:XXX 2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packa
|
||||||
EOF
|
EOF
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "Compound subquery via field processor"
|
||||||
|
notmuch search 'sexp:"(thread (of (from keithp) (subject Maildir)))"' | notmuch_search_sanitize > OUTPUT
|
||||||
|
cat<<EOF > EXPECTED
|
||||||
|
thread:XXX 2009-11-18 [7/7] Lars Kellogg-Stedman, Mikhail Gusarov, Keith Packard, Carl Worth; [notmuch] Working with Maildir storage? (inbox signed unread)
|
||||||
|
EOF
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "empty subquery"
|
test_begin_subtest "empty subquery"
|
||||||
notmuch search --query=sexp '(thread (of))' 1>OUTPUT 2>&1
|
notmuch search --query=sexp '(thread (of))' 1>OUTPUT 2>&1
|
||||||
notmuch search '*' > EXPECTED
|
notmuch search '*' > EXPECTED
|
||||||
|
@ -976,6 +996,11 @@ grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
||||||
notmuch search --output=files --query=sexp '(List *)' | sort | notmuch_dir_sanitize > OUTPUT
|
notmuch search --output=files --query=sexp '(List *)' | sort | notmuch_dir_sanitize > OUTPUT
|
||||||
test_expect_equal_file EXPECTED OUTPUT
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
|
test_begin_subtest "wildcard search for user header via field processor"
|
||||||
|
grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
||||||
|
notmuch search --output=files 'sexp:"(List *)"' | sort | notmuch_dir_sanitize > OUTPUT
|
||||||
|
test_expect_equal_file EXPECTED OUTPUT
|
||||||
|
|
||||||
test_begin_subtest "wildcard search for user header 2"
|
test_begin_subtest "wildcard search for user header 2"
|
||||||
grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
grep -Ril List-Id ${MAIL_DIR} | sort | notmuch_dir_sanitize > EXPECTED
|
||||||
notmuch search --output=files --query=sexp '(List (starts-with not))' | sort | notmuch_dir_sanitize > OUTPUT
|
notmuch search --output=files --query=sexp '(List (starts-with not))' | sort | notmuch_dir_sanitize > OUTPUT
|
||||||
|
|
Loading…
Reference in a new issue