Re: [PATCH v2] emacs: add notmuch-expr, sexp-style queries

2020-11-22 Thread David Bremner
Tom Fitzhenry  writes:

> +(require 'ert)
> +(require 'notmuch-expr)

Any ideas (from anyone) how we can run these tests in the notmuch test
suite? I guess some kind of shim might be needed, but perhaps it can
just be wrapped in one or more test_emacs calls.

> +
> +(defmacro notmuch-expr (query)
> +  "Compile an sexp QUERY into a textual notmuch query."
> +  `(notmuch-expr--eval ,query))

Does this need to be a macro? If so I'd appreciate a brief comment as to
why. At this point optimizing performace seems pretty premature, but
maybe there are other good reasons.
> index 165aaa43..8c5843e5 100644
> --- a/emacs/notmuch.el
> +++ b/emacs/notmuch.el
> @@ -79,6 +79,7 @@
>  (require 'notmuch-maildir-fcc)
>  (require 'notmuch-message)
>  (require 'notmuch-parser)
> +(require 'notmuch-expr)
>  

I know we have just been requiring things historically, but I really
wonder if it's the right thing to do, especially since it seems the
library is not (yet) used for anything. Perhaps an autoload cookie on
the appropriate functions would be best.

By the way, I'd eventually like the CLI to parse S-expr queries (and/or
perhaps JSON queries) to avoid passing via strings (and all the problems
that entails). I'm not sure when I'll get around to it. There are also
some design details to be worked out, but hopefully it would bne a
mostly-compatible syntax with what is provided here.


___
notmuch mailing list -- notmuch@notmuchmail.org
To unsubscribe send an email to notmuch-le...@notmuchmail.org


Re: [PATCH v2] emacs: add notmuch-expr, sexp-style queries

2020-11-16 Thread Jonas Bernoulli
Tom Fitzhenry  writes:

> From: Tom Fitzhenry 
>
> notmuch-expr allows you to write notmuch search queries in sexp style like:
>
> (notmuch-expr
>   '(and
> (to "emacs-devel")
> "info manual"
> (or
>   (not (is "spam"))
>   (is "important"
>
> which will generate the textual query:
>
> "to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""
> ---
>  emacs/Makefile.local   |   1 +
>  emacs/notmuch-expr-test.el |  96 
>  emacs/notmuch-expr.el  | 124 +
>  emacs/notmuch.el   |   1 +
>  4 files changed, 222 insertions(+)
>  create mode 100644 emacs/notmuch-expr-test.el
>  create mode 100644 emacs/notmuch-expr.el
>
> diff --git a/emacs/Makefile.local b/emacs/Makefile.local
> index d1b320c3..f68e6e31 100644
> --- a/emacs/Makefile.local
> +++ b/emacs/Makefile.local
> @@ -22,6 +22,7 @@ emacs_sources := \
>   $(dir)/notmuch-version.el \
>   $(dir)/notmuch-jump.el \
>   $(dir)/notmuch-company.el \
> + $(dir)/notmuch-expr.el \
>   $(dir)/notmuch-draft.el
>  
>  elpa_sources := ${emacs_sources} $(dir)/notmuch-pkg.el
> diff --git a/emacs/notmuch-expr-test.el b/emacs/notmuch-expr-test.el
> new file mode 100644
> index ..92029fec
> --- /dev/null
> +++ b/emacs/notmuch-expr-test.el
> @@ -0,0 +1,96 @@
> +(require 'ert)
> +(require 'notmuch-expr)
> +
> +(ert-deftest and ()
> +  (should
> +(equal
> +  "(\"valued\" AND is:unread AND from:s...@example.com)"
> +  (notmuch-expr
> +   '(and
> + "valued"
> + (is "unread")
> + (from "s...@example.com"))
> +
> +(ert-deftest body ()
> +  (should
> +   (equal
> +"(body:wallace AND from:gromit)"
> +(notmuch-expr
> + '(and
> +   (body "wallace")
> +   (from "gromit"))
> +
> +(ert-deftest regex ()
> +  (should
> +   (equal
> +"(subject:\"/Ca+sh/\" AND NOT is:important)"
> +(notmuch-expr
> + '(and
> +   (subject "/Ca+sh/")
> +   (not (is "important")))
> +
> +(ert-deftest precedence ()
> +  (should
> +   (equal
> +"(to:emacs-devel AND (NOT is:spam OR is:important))"
> +(notmuch-expr
> + '(and
> +   (to "emacs-devel")
> +   (or
> + (not (is "spam"))
> + (is "important")))
> +
> +(ert-deftest xor ()
> +  (should
> +   (equal
> +"is:inbox XOR is:sent"
> +(notmuch-expr
> + '(xor
> +   (is "inbox")
> +   (is "sent"))
> +
> +(ert-deftest literal ()
> +  (should
> +   (equal
> +"(is:inbox OR from:foo)"
> +(notmuch-expr
> + '(or
> +   (is "inbox")
> +   (literal "from:foo"))
> +
> +(ert-deftest string ()
> +  (should
> +   (equal
> +"(is:inbox OR \"from:foo\")"
> +(notmuch-expr
> + '(or
> +   (is "inbox")
> +   "from:foo")
> +
> +(ert-deftest tag-with-spaces ()
> +  (should
> +   (equal
> +"is:\"a tag\""
> +(notmuch-expr
> + '(tag "a tag")
> +
> +(ert-deftest quoted-spaces ()
> +  (should
> +   (equal
> +"subject:\"Hello there\""
> +(notmuch-expr
> + '(subject "Hello there")
> +
> +(ert-deftest quoted-backslash ()
> +  (should
> +   (equal
> +"subject:\"A celebration! \\o/ Woo.\""
> +(notmuch-expr
> + '(subject "A celebration! \\o/ Woo.")
> +
> +(ert-deftest quoted-quote ()
> +  (should
> +   (equal
> +"subject:\"Gandalf: \\\"Use the force!\\\" 2001\""
> +(notmuch-expr
> + '(subject "Gandalf: \"Use the force!\" 2001")
> diff --git a/emacs/notmuch-expr.el b/emacs/notmuch-expr.el
> new file mode 100644
> index ..f5a3429f
> --- /dev/null
> +++ b/emacs/notmuch-expr.el
> @@ -0,0 +1,124 @@
> +;;; notmuch-expr.el --- An S-exp library for building notmuch search queries 
> -*- lexical-binding: t; -*-
> +
> +;; Author: Tom Fitzhenry 
> +;; Package-Requires: ((emacs "24.1"))
> +;; URL: https://notmuchmail.org

I recently improved consistency of the library headers.  They
don't confirm to the Emacs conventions but its close enough,
and I think internal consistency would be nice to maintain here.

Don't specify "URL".  "Homepage" would be better, but since this
is not an entry point library its better to omit this.  I think
"notmuch.el" is the only library that specifies this currently.

Likewise because "notmuch-expr" is not a standalone _package_
"Package-Requires" should not be specified.  By the way, notmuch
now requires emacs 25.1, so specifying a lower version would not
make sense here anyway.

 Cheers,
 Jonas

> +
> +;;; Commentary:
> +
> +;; This package provides a way to build notmuch search queries via 
> s-expressions.
> +;;
> +;; For example, rather than write:
> +
> +;; "to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""
> +;;
> +;; this package allows you to generate the same query via s-expressions:
> +;;
> +;; (notmuch-expr
> +;;  '(and
> +;;(to "emacs-devel")
> +;;"info manual"
> +;;(or
> +;;  (not (is "spam"))
> +;;  (is "impor

Re: [PATCH v2] emacs: add notmuch-expr, sexp-style queries

2020-11-16 Thread David Edmondson
On Friday, 2020-11-13 at 23:01:22 +11, Tom Fitzhenry wrote:

> From: Tom Fitzhenry 
>
> notmuch-expr allows you to write notmuch search queries in sexp style like:
>
> (notmuch-expr
>   '(and
> (to "emacs-devel")
> "info manual"
> (or
>   (not (is "spam"))
>   (is "important"
>
> which will generate the textual query:
>
> "to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""

Reviewed-by: David Edmondson 

> ---
>  emacs/Makefile.local   |   1 +
>  emacs/notmuch-expr-test.el |  96 
>  emacs/notmuch-expr.el  | 124 +
>  emacs/notmuch.el   |   1 +
>  4 files changed, 222 insertions(+)
>  create mode 100644 emacs/notmuch-expr-test.el
>  create mode 100644 emacs/notmuch-expr.el
>
> diff --git a/emacs/Makefile.local b/emacs/Makefile.local
> index d1b320c3..f68e6e31 100644
> --- a/emacs/Makefile.local
> +++ b/emacs/Makefile.local
> @@ -22,6 +22,7 @@ emacs_sources := \
>   $(dir)/notmuch-version.el \
>   $(dir)/notmuch-jump.el \
>   $(dir)/notmuch-company.el \
> + $(dir)/notmuch-expr.el \
>   $(dir)/notmuch-draft.el
>  
>  elpa_sources := ${emacs_sources} $(dir)/notmuch-pkg.el
> diff --git a/emacs/notmuch-expr-test.el b/emacs/notmuch-expr-test.el
> new file mode 100644
> index ..92029fec
> --- /dev/null
> +++ b/emacs/notmuch-expr-test.el
> @@ -0,0 +1,96 @@
> +(require 'ert)
> +(require 'notmuch-expr)
> +
> +(ert-deftest and ()
> +  (should
> +(equal
> +  "(\"valued\" AND is:unread AND from:s...@example.com)"
> +  (notmuch-expr
> +   '(and
> + "valued"
> + (is "unread")
> + (from "s...@example.com"))
> +
> +(ert-deftest body ()
> +  (should
> +   (equal
> +"(body:wallace AND from:gromit)"
> +(notmuch-expr
> + '(and
> +   (body "wallace")
> +   (from "gromit"))
> +
> +(ert-deftest regex ()
> +  (should
> +   (equal
> +"(subject:\"/Ca+sh/\" AND NOT is:important)"
> +(notmuch-expr
> + '(and
> +   (subject "/Ca+sh/")
> +   (not (is "important")))
> +
> +(ert-deftest precedence ()
> +  (should
> +   (equal
> +"(to:emacs-devel AND (NOT is:spam OR is:important))"
> +(notmuch-expr
> + '(and
> +   (to "emacs-devel")
> +   (or
> + (not (is "spam"))
> + (is "important")))
> +
> +(ert-deftest xor ()
> +  (should
> +   (equal
> +"is:inbox XOR is:sent"
> +(notmuch-expr
> + '(xor
> +   (is "inbox")
> +   (is "sent"))
> +
> +(ert-deftest literal ()
> +  (should
> +   (equal
> +"(is:inbox OR from:foo)"
> +(notmuch-expr
> + '(or
> +   (is "inbox")
> +   (literal "from:foo"))
> +
> +(ert-deftest string ()
> +  (should
> +   (equal
> +"(is:inbox OR \"from:foo\")"
> +(notmuch-expr
> + '(or
> +   (is "inbox")
> +   "from:foo")
> +
> +(ert-deftest tag-with-spaces ()
> +  (should
> +   (equal
> +"is:\"a tag\""
> +(notmuch-expr
> + '(tag "a tag")
> +
> +(ert-deftest quoted-spaces ()
> +  (should
> +   (equal
> +"subject:\"Hello there\""
> +(notmuch-expr
> + '(subject "Hello there")
> +
> +(ert-deftest quoted-backslash ()
> +  (should
> +   (equal
> +"subject:\"A celebration! \\o/ Woo.\""
> +(notmuch-expr
> + '(subject "A celebration! \\o/ Woo.")
> +
> +(ert-deftest quoted-quote ()
> +  (should
> +   (equal
> +"subject:\"Gandalf: \\\"Use the force!\\\" 2001\""
> +(notmuch-expr
> + '(subject "Gandalf: \"Use the force!\" 2001")
> diff --git a/emacs/notmuch-expr.el b/emacs/notmuch-expr.el
> new file mode 100644
> index ..f5a3429f
> --- /dev/null
> +++ b/emacs/notmuch-expr.el
> @@ -0,0 +1,124 @@
> +;;; notmuch-expr.el --- An S-exp library for building notmuch search queries 
> -*- lexical-binding: t; -*-
> +
> +;; Author: Tom Fitzhenry 
> +;; Package-Requires: ((emacs "24.1"))
> +;; URL: https://notmuchmail.org
> +
> +;;; Commentary:
> +
> +;; This package provides a way to build notmuch search queries via 
> s-expressions.
> +;;
> +;; For example, rather than write:
> +
> +;; "to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""
> +;;
> +;; this package allows you to generate the same query via s-expressions:
> +;;
> +;; (notmuch-expr
> +;;  '(and
> +;;(to "emacs-devel")
> +;;"info manual"
> +;;(or
> +;;  (not (is "spam"))
> +;;  (is "important"
> +;;
> +;; See notmuch-expr-test.el for more examples.
> +;;
> +;; Some search terms are unsupported. To use those, use the `literal' atom.
> +;; For example: (literal "path:spam")
> +;;
> +;; man page: notmuch-search-terms(7).
> +;; The generated search query may change across different versions.
> +
> +;;; Code:
> +
> +(defmacro notmuch-expr (query)
> +  "Compile an sexp QUERY into a textual notmuch query."
> +  `(notmuch-expr--eval ,query))
> +
> +(defun notmuch-expr--eval (expr)
> +  (pcase expr
> +(`(tag ,s) (notmuch-expr--is s

[PATCH v2] emacs: add notmuch-expr, sexp-style queries

2020-11-13 Thread Tom Fitzhenry
From: Tom Fitzhenry 

notmuch-expr allows you to write notmuch search queries in sexp style like:

(notmuch-expr
  '(and
(to "emacs-devel")
"info manual"
(or
  (not (is "spam"))
  (is "important"

which will generate the textual query:

"to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""
---
 emacs/Makefile.local   |   1 +
 emacs/notmuch-expr-test.el |  96 
 emacs/notmuch-expr.el  | 124 +
 emacs/notmuch.el   |   1 +
 4 files changed, 222 insertions(+)
 create mode 100644 emacs/notmuch-expr-test.el
 create mode 100644 emacs/notmuch-expr.el

diff --git a/emacs/Makefile.local b/emacs/Makefile.local
index d1b320c3..f68e6e31 100644
--- a/emacs/Makefile.local
+++ b/emacs/Makefile.local
@@ -22,6 +22,7 @@ emacs_sources := \
$(dir)/notmuch-version.el \
$(dir)/notmuch-jump.el \
$(dir)/notmuch-company.el \
+   $(dir)/notmuch-expr.el \
$(dir)/notmuch-draft.el
 
 elpa_sources := ${emacs_sources} $(dir)/notmuch-pkg.el
diff --git a/emacs/notmuch-expr-test.el b/emacs/notmuch-expr-test.el
new file mode 100644
index ..92029fec
--- /dev/null
+++ b/emacs/notmuch-expr-test.el
@@ -0,0 +1,96 @@
+(require 'ert)
+(require 'notmuch-expr)
+
+(ert-deftest and ()
+  (should
+(equal
+  "(\"valued\" AND is:unread AND from:s...@example.com)"
+  (notmuch-expr
+   '(and
+ "valued"
+ (is "unread")
+ (from "s...@example.com"))
+
+(ert-deftest body ()
+  (should
+   (equal
+"(body:wallace AND from:gromit)"
+(notmuch-expr
+ '(and
+   (body "wallace")
+   (from "gromit"))
+
+(ert-deftest regex ()
+  (should
+   (equal
+"(subject:\"/Ca+sh/\" AND NOT is:important)"
+(notmuch-expr
+ '(and
+   (subject "/Ca+sh/")
+   (not (is "important")))
+
+(ert-deftest precedence ()
+  (should
+   (equal
+"(to:emacs-devel AND (NOT is:spam OR is:important))"
+(notmuch-expr
+ '(and
+   (to "emacs-devel")
+   (or
+ (not (is "spam"))
+ (is "important")))
+
+(ert-deftest xor ()
+  (should
+   (equal
+"is:inbox XOR is:sent"
+(notmuch-expr
+ '(xor
+   (is "inbox")
+   (is "sent"))
+
+(ert-deftest literal ()
+  (should
+   (equal
+"(is:inbox OR from:foo)"
+(notmuch-expr
+ '(or
+   (is "inbox")
+   (literal "from:foo"))
+
+(ert-deftest string ()
+  (should
+   (equal
+"(is:inbox OR \"from:foo\")"
+(notmuch-expr
+ '(or
+   (is "inbox")
+   "from:foo")
+
+(ert-deftest tag-with-spaces ()
+  (should
+   (equal
+"is:\"a tag\""
+(notmuch-expr
+ '(tag "a tag")
+
+(ert-deftest quoted-spaces ()
+  (should
+   (equal
+"subject:\"Hello there\""
+(notmuch-expr
+ '(subject "Hello there")
+
+(ert-deftest quoted-backslash ()
+  (should
+   (equal
+"subject:\"A celebration! \\o/ Woo.\""
+(notmuch-expr
+ '(subject "A celebration! \\o/ Woo.")
+
+(ert-deftest quoted-quote ()
+  (should
+   (equal
+"subject:\"Gandalf: \\\"Use the force!\\\" 2001\""
+(notmuch-expr
+ '(subject "Gandalf: \"Use the force!\" 2001")
diff --git a/emacs/notmuch-expr.el b/emacs/notmuch-expr.el
new file mode 100644
index ..f5a3429f
--- /dev/null
+++ b/emacs/notmuch-expr.el
@@ -0,0 +1,124 @@
+;;; notmuch-expr.el --- An S-exp library for building notmuch search queries 
-*- lexical-binding: t; -*-
+
+;; Author: Tom Fitzhenry 
+;; Package-Requires: ((emacs "24.1"))
+;; URL: https://notmuchmail.org
+
+;;; Commentary:
+
+;; This package provides a way to build notmuch search queries via 
s-expressions.
+;;
+;; For example, rather than write:
+
+;; "to:emacs-devel AND (NOT is:spam OR is:important) AND \"info manual\""
+;;
+;; this package allows you to generate the same query via s-expressions:
+;;
+;; (notmuch-expr
+;;  '(and
+;;(to "emacs-devel")
+;;"info manual"
+;;(or
+;;  (not (is "spam"))
+;;  (is "important"
+;;
+;; See notmuch-expr-test.el for more examples.
+;;
+;; Some search terms are unsupported. To use those, use the `literal' atom.
+;; For example: (literal "path:spam")
+;;
+;; man page: notmuch-search-terms(7).
+;; The generated search query may change across different versions.
+
+;;; Code:
+
+(defmacro notmuch-expr (query)
+  "Compile an sexp QUERY into a textual notmuch query."
+  `(notmuch-expr--eval ,query))
+
+(defun notmuch-expr--eval (expr)
+  (pcase expr
+(`(tag ,s) (notmuch-expr--is s))
+(`(is ,s)  (notmuch-expr--is s))
+(`(from ,s)(notmuch-expr--from s))
+(`(to ,s)  (notmuch-expr--to s))
+(`(body ,s)(notmuch-expr--body s))
+(`(subject ,s) (notmuch-expr--subject s))
+
+;; Boolean operators.
+(`(and . ,clauses) (notmuch-expr--and clauses))
+(`(or . ,clauses)  (notmuch-expr--or clauses))
+(`(not ,clause)(notmuch-expr--not clause))
+(`(xor ,c1 ,c2)(notmuch-expr--xor c