Skip to content

Commit e54ba01

Browse files
committed
Add: (property) :inherit argument
1 parent e41cdb4 commit e54ba01

File tree

3 files changed

+94
-64
lines changed

3 files changed

+94
-64
lines changed

README.org

+2-1
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ Arguments are listed next to predicate names, where applicable.
237237
- Aliases: ~olps~.
238238
+ =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.
239239
+ =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~).
240-
+ =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)~.
240+
+ =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).
241241
+ =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.
242242
- Aliases: =r=.
243243
+ =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:
550550
+ 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=.)
551551
+ Option ~org-ql-default-predicate~, applied to plain-string query tokens (before, the ~regexp~ predicate was always used, but now it may be customized).
552552
+ Alias ~c~ for predicate ~category~.
553+
+ 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.
553554

554555
*Changed*
555556
+ Give more useful error message for invalid queries.

org-ql.el

+37-13
Original file line numberDiff line numberDiff line change
@@ -1729,41 +1729,65 @@ priority B)."
17291729
(cl-loop for priority-arg in args
17301730
thereis (= item-priority (* 1000 (- org-lowest-priority (string-to-char priority-arg)))))))))
17311731

1732-
(org-ql-defpred property (property &optional value)
1733-
"Return non-nil if current entry has PROPERTY (a string), and optionally VALUE (a string)."
1734-
:normalizers ((`(,predicate-names ,property . ,value)
1732+
(org-ql-defpred property (property &optional value &key inherit)
1733+
"Return non-nil if current entry has PROPERTY (a string), and optionally VALUE (a string).
1734+
If INHERIT is nil, only match entries with PROPERTY set on the
1735+
entry; if t, also match entries with inheritance. If INHERIT is
1736+
not specified, use the Boolean value of
1737+
`org-use-property-inheritance', which see (i.e. it is only
1738+
interpreted as nil or non-nil)."
1739+
:normalizers ((`(,predicate-names ,property ,value . ,plist)
17351740
;; Convert keyword property arguments to strings. Non-sexp
17361741
;; queries result in keyword property arguments (because to do
17371742
;; otherwise would require ugly special-casing in the parsing).
17381743
(when (keywordp property)
17391744
(setf property (substring (symbol-name property) 1)))
1740-
(cons 'property (cons property value))))
1745+
(list 'property property value
1746+
:inherit (if (plist-member plist :inherit)
1747+
(plist-get plist :inherit)
1748+
org-use-property-inheritance))))
17411749
;; MAYBE: Should case folding be disabled for properties? What about values?
17421750
;; MAYBE: Support (property) without args.
1743-
:preambles ((`(,predicate-names ,property ,value)
1751+
1752+
;; NOTE: When inheritance is enabled, the preamble can't be used,
1753+
;; which will make the search slower.
1754+
:preambles ((`(,predicate-names ,property ,value . ,(map :inherit))
17441755
;; We do NOT return nil, because the predicate still needs to be tested,
17451756
;; because the regexp could match a string not inside a property drawer.
1746-
(list :regexp (rx-to-string `(seq bol (0+ space) ":" ,property ":"
1747-
(1+ space) ,value (0+ space) eol))
1757+
(list :regexp (unless inherit
1758+
(rx-to-string `(seq bol (0+ space) ":" ,property ":"
1759+
(1+ space) ,value (0+ space) eol)))
17481760
:query query))
1749-
(`(,predicate-names ,property)
1761+
(`(,predicate-names ,property . ,(map :inherit))
17501762
;; We do NOT return nil, because the predicate still needs to be tested,
17511763
;; because the regexp could match a string not inside a property drawer.
17521764
;; NOTE: The preamble only matches if there appears to be a value.
17531765
;; A line like ":ID: " without any other text does not match.
1754-
(list :regexp (rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space)
1755-
(minimal-match (1+ not-newline)) eol))
1766+
(list :regexp (unless inherit
1767+
(rx-to-string `(seq bol (0+ space) ":" ,property ":" (1+ space)
1768+
(minimal-match (1+ not-newline)) eol)))
17561769
:query query)))
17571770
:body
17581771
(pcase property
17591772
('nil (user-error "Property matcher requires a PROPERTY argument"))
17601773
(_ (pcase value
17611774
('nil
17621775
;; Check that PROPERTY exists
1763-
(org-entry-get (point) property))
1776+
(org-ql--value-at
1777+
(point) (lambda ()
1778+
(org-entry-get (point) property))))
17641779
(_
1765-
;; Check that PROPERTY has VALUE
1766-
(string-equal value (org-entry-get (point) property 'selective)))))))
1780+
;; Check that PROPERTY has VALUE.
1781+
1782+
;; TODO: Since --value-at doesn't account for inheritance,
1783+
;; we should generalize --tags-at to also work for property
1784+
;; inheritance and use it here, which should be much faster.
1785+
(string-equal value (org-ql--value-at
1786+
(point) (lambda ()
1787+
(org-entry-get (point) property inherit)))))))))
1788+
1789+
;; TODO: Add property-local, property-inherit, etc. to match tags predicates.
1790+
;; TODO: Add tests for property inheritance.
17671791

17681792
(org-ql-defpred (regexp r) (&rest regexps)
17691793
"Return non-nil if current entry matches all of REGEXPS (regexp strings)."

org-ql.info

+55-50
Original file line numberDiff line numberDiff line change
@@ -476,12 +476,13 @@ Arguments are listed next to predicate names, where applicable.
476476
predicate (while Org itself considers items without a cookie to
477477
have the default priority, which, by default, is equal to priority
478478
‘B’).
479-
‘property (property &optional value)’
479+
‘property (property &optional value &key inherit)’
480480
Return non-nil if current entry has ‘PROPERTY’ (a string), and
481-
optionally ‘VALUE’ (a string). Note that property inheritance is
482-
currently _not_ enabled for this predicate. If you need to test
483-
with inheritance, you could use a custom predicate form, like
484-
‘(org-entry-get (point) "PROPERTY" 'inherit)’.
481+
optionally ‘VALUE’ (a string). If ‘INHERIT’ is nil, only match
482+
entries with ‘PROPERTY’ set on the entry; if t, also match entries
483+
with inheritance. If ‘INHERIT’ is not specified, use the Boolean
484+
value of ‘org-use-property-inheritance’, which see (i.e. it is
485+
only interpreted as nil or non-nil).
485486
‘regexp (&rest regexps)’
486487
Return non-nil if current entry matches all of ‘REGEXPS’ (regexp
487488
strings). Matches against entire entry, from beginning of its
@@ -1034,6 +1035,10 @@ File: README.info, Node: 07-pre, Next: 062, Up: Changelog
10341035
tokens (before, the ‘regexp’ predicate was always used, but now it
10351036
may be customized).
10361037
• Alias ‘c’ for predicate ‘category’.
1038+
• Predicate ‘property’ now accepts the argument ‘:inherit’ to match
1039+
entries with property inheritance, and when unspecified, the option
1040+
‘org-use-property-inheritance’ controls whether inheritance is
1041+
used.
10371042

10381043
*Changed*
10391044
• Give more useful error message for invalid queries.
@@ -1672,51 +1677,51 @@ Node: org-ql-sparse-tree8579
16721677
Node: Queries9379
16731678
Node: Non-sexp query syntax10496
16741679
Node: General predicates12255
1675-
Node: Ancestor/descendant predicates18997
1676-
Node: Date/time predicates20125
1677-
Node: Functions / Macros23249
1678-
Node: Agenda-like views23547
1679-
Ref: Function ‘org-ql-block’23709
1680-
Node: Listing / acting-on results24970
1681-
Ref: Caching25178
1682-
Ref: Function ‘org-ql-select’26091
1683-
Ref: Function ‘org-ql-query’28517
1684-
Ref: Macro ‘org-ql’ (deprecated)30291
1685-
Node: Custom predicates30606
1686-
Ref: Macro ‘org-ql-defpred’30830
1687-
Node: Dynamic block34271
1688-
Node: Links36995
1689-
Node: Tips37682
1690-
Node: Changelog38006
1691-
Node: 07-pre38774
1692-
Node: 06240347
1693-
Node: 06140655
1694-
Node: 0641223
1695-
Node: 05244277
1696-
Node: 05144577
1697-
Node: 0545000
1698-
Node: 04946529
1699-
Node: 04846809
1700-
Node: 04747156
1701-
Node: 04647565
1702-
Node: 04547973
1703-
Node: 04448334
1704-
Node: 04348693
1705-
Node: 04248896
1706-
Node: 04149057
1707-
Node: 0449304
1708-
Node: 03253405
1709-
Node: 03153808
1710-
Node: 0354005
1711-
Node: 02357305
1712-
Node: 02257539
1713-
Node: 02157819
1714-
Node: 0258024
1715-
Node: 0162102
1716-
Node: Notes62203
1717-
Node: Comparison with Org Agenda searches62365
1718-
Node: org-sidebar63254
1719-
Node: License63533
1680+
Node: Ancestor/descendant predicates19085
1681+
Node: Date/time predicates20213
1682+
Node: Functions / Macros23337
1683+
Node: Agenda-like views23635
1684+
Ref: Function ‘org-ql-block’23797
1685+
Node: Listing / acting-on results25058
1686+
Ref: Caching25266
1687+
Ref: Function ‘org-ql-select’26179
1688+
Ref: Function ‘org-ql-query’28605
1689+
Ref: Macro ‘org-ql’ (deprecated)30379
1690+
Node: Custom predicates30694
1691+
Ref: Macro ‘org-ql-defpred’30918
1692+
Node: Dynamic block34359
1693+
Node: Links37083
1694+
Node: Tips37770
1695+
Node: Changelog38094
1696+
Node: 07-pre38862
1697+
Node: 06240672
1698+
Node: 06140980
1699+
Node: 0641548
1700+
Node: 05244602
1701+
Node: 05144902
1702+
Node: 0545325
1703+
Node: 04946854
1704+
Node: 04847134
1705+
Node: 04747481
1706+
Node: 04647890
1707+
Node: 04548298
1708+
Node: 04448659
1709+
Node: 04349018
1710+
Node: 04249221
1711+
Node: 04149382
1712+
Node: 0449629
1713+
Node: 03253730
1714+
Node: 03154133
1715+
Node: 0354330
1716+
Node: 02357630
1717+
Node: 02257864
1718+
Node: 02158144
1719+
Node: 0258349
1720+
Node: 0162427
1721+
Node: Notes62528
1722+
Node: Comparison with Org Agenda searches62690
1723+
Node: org-sidebar63579
1724+
Node: License63858
17201725

17211726
End Tag Table
17221727

0 commit comments

Comments
 (0)