From e7eb3b2031429a30371d17f34ade539b44e7cd5c Mon Sep 17 00:00:00 2001 From: Adam Porter Date: Fri, 9 Aug 2019 16:47:56 -0500 Subject: [PATCH] Add: (property) Preambles --- notes.org | 46 ++++++++++++++++++++++++++++++++++++++++++-- org-ql.el | 23 ++++++++++++++++++++++ tests/test-org-ql.el | 14 ++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/notes.org b/notes.org index 9694dd2..f7f2d75 100644 --- a/notes.org +++ b/notes.org @@ -416,11 +416,15 @@ Also, maybe instead of having a single =date= selector, I should have =scheduled ** Preambles +Not sure if clearing the cache is necessary here, because it seemed to make nearly no difference in the results, but I don't know why. + #+BEGIN_SRC elisp :results silent (cl-defmacro org-ql-preamble-bench (&key query (file "tests/data.org") (times 10)) `(bench-multi-lets :times ,times :ensure-equal t - :lets (("preamble" ((org-ql-use-preamble t))) - ("no preamble" ((org-ql-use-preamble nil)))) + :lets (("preamble" ((org-ql-use-preamble t) + (org-ql-cache (ht)))) + ("no preamble" ((org-ql-use-preamble nil) + (org-ql-cache (ht))))) :forms ((,(prin1-to-string query) (org-ql-select ,file ',query :action '(org-get-heading t t)))))) @@ -440,6 +444,44 @@ Also, maybe instead of having a single =date= selector, I should have =scheduled | preamble: (level 1) | 1.34 | 0.562950 | 0 | 0 | | no preamble: (level 1) | slowest | 0.754050 | 0 | 0 | +*** =property= + +#+BEGIN_SRC elisp + (org-ql-preamble-bench :times 1 + :file "~/org/inbox.org" + :query (property "agenda-group")) +#+END_SRC + +#+RESULTS: +| Form | x faster than next | Total runtime | # of GCs | Total GC runtime | +|----------------------------------------+--------------------+---------------+----------+------------------| +| preamble: (property "agenda-group") | 70.44 | 0.016571 | 0 | 0 | +| no preamble: (property "agenda-group") | slowest | 1.167203 | 0 | 0 | + +#+BEGIN_SRC elisp + (org-ql-preamble-bench :times 1 + :file "~/org/inbox.org" + :query (property "ID")) +#+END_SRC + +#+RESULTS: +| Form | x faster than next | Total runtime | # of GCs | Total GC runtime | +|------------------------------+--------------------+---------------+----------+------------------| +| preamble: (property "ID") | 3.51 | 0.369830 | 0 | 0 | +| no preamble: (property "ID") | slowest | 1.299684 | 0 | 0 | + +#+BEGIN_SRC elisp + (org-ql-preamble-bench :times 1 + :file "~/org/inbox.org" + :query (property "agenda-group" "plans")) +#+END_SRC + +#+RESULTS: +| Form | x faster than next | Total runtime | # of GCs | Total GC runtime | +|------------------------------------------------+--------------------+---------------+----------+------------------| +| preamble: (property "agenda-group" "plans") | 72.54 | 0.016862 | 0 | 0 | +| no preamble: (property "agenda-group" "plans") | slowest | 1.223197 | 0 | 0 | + *** =tags= If tag inheritance is enabled, we have to check tags on every heading. When it's disabled, we can search directly to headings with the given tags. diff --git a/org-ql.el b/org-ql.el index e26ca94..58a3286 100644 --- a/org-ql.el +++ b/org-ql.el @@ -343,6 +343,29 @@ replace the clause with a preamble." (`(level ,num) (setq org-ql-preamble (rx-to-string `(seq bol (repeat ,num "*") " ") t)) nil) + (`(property ,property ,value) + ;; We do NOT return nil, because the predicate still needs to be tested, + ;; because the regexp could match a string not inside a property drawer. + (setq org-ql-preamble (rx-to-string `(seq bol (0+ space) ":" ,property ":" + (1+ space) ,value (0+ space) eol))) + element) + (`(property ,property) + ;; We do NOT return nil, because the predicate still needs to be tested, + ;; because the regexp could match a string not inside a property drawer. + ;; NOTE: The preamble only matches if there appears to be a value. + ;; A line like ":ID: " without any other text does not match. + (setq org-ql-preamble (rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space) + (minimal-match (1+ not-newline)) eol))) + element) + ;; MAYBE: Support (property) without args. + ;; (`(property) + ;; ;; We do NOT return nil, because the predicate still needs to be tested, + ;; ;; because the regexp could match a string not inside a property drawer. + ;; ;; NOTE: The preamble only matches if there appears to be a value. + ;; ;; A line like ":ID: " without any other text does not match. + ;; (setq org-ql-preamble (rx-to-string `(seq bol (0+ space) ":" (1+ (not (or space ":"))) ":" + ;; (1+ space) (minimal-match (1+ not-newline)) eol))) + ;; element) ((and `(tags . ,tags) (guard (not org-use-tag-inheritance))) ;; When tag inheritance is disabled, we only consider direct tags, ;; so we can search directly to headings containing one of the tags. diff --git a/tests/test-org-ql.el b/tests/test-org-ql.el index 4e5a8cf..51761f1 100644 --- a/tests/test-org-ql.el +++ b/tests/test-org-ql.el @@ -311,6 +311,20 @@ RESULTS should be a list of strings as returned by (org-ql-expect ((done)) '("Learn universal sign language"))) + (describe "(property)" + + ;; MAYBE: Add support for (property) without arguments. + ;; (org-ql-it "without arguments" + ;; (org-ql-expect ((property)))) + + (org-ql-it "with a property" + (org-ql-expect ((property "agenda-group")) + '("Take over the universe" "Spaceship lease" "Recurring" "Write a symphony"))) + + (org-ql-it "with a property and a value" + (org-ql-expect ((property "agenda-group" "plans")) + '("Take over the universe" "Write a symphony")))) + (describe "(regexp)" (org-ql-it "with 1 argument"