diff --git a/README.org b/README.org index 39fbfd7..e8da48f 100644 --- a/README.org +++ b/README.org @@ -244,29 +244,30 @@ Arguments are listed next to predicate names, where applicable. *** Date/time predicates -All of these predicates take optional keyword arguments ~:from~, ~:to:~, and ~:on~: +These predicates take optional keyword arguments: -+ If ~:from~, return non-nil if entry has a timestamp on or after ~:from~. -+ If ~:to~, return non-nil if entry has a timestamp on or before ~:to~. -+ If ~:on~, return non-nil if entry has a timestamp on date ~:on~. ++ ~:from~: Match entries whose timestamp is on or after timestamp ~:from~. ++ ~:to~: Match entries whose timestamp is on or before timestamp ~:to~. ++ ~:on~: Match entries whose timestamp is on date ~:on~. ++ ~:with-time~: If unspecified, match timestamps with or without times (i.e. HH:MM). If nil, match timestamps without times. If t, match timestamps with times. -Argument values should be either a number of days (positive to look forward, or negative to look backward), a ~ts~ struct, or a string parseable by ~parse-time-string~ (the string may omit the time value). +Timestamp/date arguments should be either a number of days (positive to look forward, or negative to look backward), a string parseable by ~parse-time-string~ (the string may omit the time value), or a ~ts~ struct. + *Predicates* - - =ts= :: Return non-nil if current entry has a timestamp in given period. If no arguments are specified, return non-nil if entry has any timestamp. + - =ts= :: Return non-nil if current entry has a timestamp in given period. Without arguments, return non-nil if entry has a timestamp. - =ts-active=, =ts-a= :: Like =ts=, but only matches active timestamps. - =ts-inactive=, =ts-i= :: Like =ts=, but only matches inactive timestamps. The following predicates, in addition to the keyword arguments, can also take a single argument, a number, which looks backward or forward a number of days. The number can be negative to invert the direction. + *Backward-looking* - - =clocked= :: Return non-nil if current entry was clocked in given period. If no arguments are specified, return non-nil if entry was clocked at any time. Note: Clock entries are expected to be clocked out. Currently clocked entries (i.e. with unclosed timestamp ranges) are ignored. - - =closed= :: Return non-nil if current entry was closed in given period. If no arguments are specified, return non-nil if entry was closed at any time. + - =clocked= :: Return non-nil if current entry was clocked in given period. Without arguments, return non-nil if entry was ever clocked. Note: Clock entries are expected to be clocked out. Currently clocked entries (i.e. with unclosed timestamp ranges) are ignored. + - =closed= :: Return non-nil if current entry was closed in given period. Without arguments, return non-nil if entry is closed. + *Forward-looking* - - =deadline= :: Return non-nil if current entry has deadline in given period. If argument is =auto=, return non-nil if entry has deadline within =org-deadline-warning-days=. If no arguments are specified, return non-nil if entry has any deadline. - - =planning= :: Return non-nil if current entry has planning timestamp in given period (i.e. its deadline, scheduled, or closed timestamp). If no arguments are specified, return non-nil if entry is scheduled at any time. - - =scheduled= :: Return non-nil if current entry is scheduled in given period. If no arguments are specified, return non-nil if entry is scheduled at any time. + - =deadline= :: Return non-nil if current entry has deadline in given period. If argument is =auto=, return non-nil if entry has deadline within =org-deadline-warning-days=. Without arguments, return non-nil if entry has any deadline. + - =planning= :: Return non-nil if current entry has planning timestamp (i.e. its deadline, scheduled, or closed timestamp) in given period. Without arguments, return non-nil if entry has any planning timestamp. + - =scheduled= :: Return non-nil if current entry is scheduled in given period. Without arguments, return non-nil if entry is scheduled. ** Functions / Macros :PROPERTIES: @@ -523,6 +524,7 @@ Simple links may also be written manually in either sexp or non-sexp form, like: + 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*~). ++ Timestamp-related predicates now accept an optional ~:with-time~ argument, which allows matching timestamps with or without times (i.e. HH:MM). *Changed* + Helm support (including the command =helm-org-ql=) has been moved to a separate package, =helm-org-ql=. diff --git a/org-ql.el b/org-ql.el index 8f7cf23..924ce08 100644 --- a/org-ql.el +++ b/org-ql.el @@ -1846,34 +1846,41 @@ With KEYWORDS, return non-nil if its keyword is one of KEYWORDS (a list of strin ;;;;;; Timestamps -;; TODO: Remove the _on vars from these arg lists. I think they're not +;; NOTE: The underscores before some arguments in these definitions +;; prevent "unused lexical variable" warnings, because we pre-process +;; them before the functions are called. + +;; TODO: Remove the _underscored vars from these arg lists. I think they're not ;; necessary, or shouldn't be, since --pre-process-query should handle them. -;; NOTE: These docstrings apply to the functions defined by `org-ql--defpref', -;; not necessarily to the way users are expected to call them in queries. The -;; queries are pre-processed by `org-ql--normalize-query' to handle -;; arguments which are constant during a query's execution. +;; NOTE: Arguments to these predicates are pre-processed in +;; `org-ql--normalize-query' and `org-ql--query-predicate'. Some +;; arguments are not to be given by the user in a query, +;; e.g. `regexp'. FROM and TO are actually expected to be `ts' +;; structs. However, the docstrings are written for users, which +;; makes documentation easier to update. ;; TODO: Update the macro to define a user-facing docstring so I don't ;; have to manually update the documentation. -(org-ql-defpred clocked (&key from to _on) - ;; The underscore before `on' prevents "unused lexical variable" - ;; warnings, because we pre-process that argument in a macro before - ;; this function is called. - "Return non-nil if current entry was clocked in given period. -If no arguments are specified, return non-nil if entry has any -timestamp. +;; This string is common to these predicates and is used in +;; documentation; keeping it here should make it easier to update: +"If FROM, return non-nil if entry's timestamp is on or after FROM. -If FROM, return non-nil if entry has a timestamp on or after -FROM. +If TO, return non-nil if entry's timestamp is on or before TO. -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. +If ON, return non-nil if entry's timestamp is on date ON. FROM, TO, and ON should be either `ts' structs, or strings parseable by `parse-time-string' which may omit the time value." + +(org-ql-defpred clocked (&key from to _on) + "Return non-nil if current entry was clocked in given period. +Without arguments, return non-nil if entry was ever clocked. +Note: Clock entries are expected to be clocked out. Currently +clocked entries (i.e. with unclosed timestamp ranges) are +ignored." + ;; TODO: Verify that currently clocked entries are still ignored. :normalizers ((`(,predicate-names ,(and num-days (pred numberp))) ;; (clocked) and (closed) implicitly look into the past. (let ((from (->> (ts-now) @@ -1888,23 +1895,9 @@ parseable by `parse-time-string' which may omit the time value." (org-ql--predicate-ts :from from :to to :regexp org-ql-clock-regexp :match-group 1)) (org-ql-defpred closed (&key from to _on) - ;; TODO: Should this use the new org-ql-regexps? - ;; The underscore before `on' prevents "unused lexical variable" - ;; warnings, because we pre-process that argument in a macro before - ;; this function is called. + ;; MAYBE: Use the new org-ql-regexps? "Return non-nil if current entry was closed in given period. -If no arguments are specified, return non-nil if entry has any -timestamp. - -If FROM, return non-nil if entry has a timestamp on or after -FROM. - -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. - -FROM, TO, and ON should be either `ts' structs, or strings -parseable by `parse-time-string' which may omit the time value." +Without arguments, return non-nil if entry is closed." :normalizers ((`(,predicate-names ,(and num-days (pred numberp))) ;; (clocked) and (closed) implicitly look into the past. (let ((from (->> (ts-now) @@ -1919,22 +1912,10 @@ parseable by `parse-time-string' which may omit the time value." :limit (line-end-position 2))) (org-ql-defpred deadline (&key from to _on regexp _with-time) - ;; The underscore before `on' prevents "unused lexical variable" - ;; warnings, because we pre-process that argument in a macro before - ;; this function is called. "Return non-nil if current entry has deadline in given period. -If no arguments are specified, return non-nil if entry has any -timestamp. - -If FROM, return non-nil if entry has a timestamp on or after -FROM. - -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. - -FROM, TO, and ON should be either `ts' structs, or strings -parseable by `parse-time-string' which may omit the time value." +If argument is `auto', return non-nil if entry has deadline +within `org-deadline-warning-days'. Without arguments, return +non-nil if entry has a deadline." :normalizers ((`(,predicate-names auto) ;; Use `org-deadline-warning-days' as the :to arg. (let ((to (->> (ts-now) @@ -1946,7 +1927,8 @@ parseable by `parse-time-string' which may omit the time value." (ts-adjust 'day num-days) (ts-apply :hour 23 :minute 59 :second 59)))) `(deadline :to ,to)))) - ;; NOTE: Does this normalizer cause the preamble to not be used? (Adding one to the deadline-warning definition to be sure.) + ;; NOTE: Does this normalizer cause the preamble to not be used? + ;; (Adding one to the deadline-warning definition to be sure.) :preambles ((`(,predicate-names . ,rest) (list :query query :regexp (pcase-exhaustive (org-ql--plist-get* rest :with-time) @@ -1959,8 +1941,8 @@ parseable by `parse-time-string' which may omit the time value." (org-ql-defpred deadline-warning (&key from to) ;; TODO: Should this also accept a WITH-TIME argument? - ;; TODO: Should this use the new org-ql-regexps? - "Internal selector used to handle `org-deadline-warning-days' and deadlines with warning periods." + ;; MAYBE: Use the new org-ql-regexps? + "Internal predicate used to handle `org-deadline-warning-days' and deadlines with warning periods." :preambles ((`(,predicate-names . ,_) (list :regexp org-deadline-time-regexp :query query))) :body @@ -1988,23 +1970,8 @@ parseable by `parse-time-string' which may omit the time value." ('week (ts<= (->> ts (ts-adjust 'day (* -7 warning-value))) org-ql--today))))))) (org-ql-defpred planning (&key from to _on regexp _with-time) - ;; The underscore before `on' prevents "unused lexical variable" - ;; warnings, because we pre-process that argument in a macro before - ;; this function is called. - "Return non-nil if current entry has planning timestamp in given period (i.e. its deadline, scheduled, or closed timestamp). -If no arguments are specified, return non-nil if entry has any -timestamp. - -If FROM, return non-nil if entry has a timestamp on or after -FROM. - -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. - -FROM, TO, and ON should be either `ts' structs, or strings -parseable by `parse-time-string' which may omit the time value." - ;; FIXME: Update docstring. + "Return non-nil if current entry has planning timestamp in given period. +Without arguments, return non-nil if entry has any planning timestamp." :normalizers ((`(,predicate-names ,(and num-days (pred numberp))) (let ((to (->> (ts-now) (ts-adjust 'day num-days) @@ -2016,30 +1983,15 @@ parseable by `parse-time-string' which may omit the time value." ('t org-ql-regexp-planning-with-time) ('nil org-ql-regexp-planning-without-time) ('not-found org-ql-regexp-planning))))) - ;; NOTE: The argument `regexp' is provided by pre-processing done by `org-ql--query-predicate'. - ;; MAYBE: Should the regexp be done in the normalizer instead? (If so, also in other ts-related predicates.) + ;; MAYBE: Should the regexp be done in the normalizer instead? (If + ;; so, also in other ts-related predicates.) :body (org-ql--predicate-ts :from from :to to :regexp regexp :match-group 1 :limit (line-end-position 2))) (org-ql-defpred scheduled (&key from to _on regexp _with-time) - ;; The underscore before `on' prevents "unused lexical variable" - ;; warnings, because we pre-process that argument in a macro before - ;; this function is called. "Return non-nil if current entry is scheduled in given period. -If no arguments are specified, return non-nil if entry has any -timestamp. - -If FROM, return non-nil if entry has a timestamp on or after -FROM. - -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. - -FROM, TO, and ON should be either `ts' structs, or strings -parseable by `parse-time-string' which may omit the time value." - ;; FIXME: Update docstring. +Without arguments, return non-nil if entry is scheduled." :normalizers ((`(,predicate-names ,(and num-days (pred numberp))) (let ((to (->> (ts-now) (ts-adjust 'day num-days) @@ -2058,24 +2010,8 @@ parseable by `parse-time-string' which may omit the time value." (org-ql-defpred (ts ts-active ts-a ts-inactive ts-i) (&key from to _on regexp _with-time (match-group 0) (limit (org-entry-end-position))) - ;; NOTE: Arguments to this predicate are pre-processed in `org-ql--normalize-query'. - ;; The underscore before `on' prevents "unused lexical variable" warnings due to the - ;; pre-processing converting that argument to FROM and TO. The `regexp' argument is - ;; also provided by the pre-processing and is not to be given by the user. FROM and - ;; TO are actually expected to be `ts' structs. The docstring is written for users. "Return non-nil if current entry has a timestamp in given period. -If no arguments are specified, return non-nil if entry has any -timestamp. - -If FROM, return non-nil if entry has a timestamp on or after -FROM. - -If TO, return non-nil if entry has a timestamp on or before TO. - -If ON, return non-nil if entry has a timestamp on date ON. - -FROM, TO, and ON should be either `ts' structs, or strings -parseable by `parse-time-string' which may omit the time value. +Without arguments, return non-nil if entry has a timestamp. TYPE may be `active' to match active timestamps, `inactive' to match inactive ones, or `both' / nil to match both types. @@ -2083,35 +2019,39 @@ match inactive ones, or `both' / nil to match both types. LIMIT bounds the search for the timestamp REGEXP. It defaults to the end of the entry, i.e. the position returned by `org-entry-end-position', but for certain searches it should be -bound to a different positiion, e.g. for planning lines, the end -of the line after the heading." - ;; FIXME: Update docstring (e.g. mention MATCH-GROUP). +bound to a different positiion (e.g. for planning lines, the end +of the line after the heading). MATCH-GROUP should be the number +of REGEXP's group that matches the Org timestamp (i.e. excluding +any planning prefix); it defaults to 0 (i.e. the whole regexp)." ;; MAYBE: Define active/inactive ones separately? - :normalizers ((`(,(or 'ts-active 'ts-a) . ,rest) `(ts :type active ,@rest)) - (`(,(or 'ts-inactive 'ts-i) . ,rest) `(ts :type inactive ,@rest))) - :preambles ((`(,predicate-names . ,rest) - (list :regexp (pcase (plist-get rest :type) - ((or 'nil 'both) (pcase-exhaustive (org-ql--plist-get* rest :with-time) - ('t org-ql-regexp-ts-both-with-time) - ('nil org-ql-regexp-ts-both-without-time) - ('not-found org-ql-regexp-ts-both))) - ('active (pcase-exhaustive (org-ql--plist-get* rest :with-time) - ('t org-ql-regexp-ts-active-with-time) - ('nil org-ql-regexp-ts-active-without-time) - ('not-found org-ql-regexp-ts-active))) - ('inactive (pcase-exhaustive (org-ql--plist-get* rest :with-time) - ('t org-ql-regexp-ts-inactive-with-time) - ('nil org-ql-regexp-ts-inactive-without-time) - ('not-found org-ql-regexp-ts-inactive)))) - ;; Predicate needs testing only when args are present. - :query (-let (((&keys :from :to :on) rest)) - ;; FIXME: This used to be (when (or from to on) query), but that doesn't seem right, so I - ;; changed it to this if, and the tests pass either way. Might deserve a little scrutiny. - (if (or from to on) - query - t))))) - ;; TODO: DRY this with the clocked predicate. - ;; NOTE: The argument `regexp' is provided by pre-processing done by `org-ql--query-predicate'. + :normalizers + ((`(,(or 'ts-active 'ts-a) . ,rest) `(ts :type active ,@rest)) + (`(,(or 'ts-inactive 'ts-i) . ,rest) `(ts :type inactive ,@rest))) + + :preambles + ((`(,predicate-names . ,rest) + (list :regexp (pcase (plist-get rest :type) + ((or 'nil 'both) (pcase-exhaustive (org-ql--plist-get* rest :with-time) + ('t org-ql-regexp-ts-both-with-time) + ('nil org-ql-regexp-ts-both-without-time) + ('not-found org-ql-regexp-ts-both))) + ('active (pcase-exhaustive (org-ql--plist-get* rest :with-time) + ('t org-ql-regexp-ts-active-with-time) + ('nil org-ql-regexp-ts-active-without-time) + ('not-found org-ql-regexp-ts-active))) + ('inactive (pcase-exhaustive (org-ql--plist-get* rest :with-time) + ('t org-ql-regexp-ts-inactive-with-time) + ('nil org-ql-regexp-ts-inactive-without-time) + ('not-found org-ql-regexp-ts-inactive)))) + ;; Predicate needs testing only when args are present. + :query (-let (((&keys :from :to :on) rest)) + ;; TODO: This used to be (when (or from to on) query), but + ;; that doesn't seem right, so I changed it to this if, and the + ;; tests pass either way. Might deserve a little scrutiny. + (if (or from to on) + query + t))))) + :body (cl-macrolet ((next-timestamp () `(when (re-search-forward regexp limit t) diff --git a/org-ql.info b/org-ql.info index bacac72..4d945e9 100644 --- a/org-ql.info +++ b/org-ql.info @@ -530,24 +530,27 @@ File: README.info, Node: Date/time predicates, Prev: Ancestor/descendant predi 4.2.4 Date/time predicates -------------------------- -All of these predicates take optional keyword arguments ‘:from’, ‘:to:’, -and ‘:on’: +These predicates take optional keyword arguments: - • If ‘:from’, return non-nil if entry has a timestamp on or after + • ‘:from’: Match entries whose timestamp is on or after timestamp ‘:from’. - • If ‘:to’, return non-nil if entry has a timestamp on or before + • ‘:to’: Match entries whose timestamp is on or before timestamp ‘:to’. - • If ‘:on’, return non-nil if entry has a timestamp on date ‘:on’. + • ‘:on’: Match entries whose timestamp is on date ‘:on’. + • ‘:with-time’: If unspecified, match timestamps with or without + times (i.e. HH:MM). If nil, match timestamps without times. If t, + match timestamps with times. - Argument values should be either a number of days (positive to look -forward, or negative to look backward), a ‘ts’ struct, or a string -parseable by ‘parse-time-string’ (the string may omit the time value). + Timestamp/date arguments should be either a number of days (positive +to look forward, or negative to look backward), a string parseable by +‘parse-time-string’ (the string may omit the time value), or a ‘ts’ +struct. • *Predicates* ‘ts’ Return non-nil if current entry has a timestamp in given - period. If no arguments are specified, return non-nil if - entry has any timestamp. + period. Without arguments, return non-nil if entry has a + timestamp. ‘ts-active, ts-a’ Like ts, but only matches active timestamps. ‘ts-inactive, ts-i’ @@ -560,30 +563,28 @@ number of days. The number can be negative to invert the direction. • *Backward-looking* ‘clocked’ Return non-nil if current entry was clocked in given period. - If no arguments are specified, return non-nil if entry was - clocked at any time. Note: Clock entries are expected to be - clocked out. Currently clocked entries (i.e. with unclosed - timestamp ranges) are ignored. + Without arguments, return non-nil if entry was ever clocked. + Note: Clock entries are expected to be clocked out. Currently + clocked entries (i.e. with unclosed timestamp ranges) are + ignored. ‘closed’ Return non-nil if current entry was closed in given period. - If no arguments are specified, return non-nil if entry was - closed at any time. + Without arguments, return non-nil if entry is closed. • *Forward-looking* ‘deadline’ Return non-nil if current entry has deadline in given period. If argument is auto, return non-nil if entry has deadline - within org-deadline-warning-days. If no arguments are - specified, return non-nil if entry has any deadline. + within org-deadline-warning-days. Without arguments, return + non-nil if entry has any deadline. ‘planning’ - Return non-nil if current entry has planning timestamp in - given period (i.e. its deadline, scheduled, or closed - timestamp). If no arguments are specified, return non-nil if - entry is scheduled at any time. + Return non-nil if current entry has planning timestamp (i.e. + its deadline, scheduled, or closed timestamp) in given period. + Without arguments, return non-nil if entry has any planning + timestamp. ‘scheduled’ Return non-nil if current entry is scheduled in given period. - If no arguments are specified, return non-nil if entry is - scheduled at any time. + Without arguments, return non-nil if entry is scheduled.  File: README.info, Node: Functions / Macros, Next: Dynamic block, Prev: Queries, Up: Usage @@ -981,6 +982,9 @@ File: README.info, Node: 06-pre, Next: 052, Up: Changelog • Predicate ‘effort’. • Predicate ‘heading-regexp’, which matches regular expressions against heading text (alias: ‘h*’). + • Timestamp-related predicates now accept an optional ‘:with-time’ + argument, which allows matching timestamps with or without times + (i.e. HH:MM). *Changed* • Helm support (including the command helm-org-ql) has been moved to @@ -1534,40 +1538,40 @@ Node: Non-sexp query syntax9485 Node: General predicates11209 Node: Ancestor/descendant predicates17430 Node: Date/time predicates18558 -Node: Functions / Macros21213 -Node: Agenda-like views21511 -Node: Listing / acting-on results22916 -Node: Custom predicates28538 -Node: Dynamic block32029 -Node: Links34727 -Node: Tips35414 -Node: Changelog35732 -Node: 06-pre36458 -Node: 05237865 -Node: 05138169 -Node: 0538586 -Node: 04940060 -Node: 04840334 -Node: 04740681 -Node: 04641076 -Node: 04541476 -Node: 04441835 -Node: 04342194 -Node: 04242391 -Node: 04142552 -Node: 0442793 -Node: 03246726 -Node: 03147105 -Node: 0347302 -Node: 02350277 -Node: 02250505 -Node: 02150773 -Node: 0250972 -Node: 0155007 -Node: Notes55108 -Node: Comparison with Org Agenda searches55270 -Node: org-sidebar56142 -Node: License56421 +Node: Functions / Macros21220 +Node: Agenda-like views21518 +Node: Listing / acting-on results22923 +Node: Custom predicates28545 +Node: Dynamic block32036 +Node: Links34734 +Node: Tips35421 +Node: Changelog35739 +Node: 06-pre36465 +Node: 05238038 +Node: 05138342 +Node: 0538759 +Node: 04940233 +Node: 04840507 +Node: 04740854 +Node: 04641249 +Node: 04541649 +Node: 04442008 +Node: 04342367 +Node: 04242564 +Node: 04142725 +Node: 0442966 +Node: 03246899 +Node: 03147278 +Node: 0347475 +Node: 02350450 +Node: 02250678 +Node: 02150946 +Node: 0251145 +Node: 0155180 +Node: Notes55281 +Node: Comparison with Org Agenda searches55443 +Node: org-sidebar56315 +Node: License56594  End Tag Table