Add heading-regexp predicate. Fix #64
This commit is contained in:
parent
b9dfd7d93b
commit
486778e9fa
3 changed files with 48 additions and 12 deletions
27
README.org
27
README.org
|
|
@ -153,19 +153,20 @@ An =org-ql= query is a lisp form which may contain arbitrary lisp forms, as well
|
||||||
|
|
||||||
The command =org-ql-search= also accepts, and the command =helm-org-ql= only accepts, an alternative, non-sexp query syntax. The syntax is simple, and a few examples of queries in both syntaxes should suffice. By default, when multiple predicates are used, they are combined with boolean =and=.
|
The command =org-ql-search= also accepts, and the command =helm-org-ql= only accepts, an alternative, non-sexp query syntax. The syntax is simple, and a few examples of queries in both syntaxes should suffice. By default, when multiple predicates are used, they are combined with boolean =and=.
|
||||||
|
|
||||||
| Sexp syntax | Non-sexp syntax |
|
| Sexp syntax | Non-sexp syntax |
|
||||||
|-------------------------------------------------+----------------------------------------------|
|
|---------------------------------------------------+--------------------------------------------------|
|
||||||
| ~(todo)~ | ~todo:~ |
|
| ~(todo)~ | ~todo:~ |
|
||||||
| ~(todo "SOMEDAY")~ | ~todo:SOMEDAY~ |
|
| ~(todo "SOMEDAY")~ | ~todo:SOMEDAY~ |
|
||||||
| ~(todo "SOMEDAY" "WAITING")~ | ~todo:SOMEDAY,WAITING~ |
|
| ~(todo "SOMEDAY" "WAITING")~ | ~todo:SOMEDAY,WAITING~ |
|
||||||
| ~(ts :on today)~ | ~ts:on=today~ |
|
| ~(ts :on today)~ | ~ts:on=today~ |
|
||||||
| ~(ts-active :from "2017-01-01" :to "2018-01-01")~ | ~ts-active:from=2017-01-01,to=2018-01-01~ |
|
| ~(ts-active :from "2017-01-01" :to "2018-01-01")~ | ~ts-active:from=2017-01-01,to=2018-01-01~ |
|
||||||
| ~(clocked :on -1)~ | ~clocked:on=-1~ |
|
| ~(clocked :on -1)~ | ~clocked:on=-1~ |
|
||||||
| ~(heading "quoted phrase" "word")~ | ~heading:"quoted phrase",word~ |
|
| ~(heading "quoted phrase" "word")~ | ~heading:"quoted phrase",word~ |
|
||||||
| ~(and (tags "book" "books") (priority "A"))~ | ~tags:book,books priority:A~ |
|
| ~(heading-regexp "quoted phrase" "[Ww]ord")~ | ~heading-regexp:"quoted phrase",[Ww]ord~ |
|
||||||
|
| ~(and (tags "book" "books") (priority "A"))~ | ~tags:book,books priority:A~ |
|
||||||
| ~(src :lang "elisp" :regexps ("defun"))~ | ~src:defun,lang=elisp~ or ~src:lang=elisp,defun~ |
|
| ~(src :lang "elisp" :regexps ("defun"))~ | ~src:defun,lang=elisp~ or ~src:lang=elisp,defun~ |
|
||||||
| ~(and (tags "space") (not (regexp "moon")))~ | ~tags:space !moon~ |
|
| ~(and (tags "space") (not (regexp "moon")))~ | ~tags:space !moon~ |
|
||||||
| ~(priority >= B)~ | ~priority:A,B~ |
|
| ~(priority >= B)~ | ~priority:A,B~ |
|
||||||
|
|
||||||
Note that the =priority= predicate does not support comparators in the non-sexp syntax, so multiple priorities should be passed instead, as seen in the last example.
|
Note that the =priority= predicate does not support comparators in the non-sexp syntax, so multiple priorities should be passed instead, as seen in the last example.
|
||||||
|
|
||||||
|
|
@ -183,6 +184,7 @@ Arguments are listed next to predicate names, where applicable.
|
||||||
+ =habit= :: Return non-nil if entry is a habit.
|
+ =habit= :: Return non-nil if entry is a habit.
|
||||||
+ =heading (&rest regexps)= :: Return non-nil if current entry's heading matches all ~REGEXPS~ (regexp strings).
|
+ =heading (&rest regexps)= :: Return non-nil if current entry's heading matches all ~REGEXPS~ (regexp strings).
|
||||||
- Aliases: =h=.
|
- Aliases: =h=.
|
||||||
|
+ =heading-regexp (&rest regexps)= :: Return non-nil if current entry's heading matches all ~REGEXPS~ (regexp strings).
|
||||||
+ =level (level-or-comparator &optional level)= :: Return non-nil if current heading's outline level matches arguments. The following forms are accepted: ~(level NUMBER)~: Matches if heading level is ~NUMBER~. ~(level NUMBER NUMBER)~: Matches if heading level is equal to or between NUMBERs. ~(level COMPARATOR NUMBER)~: Matches if heading level compares to ~NUMBER~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~.
|
+ =level (level-or-comparator &optional level)= :: Return non-nil if current heading's outline level matches arguments. The following forms are accepted: ~(level NUMBER)~: Matches if heading level is ~NUMBER~. ~(level NUMBER NUMBER)~: Matches if heading level is equal to or between NUMBERs. ~(level COMPARATOR NUMBER)~: Matches if heading level compares to ~NUMBER~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~.
|
||||||
+ =outline-path (&rest strings)= :: Return non-nil if current node's outline path matches all of ~STRINGS~. Each string may appear as a substring in any part of the node's outline path. For example, the path =Food/Fruits/Grapes= would match ~(olp "Fruit" "Grape")~.
|
+ =outline-path (&rest strings)= :: Return non-nil if current node's outline path matches all of ~STRINGS~. Each string may appear as a substring in any part of the node's outline path. For example, the path =Food/Fruits/Grapes= would match ~(olp "Fruit" "Grape")~.
|
||||||
- Aliases: ~olp~.
|
- Aliases: ~olp~.
|
||||||
|
|
@ -385,6 +387,7 @@ Expands into a call to ~org-ql-select~ with the same arguments. For convenience
|
||||||
+ *Queries*
|
+ *Queries*
|
||||||
- Negation of terms in plain queries using ~!~. For example, ~tags:space !moon~ to exclude entries which contain ~moon~.
|
- Negation of terms in plain queries using ~!~. For example, ~tags:space !moon~ to exclude entries which contain ~moon~.
|
||||||
- Predicates =outline-path= (alias =olp=) and =outline-path-segment= (alias =olps=).
|
- Predicates =outline-path= (alias =olp=) and =outline-path-segment= (alias =olps=).
|
||||||
|
- Predicate ~heading-regexp~, which matchs heading with regexps.
|
||||||
- Predicate ~src~, which matches Org Babel source blocks.
|
- Predicate ~src~, which matches Org Babel source blocks.
|
||||||
- Alias =h= for =heading= predicate.
|
- Alias =h= for =heading= predicate.
|
||||||
- Alias =r= for =regexp= predicate. (Thanks to [[https://github.com/tumashu][Feng Shu]].)
|
- Alias =r= for =regexp= predicate. (Thanks to [[https://github.com/tumashu][Feng Shu]].)
|
||||||
|
|
|
||||||
23
org-ql.el
23
org-ql.el
|
|
@ -696,6 +696,23 @@ replace the clause with a preamble."
|
||||||
'no-group))
|
'no-group))
|
||||||
element)
|
element)
|
||||||
|
|
||||||
|
;; Heading regexp.
|
||||||
|
;; MAYBE: Adjust regexp to avoid matching in tag list.
|
||||||
|
(`(heading-regexp ,regexp)
|
||||||
|
;; Only one regexp: match with preamble, then let predicate confirm (because
|
||||||
|
;; the match could be in e.g. the tags rather than the heading text).
|
||||||
|
(setq org-ql-preamble (rx-to-string `(seq bol (1+ "*") (1+ blank) (0+ nonl)
|
||||||
|
(regexp ,regexp))
|
||||||
|
'no-group))
|
||||||
|
element)
|
||||||
|
(`(heading-regexp . ,regexps)
|
||||||
|
;; Multiple regexps: use preamble to match against first
|
||||||
|
;; regexp, then let the predicate match the rest.
|
||||||
|
(setq org-ql-preamble (rx-to-string `(seq bol (1+ "*") (1+ blank) (0+ nonl)
|
||||||
|
(regexp ,(car regexps)))
|
||||||
|
'no-group))
|
||||||
|
element)
|
||||||
|
|
||||||
;; Heading levels.
|
;; Heading levels.
|
||||||
(`(level ,comparator-or-num ,num)
|
(`(level ,comparator-or-num ,num)
|
||||||
(let ((repeat (pcase comparator-or-num
|
(let ((repeat (pcase comparator-or-num
|
||||||
|
|
@ -1149,6 +1166,12 @@ priority B)."
|
||||||
(let ((heading (org-get-heading 'no-tags 'no-todo)))
|
(let ((heading (org-get-heading 'no-tags 'no-todo)))
|
||||||
(--all? (string-match it heading) regexps)))
|
(--all? (string-match it heading) regexps)))
|
||||||
|
|
||||||
|
(org-ql--defpred heading-regexp (&rest regexps)
|
||||||
|
"Return non-nil if current entry's heading matches all REGEXPS (regexp strings)."
|
||||||
|
;; TODO: In Org 9.2+, `org-get-heading' takes 2 more arguments.
|
||||||
|
(let ((heading (org-get-heading 'no-tags 'no-todo)))
|
||||||
|
(--all? (string-match it heading) regexps)))
|
||||||
|
|
||||||
(org-ql--defpred property (property &optional value)
|
(org-ql--defpred property (property &optional value)
|
||||||
"Return non-nil if current entry has PROPERTY (a string), and optionally VALUE (a string)."
|
"Return non-nil if current entry has PROPERTY (a string), and optionally VALUE (a string)."
|
||||||
(pcase property
|
(pcase property
|
||||||
|
|
|
||||||
|
|
@ -513,6 +513,16 @@ RESULTS should be a list of strings as returned by
|
||||||
(org-ql-expect ((heading "Take over" "world"))
|
(org-ql-expect ((heading "Take over" "world"))
|
||||||
'("Take over the world"))))
|
'("Take over the world"))))
|
||||||
|
|
||||||
|
(describe "(heading-regexp)"
|
||||||
|
(org-ql-it "with one argument"
|
||||||
|
(org-ql-expect ((heading-regexp "w[ol]r[lm]d"))
|
||||||
|
;; NOTE: This--correctly--does not match the "Skype with president of
|
||||||
|
;; Antarctica" heading, which has the tag ":world:" in its heading line.
|
||||||
|
'("Take over the world")))
|
||||||
|
(org-ql-it "with two arguments"
|
||||||
|
(org-ql-expect ((heading-regexp "Take over" "w[ol]r[lm]d"))
|
||||||
|
'("Take over the world"))))
|
||||||
|
|
||||||
(describe "(outline-path)"
|
(describe "(outline-path)"
|
||||||
(org-ql-it "with one argument"
|
(org-ql-it "with one argument"
|
||||||
(org-ql-expect ((outline-path "symphony"))
|
(org-ql-expect ((outline-path "symphony"))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue