parent
0dc073ffac
commit
d8bfa2317a
4 changed files with 176 additions and 36 deletions
|
|
@ -206,6 +206,7 @@ Arguments are listed next to predicate names, where applicable.
|
||||||
|
|
||||||
+ =category (&optional categories)= :: Return non-nil if current heading is in one or more of ~CATEGORIES~ (a list of strings).
|
+ =category (&optional categories)= :: Return non-nil if current heading is in one or more of ~CATEGORIES~ (a list of strings).
|
||||||
+ =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~.
|
||||||
|
+ =effort (&optional effort-or-comparator effort)= :: Return non-nil if current heading's effort property matches arguments. The following forms are accepted: ~(effort DURATION)~: Matches if effort is ~DURATION~. ~(effort DURATION DURATION)~: Matches if effort is between DURATIONs, inclusive. ~(effort COMPARATOR DURATION)~: Matches if effort compares to ~DURATION~ with ~COMPARATOR~. ~COMPARATOR~ may be ~<~, ~<=~, ~>~, or ~>=~. ~DURATION~ should be an Org effort string, like =5= or =0:05=.
|
||||||
+ =habit= :: Return non-nil if entry is a habit.
|
+ =habit= :: Return non-nil if entry is a habit.
|
||||||
+ =heading (&rest strings)= :: Return non-nil if current entry's heading matches all ~STRINGS~. Matching is done case-insensitively.
|
+ =heading (&rest strings)= :: Return non-nil if current entry's heading matches all ~STRINGS~. Matching is done case-insensitively.
|
||||||
- Aliases: =h=.
|
- Aliases: =h=.
|
||||||
|
|
@ -520,6 +521,7 @@ Simple links may also be written manually in either sexp or non-sexp form, like:
|
||||||
|
|
||||||
*Added*
|
*Added*
|
||||||
+ Macro =org-ql-defpred=, used to define search predicates. (See [[file:examples/defpred.org][tutorial]].)
|
+ Macro =org-ql-defpred=, used to define search predicates. (See [[file:examples/defpred.org][tutorial]].)
|
||||||
|
+ Predicate ~effort~.
|
||||||
+ Predicate ~heading-regexp~, which matches regular expressions against heading text (alias: ~h*~).
|
+ Predicate ~heading-regexp~, which matches regular expressions against heading text (alias: ~h*~).
|
||||||
|
|
||||||
*Changed*
|
*Changed*
|
||||||
|
|
|
||||||
67
org-ql.el
67
org-ql.el
|
|
@ -1017,6 +1017,73 @@ predicates."
|
||||||
;; NOTE: This was a defsubst before being defined with the macro. Might be good to make it a defsubst again.
|
;; NOTE: This was a defsubst before being defined with the macro. Might be good to make it a defsubst again.
|
||||||
:body (or (apply #'org-ql--predicate-todo org-done-keywords)))
|
:body (or (apply #'org-ql--predicate-todo org-done-keywords)))
|
||||||
|
|
||||||
|
(defun org-ql--duration-to-minutes (duration)
|
||||||
|
"Return DURATION string as a number of minutes.
|
||||||
|
For compatibility, since Org 9.1 deprecated
|
||||||
|
`org-duration-string-to-minutes', replacing it with
|
||||||
|
`org-duration-to-minutes', which seems to return floats instead
|
||||||
|
of integers."
|
||||||
|
;; MAYBE: Remove if compatibility with Org 9.0 is dropped.
|
||||||
|
(funcall (if (fboundp 'org-duration-to-minutes)
|
||||||
|
#'org-duration-to-minutes
|
||||||
|
#'org-duration-string-to-minutes)
|
||||||
|
duration))
|
||||||
|
|
||||||
|
(org-ql-defpred effort (&optional effort-or-comparator effort)
|
||||||
|
"Return non-nil if current heading's effort property matches arguments.
|
||||||
|
The following forms are accepted:
|
||||||
|
|
||||||
|
(effort DURATION): Matches if effort is DURATION.
|
||||||
|
(effort DURATION DURATION): Matches if effort is between DURATIONs, inclusive.
|
||||||
|
(effort COMPARATOR DURATION): Matches if effort compares to DURATION with COMPARATOR.
|
||||||
|
|
||||||
|
COMPARATOR may be `<', `<=', `>', or `>='. DURATION should be an
|
||||||
|
Org effort string, like \"5\" or \"0:05\"."
|
||||||
|
:normalizers ((`(,predicate-names . ,args)
|
||||||
|
;; Arguments could be given as strings (e.g. from a non-Lisp query).
|
||||||
|
`(effort ,@(--map (pcase-exhaustive it
|
||||||
|
((or "<" "<=" ">" ">=" "=")
|
||||||
|
(intern it))
|
||||||
|
((pred stringp) (org-ql--duration-to-minutes it))
|
||||||
|
((pred numberp) it)
|
||||||
|
((or '< '<= '> '>= '=)
|
||||||
|
;; FIXME: This same treatment probably needs to be done in the (level) predicate's normalizer (which I would have caught had I already written tests for it).
|
||||||
|
`',it))
|
||||||
|
args))))
|
||||||
|
;; NOTE: We always test the body, because we must ensure that the
|
||||||
|
;; ":effort:" string found is actually an entry property.
|
||||||
|
:preambles ((`(,predicate-names ,_comparator-or-num ,_num)
|
||||||
|
;; Since we can't compare this using regexps, we just check for what looks like a valid effort.
|
||||||
|
;; FIXME: Are decimal efforts allowed, or only colon-separated HH:MM?
|
||||||
|
(list :regexp (rx-to-string `(seq bol (0+ blank) ":effort:" (1+ blank) (1+ (or digit "." ":"))) t)
|
||||||
|
:case-fold t :query query))
|
||||||
|
(`(,predicate-names ,num)
|
||||||
|
;; Testing equality to a certain effort.
|
||||||
|
(let* ((with-colon (org-duration-from-minutes num))
|
||||||
|
(without-colon (number-to-string num))
|
||||||
|
(without-colon-and-decimal
|
||||||
|
(if (string-suffix-p ".0" without-colon)
|
||||||
|
(replace-regexp-in-string (rx ".0" eos) "" without-colon t t)
|
||||||
|
"")))
|
||||||
|
(list :regexp (rx-to-string `(seq bol (0+ blank) ":effort:" (1+ blank)
|
||||||
|
(or ,with-colon ,without-colon ,without-colon-and-decimal) (or blank eol)) t)
|
||||||
|
:case-fold t :query query))))
|
||||||
|
:body (let ((entry-effort (org-entry-get (point) "effort"))
|
||||||
|
entry-effort-minutes)
|
||||||
|
(when entry-effort
|
||||||
|
(setf entry-effort-minutes (org-ql--duration-to-minutes entry-effort))
|
||||||
|
(pcase effort-or-comparator
|
||||||
|
('nil
|
||||||
|
;; Any effort. (NOTE: This must come before the symbolp clause, because `symbolp' is non-nil for nil!)
|
||||||
|
t)
|
||||||
|
((pred numberp) (pcase effort
|
||||||
|
('nil ;; Equality
|
||||||
|
(= effort-or-comparator entry-effort-minutes))
|
||||||
|
((pred numberp) ;; Between two levels
|
||||||
|
(<= effort-or-comparator entry-effort-minutes effort))))
|
||||||
|
((pred symbolp) ;; Compare with function
|
||||||
|
(funcall effort-or-comparator entry-effort-minutes effort))))))
|
||||||
|
|
||||||
(org-ql-defpred habit ()
|
(org-ql-defpred habit ()
|
||||||
"Return non-nil if entry is a habit."
|
"Return non-nil if entry is a habit."
|
||||||
:preambles ((`(,predicate-names)
|
:preambles ((`(,predicate-names)
|
||||||
|
|
|
||||||
81
org-ql.info
81
org-ql.info
|
|
@ -401,6 +401,14 @@ Arguments are listed next to predicate names, where applicable.
|
||||||
(a list of strings).
|
(a list of strings).
|
||||||
‘done’
|
‘done’
|
||||||
Return non-nil if entry’s ‘TODO’ keyword is in ‘org-done-keywords’.
|
Return non-nil if entry’s ‘TODO’ keyword is in ‘org-done-keywords’.
|
||||||
|
‘effort (&optional effort-or-comparator effort)’
|
||||||
|
Return non-nil if current heading’s effort property matches
|
||||||
|
arguments. The following forms are accepted: ‘(effort DURATION)’:
|
||||||
|
Matches if effort is ‘DURATION’. ‘(effort DURATION DURATION)’:
|
||||||
|
Matches if effort is between DURATIONs, inclusive. ‘(effort
|
||||||
|
COMPARATOR DURATION)’: Matches if effort compares to ‘DURATION’
|
||||||
|
with ‘COMPARATOR’. ‘COMPARATOR’ may be ‘<’, ‘<=’, ‘>’, or ‘>=’.
|
||||||
|
‘DURATION’ should be an Org effort string, like 5 or 0:05.
|
||||||
‘habit’
|
‘habit’
|
||||||
Return non-nil if entry is a habit.
|
Return non-nil if entry is a habit.
|
||||||
‘heading (&rest strings)’
|
‘heading (&rest strings)’
|
||||||
|
|
@ -970,6 +978,7 @@ File: README.info, Node: 06-pre, Next: 052, Up: Changelog
|
||||||
*Added*
|
*Added*
|
||||||
• Macro org-ql-defpred, used to define search predicates. (See
|
• Macro org-ql-defpred, used to define search predicates. (See
|
||||||
tutorial (examples/defpred.org).)
|
tutorial (examples/defpred.org).)
|
||||||
|
• Predicate ‘effort’.
|
||||||
• Predicate ‘heading-regexp’, which matches regular expressions
|
• Predicate ‘heading-regexp’, which matches regular expressions
|
||||||
against heading text (alias: ‘h*’).
|
against heading text (alias: ‘h*’).
|
||||||
|
|
||||||
|
|
@ -1523,42 +1532,42 @@ Node: org-ql-sparse-tree7574
|
||||||
Node: Queries8374
|
Node: Queries8374
|
||||||
Node: Non-sexp query syntax9485
|
Node: Non-sexp query syntax9485
|
||||||
Node: General predicates11192
|
Node: General predicates11192
|
||||||
Node: Ancestor/descendant predicates16835
|
Node: Ancestor/descendant predicates17413
|
||||||
Node: Date/time predicates17963
|
Node: Date/time predicates18541
|
||||||
Node: Functions / Macros20618
|
Node: Functions / Macros21196
|
||||||
Node: Agenda-like views20916
|
Node: Agenda-like views21494
|
||||||
Node: Listing / acting-on results22321
|
Node: Listing / acting-on results22899
|
||||||
Node: Custom predicates27943
|
Node: Custom predicates28521
|
||||||
Node: Dynamic block31434
|
Node: Dynamic block32012
|
||||||
Node: Links34132
|
Node: Links34710
|
||||||
Node: Tips34819
|
Node: Tips35397
|
||||||
Node: Changelog35137
|
Node: Changelog35715
|
||||||
Node: 06-pre35863
|
Node: 06-pre36441
|
||||||
Node: 05237239
|
Node: 05237848
|
||||||
Node: 05137543
|
Node: 05138152
|
||||||
Node: 0537960
|
Node: 0538569
|
||||||
Node: 04939434
|
Node: 04940043
|
||||||
Node: 04839708
|
Node: 04840317
|
||||||
Node: 04740055
|
Node: 04740664
|
||||||
Node: 04640450
|
Node: 04641059
|
||||||
Node: 04540850
|
Node: 04541459
|
||||||
Node: 04441209
|
Node: 04441818
|
||||||
Node: 04341568
|
Node: 04342177
|
||||||
Node: 04241765
|
Node: 04242374
|
||||||
Node: 04141926
|
Node: 04142535
|
||||||
Node: 0442167
|
Node: 0442776
|
||||||
Node: 03246100
|
Node: 03246709
|
||||||
Node: 03146479
|
Node: 03147088
|
||||||
Node: 0346676
|
Node: 0347285
|
||||||
Node: 02349651
|
Node: 02350260
|
||||||
Node: 02249879
|
Node: 02250488
|
||||||
Node: 02150147
|
Node: 02150756
|
||||||
Node: 0250346
|
Node: 0250955
|
||||||
Node: 0154381
|
Node: 0154990
|
||||||
Node: Notes54482
|
Node: Notes55091
|
||||||
Node: Comparison with Org Agenda searches54644
|
Node: Comparison with Org Agenda searches55253
|
||||||
Node: org-sidebar55516
|
Node: org-sidebar56125
|
||||||
Node: License55795
|
Node: License56404
|
||||||
|
|
||||||
End Tag Table
|
End Tag Table
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -643,6 +643,68 @@ RESULTS should be a list of strings as returned by
|
||||||
(org-ql-expect ('(done))
|
(org-ql-expect ('(done))
|
||||||
'("Learn universal sign language")))
|
'("Learn universal sign language")))
|
||||||
|
|
||||||
|
(describe "(effort)"
|
||||||
|
(org-ql-it "with a number"
|
||||||
|
(org-ql-expect ('(effort 5))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort "5"))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort "0:05"))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort 1))
|
||||||
|
nil))
|
||||||
|
(org-ql-it "with two numbers"
|
||||||
|
(org-ql-expect ('(effort 5 6))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort "0:05" "0:05"))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort 4 5))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort 4 6))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort 6 7))
|
||||||
|
nil))
|
||||||
|
(org-ql-it "<"
|
||||||
|
(org-ql-expect ('(effort < 5))
|
||||||
|
nil)
|
||||||
|
(org-ql-expect ('(effort < 6))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort < "0:06"))
|
||||||
|
'("Order a pizza")))
|
||||||
|
(org-ql-it "<="
|
||||||
|
(org-ql-expect ('(effort <= 4))
|
||||||
|
nil)
|
||||||
|
(org-ql-expect ('(effort <= 5))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort <= 6))
|
||||||
|
'("Order a pizza"))
|
||||||
|
(org-ql-expect ('(effort <= "0:06"))
|
||||||
|
'("Order a pizza")))
|
||||||
|
(org-ql-it ">"
|
||||||
|
(org-ql-expect ('(effort > 4))
|
||||||
|
'("Order a pizza" "Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort > 5))
|
||||||
|
'("Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort > "0:05"))
|
||||||
|
'("Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort > 30))
|
||||||
|
nil)
|
||||||
|
(org-ql-expect ('(effort > "0:30"))
|
||||||
|
nil))
|
||||||
|
(org-ql-it ">="
|
||||||
|
(org-ql-expect ('(effort >= 4))
|
||||||
|
'("Order a pizza" "Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort >= 5))
|
||||||
|
'("Order a pizza" "Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort >= "0:05"))
|
||||||
|
'("Order a pizza" "Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort >= 30))
|
||||||
|
'("Shop for groceries"))
|
||||||
|
(org-ql-expect ('(effort >= 31))
|
||||||
|
nil)
|
||||||
|
(org-ql-expect ('(effort >= "0:31"))
|
||||||
|
nil)))
|
||||||
|
|
||||||
(org-ql-it "(habit)"
|
(org-ql-it "(habit)"
|
||||||
(org-ql-expect ('(habit))
|
(org-ql-expect ('(habit))
|
||||||
'("Practice leaping tall buildings in a single bound")))
|
'("Practice leaping tall buildings in a single bound")))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue