Change: Improve level predicate
Now accepts e.g. (level 2 4) to match headings from levels 2-4, inclusive. Also add tests for (level) preamble conversion.
This commit is contained in:
parent
99b38d131e
commit
bdf473356d
3 changed files with 57 additions and 21 deletions
|
|
@ -118,7 +118,7 @@ Note that, for convenience, standard numeric comparator function symbols (~<~, ~
|
||||||
+ ~done~ :: Return non-nil if entry's ~TODO~ keyword is in ~org-done-keywords~.
|
+ ~done~ :: Return non-nil if entry's ~TODO~ keyword is in ~org-done-keywords~.
|
||||||
+ ~habit~ :: Return non-nil if entry is a habit.
|
+ ~habit~ :: Return non-nil if entry is a habit.
|
||||||
+ ~heading (regexp)~ :: Return non-nil if current entry's heading matches ~REGEXP~ (a regexp string).
|
+ ~heading (regexp)~ :: Return non-nil if current entry's heading matches ~REGEXP~ (a regexp string).
|
||||||
+ ~level (level-or-comparator &optional level)~ :: Return non-nil if current heading's outline level matches ~LEVEL~ with ~COMPARATOR~. If ~LEVEL~ is nil, ~LEVEL-OR-COMPARATOR~ should be an integer level, which will be tested for equality to the heading's outline level. If ~LEVEL~ is non-nil, ~LEVEL-OR-COMPARATOR~ should be a comparator function (like ~<=~).
|
+ ~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 ~>=~.
|
||||||
+ ~planning (&optional comparator target-date)~ :: Return non-nil if entry's planning date (deadline or scheduled) compares with ~TARGET-DATE~ using ~COMPARATOR~. ~TARGET-DATE~ should be a string parseable by ~date-to-day~. ~COMPARATOR~ should be a function (like ~<=~).
|
+ ~planning (&optional comparator target-date)~ :: Return non-nil if entry's planning date (deadline or scheduled) compares with ~TARGET-DATE~ using ~COMPARATOR~. ~TARGET-DATE~ should be a string parseable by ~date-to-day~. ~COMPARATOR~ should be a function (like ~<=~).
|
||||||
+ ~priority (&optional comparator-or-priority priority)~ :: Return non-nil if current heading has a certain priority. ~COMPARATOR-OR-PRIORITY~ should be either a comparator function, like ~<=~, or a priority string, like "A" (in which case (~=~ will be the comparator). If ~COMPARATOR-OR-PRIORITY~ is a comparator, ~PRIORITY~ should be a priority string.
|
+ ~priority (&optional comparator-or-priority priority)~ :: Return non-nil if current heading has a certain priority. ~COMPARATOR-OR-PRIORITY~ should be either a comparator function, like ~<=~, or a priority string, like "A" (in which case (~=~ will be the comparator). If ~COMPARATOR-OR-PRIORITY~ is a comparator, ~PRIORITY~ should be a priority string.
|
||||||
+ ~property (property &optional value)~ :: Return non-nil if current entry has ~PROPERTY~ (a string), and optionally ~VALUE~ (a string).
|
+ ~property (property &optional value)~ :: Return non-nil if current entry has ~PROPERTY~ (a string), and optionally ~VALUE~ (a string).
|
||||||
|
|
|
||||||
41
org-ql.el
41
org-ql.el
|
|
@ -281,7 +281,7 @@ replace the clause with a preamble."
|
||||||
(pcase element
|
(pcase element
|
||||||
(`(or _) element)
|
(`(or _) element)
|
||||||
(`(regexp . ,regexps)
|
(`(regexp . ,regexps)
|
||||||
(let* ((regexp (rx-to-string `(or ,@regexps))))
|
(let* ((regexp (rx-to-string `(or ,@regexps) t)))
|
||||||
(setq org-ql-preamble regexp)
|
(setq org-ql-preamble regexp)
|
||||||
;; Return nil
|
;; Return nil
|
||||||
nil))
|
nil))
|
||||||
|
|
@ -289,13 +289,21 @@ replace the clause with a preamble."
|
||||||
(let* ((regexps (--map (list 'regexp
|
(let* ((regexps (--map (list 'regexp
|
||||||
(format org-heading-keyword-regexp-format it))
|
(format org-heading-keyword-regexp-format it))
|
||||||
todo-keywords))
|
todo-keywords))
|
||||||
(regexp (rx-to-string `(or ,@regexps))))
|
(regexp (rx-to-string `(or ,@regexps) t)))
|
||||||
(setq org-ql-preamble regexp)
|
(setq org-ql-preamble regexp)
|
||||||
;; Return nil
|
;; Return nil
|
||||||
nil))
|
nil))
|
||||||
;; FIXME: Need to handle e.g. (level <= 2)
|
(`(level ,comparator-or-num ,num)
|
||||||
|
(let ((repeat (pcase comparator-or-num
|
||||||
|
('< `(repeat 1 ,(1- num) "*"))
|
||||||
|
('<= `(repeat 1 ,num "*"))
|
||||||
|
('> `(>= ,(1+ num) "*"))
|
||||||
|
('>= `(>= ,num "*"))
|
||||||
|
((pred integerp) `(repeat ,comparator-or-num ,num "*")))))
|
||||||
|
(setq org-ql-preamble (rx-to-string `(seq bol ,repeat " ") t))
|
||||||
|
nil))
|
||||||
(`(level ,num)
|
(`(level ,num)
|
||||||
(let* ((regexp (rx-to-string `(seq bol (repeat ,num "*") " "))))
|
(let* ((regexp (rx-to-string `(seq bol (repeat ,num "*") " ") t)))
|
||||||
(setq org-ql-preamble regexp)
|
(setq org-ql-preamble regexp)
|
||||||
nil))
|
nil))
|
||||||
(`(and . ,rest)
|
(`(and . ,rest)
|
||||||
|
|
@ -502,20 +510,25 @@ With KEYWORDS, return non-nil if its keyword is one of KEYWORDS (a list of strin
|
||||||
(otherwise (seq-intersection tags tags-at)))))
|
(otherwise (seq-intersection tags tags-at)))))
|
||||||
|
|
||||||
(org-ql--defpred level (level-or-comparator &optional level)
|
(org-ql--defpred level (level-or-comparator &optional level)
|
||||||
"Return non-nil if current heading's outline level matches LEVEL with COMPARATOR.
|
"Return non-nil if current heading's outline level matches arguments.
|
||||||
|
The following forms are accepted:
|
||||||
|
|
||||||
If LEVEL is nil, LEVEL-OR-COMPARATOR should be an integer level,
|
(level NUMBER): Matches if heading level is NUMBER.
|
||||||
which will be tested for equality to the heading's outline level.
|
(level NUMBER NUMBER): Matches if heading level is equal to or between NUMBERs.
|
||||||
If LEVEL is non-nil, LEVEL-OR-COMPARATOR should be a comparator
|
(level COMPARATOR NUMBER): Matches if heading level compares to NUMBER with COMPARATOR.
|
||||||
function (like `<=')."
|
|
||||||
|
COMPARATOR may be `<', `<=', `>', or `>='."
|
||||||
;; NOTE: It might be necessary to take into account `org-odd-levels'; see docstring for
|
;; NOTE: It might be necessary to take into account `org-odd-levels'; see docstring for
|
||||||
;; `org-outline-level'.
|
;; `org-outline-level'.
|
||||||
(when-let ((outline-level (org-outline-level)))
|
(when-let ((outline-level (org-outline-level)))
|
||||||
(pcase level
|
(pcase level-or-comparator
|
||||||
;; Check for equality
|
((pred numberp) (pcase level
|
||||||
((pred null) (= outline-level level-or-comparator))
|
('nil ;; Equality
|
||||||
;; Check with comparator
|
(= outline-level level-or-comparator))
|
||||||
(_ (funcall level-or-comparator outline-level level)))))
|
((pred numberp) ;; Between two levels
|
||||||
|
(>= level-or-comparator outline-level level))))
|
||||||
|
((pred symbolp) ;; Compare with function
|
||||||
|
(funcall level-or-comparator outline-level level)))))
|
||||||
|
|
||||||
(org-ql--defpred priority (&optional comparator-or-priority priority)
|
(org-ql--defpred priority (&optional comparator-or-priority priority)
|
||||||
"Return non-nil if current heading has a certain priority.
|
"Return non-nil if current heading has a certain priority.
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,34 @@ Based on Buttercup macro `it'."
|
||||||
(cl-loop while (re-search-forward org-heading-regexp nil t)
|
(cl-loop while (re-search-forward org-heading-regexp nil t)
|
||||||
sum 1)))))
|
sum 1)))))
|
||||||
|
|
||||||
(describe "Predicates"
|
(describe "Query compiling"
|
||||||
|
;; Okay, so it's not really "compiling," but it sounds fancy. :)
|
||||||
|
|
||||||
|
;; TODO: Other predicates.
|
||||||
|
|
||||||
|
(describe "(level)"
|
||||||
|
(it "with a number"
|
||||||
|
(expect (org-ql--query-preamble '(level 2))
|
||||||
|
:to-equal `(t ,(rx bol (repeat 2 "*") " "))))
|
||||||
|
(it "with two numbers"
|
||||||
|
(expect (org-ql--query-preamble '(level 2 4))
|
||||||
|
:to-equal `(t ,(rx bol (repeat 2 4 "*") " "))))
|
||||||
|
(it "<"
|
||||||
|
(expect (org-ql--query-preamble '(level < 3))
|
||||||
|
:to-equal `(t ,(rx bol (repeat 1 2 "*") " "))))
|
||||||
|
(it "<="
|
||||||
|
(expect (org-ql--query-preamble '(level <= 2))
|
||||||
|
:to-equal `(t ,(rx bol (repeat 1 2 "*") " "))))
|
||||||
|
(it ">"
|
||||||
|
(expect (org-ql--query-preamble '(level > 2))
|
||||||
|
:to-equal `(t ,(rx bol (>= 3 "*") " "))))
|
||||||
|
(it ">="
|
||||||
|
(expect (org-ql--query-preamble '(level >= 2))
|
||||||
|
:to-equal `(t ,(rx bol (>= 2 "*") " "))))))
|
||||||
|
|
||||||
|
(describe "Query results"
|
||||||
|
|
||||||
|
;; TODO: Other predicates.
|
||||||
|
|
||||||
(describe "(category)"
|
(describe "(category)"
|
||||||
(org-ql-it "without arguments"
|
(org-ql-it "without arguments"
|
||||||
|
|
@ -364,10 +391,6 @@ Based on Buttercup macro `it'."
|
||||||
(expect (org-ql test-buffer
|
(expect (org-ql test-buffer
|
||||||
(ts :on "2019-06-09")
|
(ts :on "2019-06-09")
|
||||||
:action (org-ql-test-org-get-heading))
|
:action (org-ql-test-org-get-heading))
|
||||||
:to-equal nil))
|
:to-equal nil)))))
|
||||||
)
|
|
||||||
|
|
||||||
;; TODO: Other predicates.
|
|
||||||
))
|
|
||||||
|
|
||||||
;;; org-ql.el ends here
|
;;; org-ql.el ends here
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue