Add: (property) :inherit argument

This commit is contained in:
Adam Porter 2022-10-07 18:33:35 -05:00
parent e41cdb4591
commit e54ba0102c
3 changed files with 94 additions and 64 deletions

View file

@ -237,7 +237,7 @@ Arguments are listed next to predicate names, where applicable.
- Aliases: ~olps~. - Aliases: ~olps~.
+ =path (&rest regexps)= :: Return non-nil if current heading's buffer's filename path matches any of ~REGEXPS~ (regexp strings). Without arguments, return non-nil if buffer is file-backed. + =path (&rest regexps)= :: Return non-nil if current heading's buffer's filename path matches any of ~REGEXPS~ (regexp strings). Without arguments, return non-nil if buffer is file-backed.
+ =priority (&rest args)= :: Return non-nil if current heading has a certain priority. ~ARGS~ may be either a list of one or more priority letters as strings, or a comparator function symbol followed by a priority letter string. For example: ~(priority "A") (priority "A" "B") (priority '>= "B")~ Note that items without a priority cookie never match this predicate (while Org itself considers items without a cookie to have the default priority, which, by default, is equal to priority ~B~). + =priority (&rest args)= :: Return non-nil if current heading has a certain priority. ~ARGS~ may be either a list of one or more priority letters as strings, or a comparator function symbol followed by a priority letter string. For example: ~(priority "A") (priority "A" "B") (priority '>= "B")~ Note that items without a priority cookie never match this predicate (while Org itself considers items without a cookie to have the default priority, which, by default, is equal to priority ~B~).
+ =property (property &optional value)= :: Return non-nil if current entry has ~PROPERTY~ (a string), and optionally ~VALUE~ (a string). Note that property inheritance is currently /not/ enabled for this predicate. If you need to test with inheritance, you could use a custom predicate form, like ~(org-entry-get (point) "PROPERTY" 'inherit)~. + =property (property &optional value &key inherit)= :: Return non-nil if current entry has ~PROPERTY~ (a string), and optionally ~VALUE~ (a string). If ~INHERIT~ is nil, only match entries with ~PROPERTY~ set on the entry; if t, also match entries with inheritance. If ~INHERIT~ is not specified, use the Boolean value of ~org-use-property-inheritance~, which see (i.e. it is only interpreted as nil or non-nil).
+ =regexp (&rest regexps)= :: Return non-nil if current entry matches all of ~REGEXPS~ (regexp strings). Matches against entire entry, from beginning of its heading to the next heading. + =regexp (&rest regexps)= :: Return non-nil if current entry matches all of ~REGEXPS~ (regexp strings). Matches against entire entry, from beginning of its heading to the next heading.
- Aliases: =r=. - Aliases: =r=.
+ =rifle (&rest strings)= :: Return non-nil if each string is found in either the entry or its outline path. Works like =org-rifle=. This is probably the most useful, intuitive, general-purpose predicate. + =rifle (&rest strings)= :: Return non-nil if each string is found in either the entry or its outline path. Works like =org-rifle=. This is probably the most useful, intuitive, general-purpose predicate.
@ -550,6 +550,7 @@ Simple links may also be written manually in either sexp or non-sexp form, like:
+ Predicate ~rifle~, which matches an entry if each of the given arguments is found in either the entry's contents or its outline path. This provides very intuitive results, mimicing the behavior of [[https://github.com/alphapapa/org-rifle][=org-rifle=]]. In fact, the results are so useful that it's now the default predicate for plain-string query tokens. (It is also aliased to ~smart~, since it's so "smart," and not all users have used =org-rifle=.) + Predicate ~rifle~, which matches an entry if each of the given arguments is found in either the entry's contents or its outline path. This provides very intuitive results, mimicing the behavior of [[https://github.com/alphapapa/org-rifle][=org-rifle=]]. In fact, the results are so useful that it's now the default predicate for plain-string query tokens. (It is also aliased to ~smart~, since it's so "smart," and not all users have used =org-rifle=.)
+ Option ~org-ql-default-predicate~, applied to plain-string query tokens (before, the ~regexp~ predicate was always used, but now it may be customized). + Option ~org-ql-default-predicate~, applied to plain-string query tokens (before, the ~regexp~ predicate was always used, but now it may be customized).
+ Alias ~c~ for predicate ~category~. + Alias ~c~ for predicate ~category~.
+ Predicate ~property~ now accepts the argument ~:inherit~ to match entries with property inheritance, and when unspecified, the option ~org-use-property-inheritance~ controls whether inheritance is used.
*Changed* *Changed*
+ Give more useful error message for invalid queries. + Give more useful error message for invalid queries.

View file

@ -1729,30 +1729,43 @@ priority B)."
(cl-loop for priority-arg in args (cl-loop for priority-arg in args
thereis (= item-priority (* 1000 (- org-lowest-priority (string-to-char priority-arg))))))))) thereis (= item-priority (* 1000 (- org-lowest-priority (string-to-char priority-arg)))))))))
(org-ql-defpred property (property &optional value) (org-ql-defpred property (property &optional value &key inherit)
"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).
:normalizers ((`(,predicate-names ,property . ,value) If INHERIT is nil, only match entries with PROPERTY set on the
entry; if t, also match entries with inheritance. If INHERIT is
not specified, use the Boolean value of
`org-use-property-inheritance', which see (i.e. it is only
interpreted as nil or non-nil)."
:normalizers ((`(,predicate-names ,property ,value . ,plist)
;; Convert keyword property arguments to strings. Non-sexp ;; Convert keyword property arguments to strings. Non-sexp
;; queries result in keyword property arguments (because to do ;; queries result in keyword property arguments (because to do
;; otherwise would require ugly special-casing in the parsing). ;; otherwise would require ugly special-casing in the parsing).
(when (keywordp property) (when (keywordp property)
(setf property (substring (symbol-name property) 1))) (setf property (substring (symbol-name property) 1)))
(cons 'property (cons property value)))) (list 'property property value
:inherit (if (plist-member plist :inherit)
(plist-get plist :inherit)
org-use-property-inheritance))))
;; MAYBE: Should case folding be disabled for properties? What about values? ;; MAYBE: Should case folding be disabled for properties? What about values?
;; MAYBE: Support (property) without args. ;; MAYBE: Support (property) without args.
:preambles ((`(,predicate-names ,property ,value)
;; NOTE: When inheritance is enabled, the preamble can't be used,
;; which will make the search slower.
:preambles ((`(,predicate-names ,property ,value . ,(map :inherit))
;; We do NOT return nil, because the predicate still needs to be tested, ;; 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. ;; because the regexp could match a string not inside a property drawer.
(list :regexp (rx-to-string `(seq bol (0+ space) ":" ,property ":" (list :regexp (unless inherit
(1+ space) ,value (0+ space) eol)) (rx-to-string `(seq bol (0+ space) ":" ,property ":"
(1+ space) ,value (0+ space) eol)))
:query query)) :query query))
(`(,predicate-names ,property) (`(,predicate-names ,property . ,(map :inherit))
;; We do NOT return nil, because the predicate still needs to be tested, ;; 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. ;; because the regexp could match a string not inside a property drawer.
;; NOTE: The preamble only matches if there appears to be a value. ;; NOTE: The preamble only matches if there appears to be a value.
;; A line like ":ID: " without any other text does not match. ;; A line like ":ID: " without any other text does not match.
(list :regexp (rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space) (list :regexp (unless inherit
(minimal-match (1+ not-newline)) eol)) (rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space)
(minimal-match (1+ not-newline)) eol)))
:query query))) :query query)))
:body :body
(pcase property (pcase property
@ -1760,10 +1773,21 @@ priority B)."
(_ (pcase value (_ (pcase value
('nil ('nil
;; Check that PROPERTY exists ;; Check that PROPERTY exists
(org-entry-get (point) property)) (org-ql--value-at
(point) (lambda ()
(org-entry-get (point) property))))
(_ (_
;; Check that PROPERTY has VALUE ;; Check that PROPERTY has VALUE.
(string-equal value (org-entry-get (point) property 'selective)))))))
;; TODO: Since --value-at doesn't account for inheritance,
;; we should generalize --tags-at to also work for property
;; inheritance and use it here, which should be much faster.
(string-equal value (org-ql--value-at
(point) (lambda ()
(org-entry-get (point) property inherit)))))))))
;; TODO: Add property-local, property-inherit, etc. to match tags predicates.
;; TODO: Add tests for property inheritance.
(org-ql-defpred (regexp r) (&rest regexps) (org-ql-defpred (regexp r) (&rest regexps)
"Return non-nil if current entry matches all of REGEXPS (regexp strings)." "Return non-nil if current entry matches all of REGEXPS (regexp strings)."

View file

@ -476,12 +476,13 @@ Arguments are listed next to predicate names, where applicable.
predicate (while Org itself considers items without a cookie to predicate (while Org itself considers items without a cookie to
have the default priority, which, by default, is equal to priority have the default priority, which, by default, is equal to priority
B). B).
property (property &optional value) property (property &optional value &key inherit)
Return non-nil if current entry has PROPERTY (a string), and Return non-nil if current entry has PROPERTY (a string), and
optionally VALUE (a string). Note that property inheritance is optionally VALUE (a string). If INHERIT is nil, only match
currently _not_ enabled for this predicate. If you need to test entries with PROPERTY set on the entry; if t, also match entries
with inheritance, you could use a custom predicate form, like with inheritance. If INHERIT is not specified, use the Boolean
(org-entry-get (point) "PROPERTY" 'inherit). value of org-use-property-inheritance, which see (i.e. it is
only interpreted as nil or non-nil).
regexp (&rest regexps) regexp (&rest regexps)
Return non-nil if current entry matches all of REGEXPS (regexp Return non-nil if current entry matches all of REGEXPS (regexp
strings). Matches against entire entry, from beginning of its strings). Matches against entire entry, from beginning of its
@ -1034,6 +1035,10 @@ File: README.info, Node: 07-pre, Next: 062, Up: Changelog
tokens (before, the regexp predicate was always used, but now it tokens (before, the regexp predicate was always used, but now it
may be customized). may be customized).
• Alias c for predicate category. • Alias c for predicate category.
• Predicate property now accepts the argument :inherit to match
entries with property inheritance, and when unspecified, the option
org-use-property-inheritance controls whether inheritance is
used.
*Changed* *Changed*
• Give more useful error message for invalid queries. • Give more useful error message for invalid queries.
@ -1672,51 +1677,51 @@ Node: org-ql-sparse-tree8579
Node: Queries9379 Node: Queries9379
Node: Non-sexp query syntax10496 Node: Non-sexp query syntax10496
Node: General predicates12255 Node: General predicates12255
Node: Ancestor/descendant predicates18997 Node: Ancestor/descendant predicates19085
Node: Date/time predicates20125 Node: Date/time predicates20213
Node: Functions / Macros23249 Node: Functions / Macros23337
Node: Agenda-like views23547 Node: Agenda-like views23635
Ref: Function org-ql-block23709 Ref: Function org-ql-block23797
Node: Listing / acting-on results24970 Node: Listing / acting-on results25058
Ref: Caching25178 Ref: Caching25266
Ref: Function org-ql-select26091 Ref: Function org-ql-select26179
Ref: Function org-ql-query28517 Ref: Function org-ql-query28605
Ref: Macro org-ql (deprecated)30291 Ref: Macro org-ql (deprecated)30379
Node: Custom predicates30606 Node: Custom predicates30694
Ref: Macro org-ql-defpred30830 Ref: Macro org-ql-defpred30918
Node: Dynamic block34271 Node: Dynamic block34359
Node: Links36995 Node: Links37083
Node: Tips37682 Node: Tips37770
Node: Changelog38006 Node: Changelog38094
Node: 07-pre38774 Node: 07-pre38862
Node: 06240347 Node: 06240672
Node: 06140655 Node: 06140980
Node: 0641223 Node: 0641548
Node: 05244277 Node: 05244602
Node: 05144577 Node: 05144902
Node: 0545000 Node: 0545325
Node: 04946529 Node: 04946854
Node: 04846809 Node: 04847134
Node: 04747156 Node: 04747481
Node: 04647565 Node: 04647890
Node: 04547973 Node: 04548298
Node: 04448334 Node: 04448659
Node: 04348693 Node: 04349018
Node: 04248896 Node: 04249221
Node: 04149057 Node: 04149382
Node: 0449304 Node: 0449629
Node: 03253405 Node: 03253730
Node: 03153808 Node: 03154133
Node: 0354005 Node: 0354330
Node: 02357305 Node: 02357630
Node: 02257539 Node: 02257864
Node: 02157819 Node: 02158144
Node: 0258024 Node: 0258349
Node: 0162102 Node: 0162427
Node: Notes62203 Node: Notes62528
Node: Comparison with Org Agenda searches62365 Node: Comparison with Org Agenda searches62690
Node: org-sidebar63254 Node: org-sidebar63579
Node: License63533 Node: License63858
 
End Tag Table End Tag Table