Fix: Planning-related predicates searched too far into entries

Planning-line-related predicates searched entire entries, which could
find lines that looked like planning lines but were not.  For example, in an
entry talking about tiny.el, in a source code block, in Elisp comments
that had text resembling an Org planning line, that text would be
found by the regexp search, and the predicate would then attempt to
parse the match, which could fail.

Now the regexp search for planning-line-related predicates is bound by
the end of the line after the heading, which is the only place that
actual Org planning lines are supposed to be.
This commit is contained in:
Adam Porter 2019-08-30 05:23:39 -05:00
parent d8d2455a2c
commit e839397579
2 changed files with 25 additions and 13 deletions

View file

@ -476,6 +476,7 @@ Expands into a call to ~org-ql-select~ with the same arguments. For convenience
+ Don't search buffers without headings, and show a message if the user attempts it. + Don't search buffers without headings, and show a message if the user attempts it.
+ Don't search hidden/special buffers. + Don't search hidden/special buffers.
+ Properly accept arbitrary sort functions in =org-ql-select=, etc. (Fixes [[https://github.com/alphapapa/org-ql/issues/37][#37]]. Thanks to [[https://github.com/mz-pdm][Milan Zamazal]].) + Properly accept arbitrary sort functions in =org-ql-select=, etc. (Fixes [[https://github.com/alphapapa/org-ql/issues/37][#37]]. Thanks to [[https://github.com/mz-pdm][Milan Zamazal]].)
+ Planning-line-related predicates searched too far into entries.
*Compatibility* *Compatibility*
+ Fixes for compatibility with Org 9.2. (Thanks to [[https://github.com/ataias][Ataias Pereira Reis]] and [[https://github.com/dakra][Daniel Kraus]].) + Fixes for compatibility with Org 9.2. (Thanks to [[https://github.com/ataias][Ataias Pereira Reis]] and [[https://github.com/dakra][Daniel Kraus]].)

View file

@ -844,7 +844,8 @@ If ON, return non-nil if entry has a timestamp on date ON.
FROM, TO, and ON should be either `ts' structs, or strings FROM, TO, and ON should be either `ts' structs, or strings
parseable by `parse-time-string' which may omit the time value." parseable by `parse-time-string' which may omit the time value."
(org-ql--predicate-ts :from from :to to :regexp org-closed-time-regexp :match-group 1)) (org-ql--predicate-ts :from from :to to :regexp org-closed-time-regexp :match-group 1
:limit (line-end-position 2)))
(org-ql--defpred deadline (&key from to _on) (org-ql--defpred deadline (&key from to _on)
;; The underscore before `on' prevents "unused lexical variable" ;; The underscore before `on' prevents "unused lexical variable"
@ -863,10 +864,13 @@ If ON, return non-nil if entry has a timestamp on date ON.
FROM, TO, and ON should be either `ts' structs, or strings FROM, TO, and ON should be either `ts' structs, or strings
parseable by `parse-time-string' which may omit the time value." parseable by `parse-time-string' which may omit the time value."
(org-ql--predicate-ts :from from :to to :regexp org-deadline-time-regexp :match-group 1)) (org-ql--predicate-ts :from from :to to :regexp org-deadline-time-regexp :match-group 1
:limit (line-end-position 2)))
(org-ql--defpred deadline-warning (&key from to) (org-ql--defpred deadline-warning (&key from to)
"Internal selector used to handle `org-deadline-warning-days' and deadlines with warning periods." "Internal selector used to handle `org-deadline-warning-days' and deadlines with warning periods.
Should be called on a planning line, because it does not search
past the end of the current line."
(save-excursion (save-excursion
(forward-line 1) (forward-line 1)
(when (re-search-forward org-deadline-time-regexp (line-end-position) t) (when (re-search-forward org-deadline-time-regexp (line-end-position) t)
@ -906,7 +910,8 @@ If ON, return non-nil if entry has a timestamp on date ON.
FROM, TO, and ON should be either `ts' structs, or strings FROM, TO, and ON should be either `ts' structs, or strings
parseable by `parse-time-string' which may omit the time value." parseable by `parse-time-string' which may omit the time value."
(org-ql--predicate-ts :from from :to to :regexp org-ql-planning-regexp :match-group 1)) (org-ql--predicate-ts :from from :to to :regexp org-ql-planning-regexp :match-group 1
:limit (line-end-position 2)))
(org-ql--defpred scheduled (&key from to _on) (org-ql--defpred scheduled (&key from to _on)
;; The underscore before `on' prevents "unused lexical variable" ;; The underscore before `on' prevents "unused lexical variable"
@ -925,9 +930,10 @@ If ON, return non-nil if entry has a timestamp on date ON.
FROM, TO, and ON should be either `ts' structs, or strings FROM, TO, and ON should be either `ts' structs, or strings
parseable by `parse-time-string' which may omit the time value." parseable by `parse-time-string' which may omit the time value."
(org-ql--predicate-ts :from from :to to :regexp org-scheduled-time-regexp :match-group 1)) (org-ql--predicate-ts :from from :to to :regexp org-scheduled-time-regexp :match-group 1
:limit (line-end-position 2)))
(org-ql--defpred ts (&key from to _on regexp (match-group 0)) (org-ql--defpred ts (&key from to _on regexp (match-group 0) (limit (org-entry-end-position)))
;; The underscore before `on' prevents "unused lexical variable" warnings, ;; The underscore before `on' prevents "unused lexical variable" warnings,
;; because we pre-process that argument in a macro before this function is ;; because we pre-process that argument in a macro before this function is
;; called. The `regexp' argument is also provided by the macro and is not ;; called. The `regexp' argument is also provided by the macro and is not
@ -947,24 +953,29 @@ FROM, TO, and ON should be either `ts' structs, or strings
parseable by `parse-time-string' which may omit the time value. parseable by `parse-time-string' which may omit the time value.
TYPE may be `active' to match active timestamps, `inactive' to TYPE may be `active' to match active timestamps, `inactive' to
match inactive ones, or `both' / nil to match both types." 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."
;; TODO: DRY this with the clocked predicate. ;; TODO: DRY this with the clocked predicate.
;; NOTE: FROM and TO are actually expected to be `ts' structs. The docstring is written ;; NOTE: FROM and TO are actually expected to be `ts' structs. The docstring is written
;; for end users, for which the arguments are pre-processed by `org-ql-select'. ;; for end users, for which the arguments are pre-processed by `org-ql-select'.
;; FIXME: This assumes every "clocked" entry is a range. Unclosed clock entries are not handled. ;; FIXME: This assumes every "clocked" entry is a range. Unclosed clock entries are not handled.
(cl-macrolet ((next-timestamp () (cl-macrolet ((next-timestamp ()
`(when (re-search-forward regexp end-pos t) `(when (re-search-forward regexp limit t)
(ts-parse-org (match-string match-group)))) (ts-parse-org (match-string match-group))))
(test-timestamps (pred-form) (test-timestamps (pred-form)
`(cl-loop for next-ts = (next-timestamp) `(cl-loop for next-ts = (next-timestamp)
while next-ts while next-ts
thereis ,pred-form))) thereis ,pred-form)))
(save-excursion (save-excursion
(let ((end-pos (org-entry-end-position))) (cond ((not (or from to)) (re-search-forward regexp limit t))
(cond ((not (or from to)) (re-search-forward regexp end-pos t)) ((and from to) (test-timestamps (ts-in from to next-ts)))
((and from to) (test-timestamps (ts-in from to next-ts))) (from (test-timestamps (ts<= from next-ts)))
(from (test-timestamps (ts<= from next-ts))) (to (test-timestamps (ts<= next-ts to)))))))
(to (test-timestamps (ts<= next-ts to))))))))
;;;;; Sorting ;;;;; Sorting