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~.
|
||||
+ ~habit~ :: Return non-nil if entry is a habit.
|
||||
+ ~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 ~<=~).
|
||||
+ ~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).
|
||||
|
|
|
|||
41
org-ql.el
41
org-ql.el
|
|
@ -281,7 +281,7 @@ replace the clause with a preamble."
|
|||
(pcase element
|
||||
(`(or _) element)
|
||||
(`(regexp . ,regexps)
|
||||
(let* ((regexp (rx-to-string `(or ,@regexps))))
|
||||
(let* ((regexp (rx-to-string `(or ,@regexps) t)))
|
||||
(setq org-ql-preamble regexp)
|
||||
;; Return nil
|
||||
nil))
|
||||
|
|
@ -289,13 +289,21 @@ replace the clause with a preamble."
|
|||
(let* ((regexps (--map (list 'regexp
|
||||
(format org-heading-keyword-regexp-format it))
|
||||
todo-keywords))
|
||||
(regexp (rx-to-string `(or ,@regexps))))
|
||||
(regexp (rx-to-string `(or ,@regexps) t)))
|
||||
(setq org-ql-preamble regexp)
|
||||
;; Return 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)
|
||||
(let* ((regexp (rx-to-string `(seq bol (repeat ,num "*") " "))))
|
||||
(let* ((regexp (rx-to-string `(seq bol (repeat ,num "*") " ") t)))
|
||||
(setq org-ql-preamble regexp)
|
||||
nil))
|
||||
(`(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)))))
|
||||
|
||||
(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,
|
||||
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 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 `>='."
|
||||
;; NOTE: It might be necessary to take into account `org-odd-levels'; see docstring for
|
||||
;; `org-outline-level'.
|
||||
(when-let ((outline-level (org-outline-level)))
|
||||
(pcase level
|
||||
;; Check for equality
|
||||
((pred null) (= outline-level level-or-comparator))
|
||||
;; Check with comparator
|
||||
(_ (funcall level-or-comparator outline-level level)))))
|
||||
(pcase level-or-comparator
|
||||
((pred numberp) (pcase level
|
||||
('nil ;; Equality
|
||||
(= outline-level level-or-comparator))
|
||||
((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)
|
||||
"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)
|
||||
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)"
|
||||
(org-ql-it "without arguments"
|
||||
|
|
@ -364,10 +391,6 @@ Based on Buttercup macro `it'."
|
|||
(expect (org-ql test-buffer
|
||||
(ts :on "2019-06-09")
|
||||
:action (org-ql-test-org-get-heading))
|
||||
:to-equal nil))
|
||||
)
|
||||
|
||||
;; TODO: Other predicates.
|
||||
))
|
||||
:to-equal nil)))))
|
||||
|
||||
;;; org-ql.el ends here
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue