diff --git a/README.org b/README.org index 1ecf6be..c57321b 100644 --- a/README.org +++ b/README.org @@ -153,17 +153,18 @@ An =org-ql= query is a lisp form which may contain arbitrary lisp forms, as well The command =org-ql-search= also accepts, and the command =helm-org-ql= only accepts, an alternative, non-sexp query syntax. The syntax is simple, and a few examples of queries in both syntaxes should suffice. By default, when multiple predicates are used, they are combined with boolean =and=. -| Sexp syntax | Non-sexp syntax | -|-------------------------------------------------+-----------------------------------------| -| ~(todo)~ | ~todo:~ | -| ~(todo "SOMEDAY")~ | ~todo:SOMEDAY~ | -| ~(todo "SOMEDAY" "WAITING")~ | ~todo:SOMEDAY,WAITING~ | -| ~(ts :on today)~ | ~ts:on=today~ | -| ~(ts-active :from "2017-01-01" :to "2018-01-01")~ | ~ts-active:from=2017-01-01,to=2018-01-01~ | -| ~(clocked :on -1)~ | ~clocked:on=-1~ | -| ~(heading "quoted phrase" "word")~ | ~heading:"quoted phrase",word~ | -| ~(and (tags "book" "books") (priority "A"))~ | ~tags:book,books priority:A~ | -| ~(priority >= B)~ | ~priority:A,B~ | +| Sexp syntax | Non-sexp syntax | +|-------------------------------------------------+----------------------------------------------| +| ~(todo)~ | ~todo:~ | +| ~(todo "SOMEDAY")~ | ~todo:SOMEDAY~ | +| ~(todo "SOMEDAY" "WAITING")~ | ~todo:SOMEDAY,WAITING~ | +| ~(ts :on today)~ | ~ts:on=today~ | +| ~(ts-active :from "2017-01-01" :to "2018-01-01")~ | ~ts-active:from=2017-01-01,to=2018-01-01~ | +| ~(clocked :on -1)~ | ~clocked:on=-1~ | +| ~(heading "quoted phrase" "word")~ | ~heading:"quoted phrase",word~ | +| ~(and (tags "book" "books") (priority "A"))~ | ~tags:book,books priority:A~ | +| ~(src :lang "elisp" :regexps ("defun"))~ | ~src:defun,lang=elisp~ or ~src:lang=elisp,defun~ | +| ~(priority >= B)~ | ~priority:A,B~ | Note that the =priority= predicate does not support comparators in the non-sexp syntax, so multiple priorities should be passed instead, as seen in the last example. @@ -189,7 +190,7 @@ Arguments are listed next to predicate names, where applicable. + =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. If both arguments are nil, return non-nil if heading has any defined priority. + =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. -+ ~src (&optional 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. ++ ~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. - Aliases: ~inherited-tags~, ~tags-i~, ~itags~. diff --git a/org-ql.el b/org-ql.el index 4d30744..b5d898b 100644 --- a/org-ql.el +++ b/org-ql.el @@ -591,6 +591,26 @@ Replaces bare strings with (regexp) selectors, and appropriate (setf property (substring (symbol-name property) 1))) (cons 'property (cons property value))) + ;; Source blocks. + (`(src . ,args) + ;; Rewrite to use keyword args. + (-let (regexps lang keyword-index) + (cond ((plist-get args :lang) + ;; Lang given first, or only lang given. + (setf lang (plist-get args :lang) + regexps (seq-difference args (list :lang lang)))) + ((setf keyword-index (-find-index #'keywordp args)) + ;; Regexps and lang given. + (setf lang (plist-get (cl-subseq args keyword-index) :lang) + regexps (cl-subseq args 0 keyword-index))) + (t ;; Only regexps given. + (setf regexps args))) + (when regexps + ;; This feels awkward and wrong, but we have to quote lists + ;; and avoid quoting nil. There must be a better way. + (setf regexps `(',regexps))) + `(src :lang ,lang :regexps ,@regexps))) + ;; Tags. (`(,(or 'tags-all 'tags&) . ,tags) `(and ,@(--map `(tags ,it) tags))) ;; MAYBE: -all versions for inherited and local. @@ -747,8 +767,8 @@ replace the clause with a preamble." ;; element) ;; Src blocks. - (`(src ,lang . ,_) - (setq org-ql-preamble (org-ql--format-src-block-regexp lang)) + (`(src . ,args) + (setq org-ql-preamble (org-ql--format-src-block-regexp (plist-get args :lang))) ;; Always check contents with predicate. element) @@ -795,7 +815,7 @@ replace the clause with a preamble." (rx-to-string `(seq bol (group (zero-or-more (any " "))) "#+begin_src" (one-or-more (any " ")) - ,lang + ,(or lang `(1+ (not (any " \n \f ")))) (zero-or-more (any " ")) (group (or (seq (zero-or-more (not (any "\n\":"))) "\"" @@ -1130,9 +1150,10 @@ priority B)." ;; Check that PROPERTY has VALUE (string-equal value (org-entry-get (point) property 'selective))))))) -(org-ql--defpred src (&optional lang &rest regexps) +(org-ql--defpred src (&key regexps lang) "Return non-nil if current entry contains an Org source block matching all of REGEXPS. -If LANG is non-nil, the block must be in that language." +If keyword argument LANG is non-nil, the block must be in that +language." (catch 'return (save-excursion (save-match-data diff --git a/org-ql.info b/org-ql.info index fd67821..4c5c984 100644 --- a/org-ql.info +++ b/org-ql.info @@ -329,7 +329,7 @@ default, when multiple predicates are used, they are combined with boolean and. Sexp syntax Non-sexp syntax ------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------- ‘(todo)’ ‘todo:’ ‘(todo "SOMEDAY")’ ‘todo:SOMEDAY’ ‘(todo "SOMEDAY" "WAITING")’ ‘todo:SOMEDAY,WAITING’ @@ -338,6 +338,7 @@ Sexp syntax Non-sexp syntax ‘(clocked :on -1)’ ‘clocked:on=-1’ ‘(heading "quoted phrase" "word")’ ‘heading:"quoted phrase",word’ ‘(and (tags "book" "books") (priority "A"))’ ‘tags:book,books priority:A’ +‘(src :lang "elisp" :regexps ("defun"))’ ‘src:defun,lang=elisp’ or ‘src:lang=elisp,defun’ ‘(priority >= B)’ ‘priority:A,B’ Note that the priority predicate does not support comparators in the @@ -411,7 +412,7 @@ Arguments are listed next to predicate names, where applicable. 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. -‘‘src (&optional lang regexps)’’ +‘‘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. @@ -979,24 +980,24 @@ Node: org-ql-view-recent-items6452 Node: org-ql-sparse-tree6936 Node: Queries7736 Node: Non-sexp query syntax8578 -Node: Predicates10078 -Node: Date/time predicates15197 -Node: Functions / Macros17832 -Node: Agenda-like views18019 -Node: Listing / acting-on results19424 -Node: Changelog24026 -Node: 04-pre24548 -Node: 03125492 -Node: 0325690 -Node: 02328663 -Node: 02228889 -Node: 02129155 -Node: 0229352 -Node: 0133385 -Node: Notes33484 -Node: Comparison with Org Agenda searches33646 -Node: org-sidebar34517 -Node: License34796 +Node: Predicates10198 +Node: Date/time predicates15312 +Node: Functions / Macros17947 +Node: Agenda-like views18134 +Node: Listing / acting-on results19539 +Node: Changelog24141 +Node: 04-pre24663 +Node: 03125607 +Node: 0325805 +Node: 02328778 +Node: 02229004 +Node: 02129270 +Node: 0229467 +Node: 0133500 +Node: Notes33599 +Node: Comparison with Org Agenda searches33761 +Node: org-sidebar34632 +Node: License34911  End Tag Table