From 4f29bcfd67aa88bf8f45b9b580e8f3ac84465700 Mon Sep 17 00:00:00 2001 From: Adam Porter Date: Thu, 9 Jun 2022 23:03:48 -0500 Subject: [PATCH] Add: (rifle/smart) Predicate --- README.org | 4 ++ org-ql.el | 26 ++++++++++++- org-ql.info | 106 ++++++++++++++++++++++++++++++---------------------- 3 files changed, 90 insertions(+), 46 deletions(-) diff --git a/README.org b/README.org index 25f3257..b89765a 100644 --- a/README.org +++ b/README.org @@ -236,6 +236,9 @@ Arguments are listed next to predicate names, where applicable. + =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)~. + =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=. ++ =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. + - Aliases: ~smart~. + - *Note:* By default, this is the default predicate used for plain-string query tokens (i.e. given without a specified predicate). This can be customized with the option ~org-ql-default-predicate~. + ~src (&key lang regexps)~ :: Return non-nil if current entry contains an Org Babel source block. If ~LANG~ is non-nil, match blocks of that language. If ~REGEXPS~ is non-nil, require that block's contents match all regexps. + =tags (&optional tags)= :: Return non-nil if current heading has one or more of ~TAGS~ (a list of strings). Tests both inherited and local tags. + =tags-inherited (&optional tags)= :: Return non-nil if current heading's inherited tags include one or more of ~TAGS~ (a list of strings). If ~TAGS~ is nil, return non-nil if heading has any inherited tags. @@ -539,6 +542,7 @@ Simple links may also be written manually in either sexp or non-sexp form, like: *Added* + Commands ~org-ql-find~, ~org-ql-find-heading~, and ~org-ql-find-path~, which jump to entries selected using Emacs's built-in completion facilities and Org QL queries (like ~helm-org-ql~, but doesn't require Helm.). ++ 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). *Changed* diff --git a/org-ql.el b/org-ql.el index 1cb78ad..3e54283 100644 --- a/org-ql.el +++ b/org-ql.el @@ -298,11 +298,13 @@ See Info node `(org-ql)Queries'." :type 'boolean :risky t) -(defcustom org-ql-default-predicate 'regexp +(defcustom org-ql-default-predicate 'rifle "Predicate used for plain-string tokens without a specified predicate." :type '(choice (const heading) (const heading-regexp) (const regexp) + (const rifle) + (const smart) (const outline-path) (const outline-path-segment))) @@ -1555,6 +1557,28 @@ any link is found." (string-match-p description-or-target (match-string org-ql-link-description-group))))))))) +(org-ql-defpred (rifle smart) (&rest strings) + "Return non-nil if each string argument is found in either the entry or its outline path. +Works like `org-rifle'. This is probably the most useful, +intuitive, general-purpose predicate." + ;; NOTE: This predicate advertises that it takes strings, but they + ;; are normalized to regexps. Because of that, we must use a + ;; coalescing function. + :coalesce-multiple-calls (lambda (coalesced-args current-args) + (setf (plist-get coalesced-args :regexps) + (list 'quote (append (cadr (plist-get coalesced-args :regexps)) + (cadr (plist-get current-args :regexps))))) + coalesced-args) + :normalizers ((`(,predicate-names . ,(and rest (guard (cl-every #'stringp rest)))) + ;; If this doesn't match, it's already normalized. + `(rifle :regexps ',(mapcar #'regexp-quote rest)))) + :preambles ((`(,predicate-names :regexps ',regexps) + (list :regexp (rx-to-string `(seq bow (or ,@(mapcar (lambda (s) `(regexp ,s)) regexps)))) + :case-fold t :query query))) + :body (cl-loop for regexp in (plist-get strings :regexps) + always (or (org-ql--predicate-regexp regexp) + (org-ql--predicate-outline-path regexp)))) + ;; MAYBE: Preambles for outline-path predicates. Not sure if possible without complicated logic. ;; FIXME: These preds say they accept regexps but the strings get regexp-quoted. They should probably just take strings. diff --git a/org-ql.info b/org-ql.info index 684a19e..25ccf74 100644 --- a/org-ql.info +++ b/org-ql.info @@ -483,6 +483,15 @@ Arguments are listed next to predicate names, where applicable. strings). Matches against entire entry, from beginning of its heading to the next heading. • 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. + • Aliases: ‘smart’. + • *Note:* By default, this is the default predicate used for + plain-string query tokens (i.e. given without a specified + predicate). This can be customized with the option + ‘org-ql-default-predicate’. ‘src (&key lang regexps)’ Return non-nil if current entry contains an Org Babel source block. If ‘LANG’ is non-nil, match blocks of that language. If ‘REGEXPS’ @@ -1008,6 +1017,13 @@ File: README.info, Node: 07-pre, Next: 062, Up: Changelog ‘org-ql-find-path’, which jump to entries selected using Emacs’s built-in completion facilities and Org QL queries (like ‘helm-org-ql’, but doesn’t require Helm.). + • 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 ‘org-rifle’ (https://github.com/alphapapa/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). @@ -1646,51 +1662,51 @@ Node: org-ql-sparse-tree8345 Node: Queries9145 Node: Non-sexp query syntax10262 Node: General predicates12021 -Node: Ancestor/descendant predicates18260 -Node: Date/time predicates19388 -Node: Functions / Macros22512 -Node: Agenda-like views22810 -Ref: Function ‘org-ql-block’22972 -Node: Listing / acting-on results24233 -Ref: Caching24441 -Ref: Function ‘org-ql-select’25354 -Ref: Function ‘org-ql-query’27780 -Ref: Macro ‘org-ql’ (deprecated)29554 -Node: Custom predicates29869 -Ref: Macro ‘org-ql-defpred’30093 -Node: Dynamic block33534 -Node: Links36258 -Node: Tips36945 -Node: Changelog37269 -Node: 07-pre38037 -Node: 06238786 -Node: 06139094 -Node: 0639662 -Node: 05242716 -Node: 05143016 -Node: 0543439 -Node: 04944968 -Node: 04845248 -Node: 04745595 -Node: 04646004 -Node: 04546412 -Node: 04446773 -Node: 04347132 -Node: 04247335 -Node: 04147496 -Node: 0447743 -Node: 03251844 -Node: 03152247 -Node: 0352444 -Node: 02355744 -Node: 02255978 -Node: 02156258 -Node: 0256463 -Node: 0160541 -Node: Notes60642 -Node: Comparison with Org Agenda searches60804 -Node: org-sidebar61693 -Node: License61972 +Node: Ancestor/descendant predicates18763 +Node: Date/time predicates19891 +Node: Functions / Macros23015 +Node: Agenda-like views23313 +Ref: Function ‘org-ql-block’23475 +Node: Listing / acting-on results24736 +Ref: Caching24944 +Ref: Function ‘org-ql-select’25857 +Ref: Function ‘org-ql-query’28283 +Ref: Macro ‘org-ql’ (deprecated)30057 +Node: Custom predicates30372 +Ref: Macro ‘org-ql-defpred’30596 +Node: Dynamic block34037 +Node: Links36761 +Node: Tips37448 +Node: Changelog37772 +Node: 07-pre38540 +Node: 06239801 +Node: 06140109 +Node: 0640677 +Node: 05243731 +Node: 05144031 +Node: 0544454 +Node: 04945983 +Node: 04846263 +Node: 04746610 +Node: 04647019 +Node: 04547427 +Node: 04447788 +Node: 04348147 +Node: 04248350 +Node: 04148511 +Node: 0448758 +Node: 03252859 +Node: 03153262 +Node: 0353459 +Node: 02356759 +Node: 02256993 +Node: 02157273 +Node: 0257478 +Node: 0161556 +Node: Notes61657 +Node: Comparison with Org Agenda searches61819 +Node: org-sidebar62708 +Node: License62987  End Tag Table