org-make-tags-matcher: Re-add quoting of property names

* lisp/org.el (org-make-tags-matcher):
* testing/lisp/test-org.el (test-org/map-entries): Move special cased
handling of LEVEL properties.  Add tests for other special cased
properties TODO and CATEGORY.

* lisp/org.el (org-make-tags-matcher):
* doc/org-manual.org (Matching tags and properties):
* testing/lisp/test-org.el (test-org/map-entries): Re-add and extend
quoting of property names in search strings.

Link: https://orgmode.org/list/87h6oq2nu1.fsf@gmail.com
This commit is contained in:
Jens Schmidt 2023-08-24 22:38:02 +02:00 committed by Ihor Radchenko
parent dbf415b840
commit 234650af2e
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
3 changed files with 68 additions and 43 deletions

View File

@ -9320,21 +9320,21 @@ With the regular =<= operator, the search would handle entries without
an =EFFORT= property as having a zero effort and would include them in
the result as well.
Currently, you can use only property names including alphanumeric
characters, underscores, and minus characters in search strings. In
addition, if you want to search for a property whose name starts with
a minus character, you have to "quote" that leading minus character
with an explicit positive selection plus character, like this:
You can use all characters valid in property names when matching
properties. However, you have to quote some characters in property
names with backslashes when using them in search strings, namely all
characters different from alphanumerics and underscores[fn:: If you
quote alphanumeric characters or underscores with a backslash, that
backslash is ignored.]. For example, to search for all entries having
a property =boss-prio=, =boss:prio=, or =boss\prio=, respectively,
with value =C=, use search strings
#+begin_example
+-long-and-twisted-property-name-="foo"
boss\-prio="C"
boss\:prio="C"
boss\\prio="C"
#+end_example
#+texinfo: @noindent
Without that extra plus character, the minus character would be taken
to indicate a negative selection on search term
=long-and-twisted-property-name-="foo"=.
You can configure Org mode to use property inheritance during
a search, but beware that this can slow down searches considerably.
See [[*Property Inheritance]], for details.

View File

@ -11328,15 +11328,14 @@ See also `org-scan-tags'."
"\\(?2:"
;; tag regexp match
"{[^}]+}\\|"
;; LEVEL property match. For sake of consistency,
;; recognize starred operators here as well. We do
;; not need to process them below, however, since
;; the LEVEL property is always present.
"LEVEL\\(?3:" opre "\\)\\*?\\(?4:[0-9]+\\)\\|"
;; regular property match
;; property match. Try to keep this subre generic
;; and rather handle special properties like LEVEL
;; and CATEGORY further below. This ensures that
;; the same quoting mechanics can be used for all
;; property names.
"\\(?:"
;; property name [1]
"\\(?5:[[:alnum:]_-]+\\)"
"\\(?5:\\(?:[[:alnum:]_]+\\|\\\\[^[:space:]]\\)+\\)"
;; operator, optionally starred
"\\(?6:" opre "\\)\\(?7:\\*\\)?"
;; operand (regexp, double-quoted string,
@ -11353,13 +11352,19 @@ See also `org-scan-tags'."
(start 0)
tagsmatch todomatch tagsmatcher todomatcher)
;; [1] The minus characters in property names do *not* conflict
;; with the exclusion operator above, since the mandatory
;; following operator distinguishes these both cases.
;; Accordingly, minus characters do not need any special quoting,
;; even if https://orgmode.org/list/87jzv67k3p.fsf@localhost and
;; commit 19b0e03f32c6032a60150fc6cb07c6f766cb3f6c suggest
;; otherwise.
;; [1] The history of this particular subre:
;; - \\([[:alnum:]_]+\\) [pre-19b0e03]
;; Does not allow for minus characters in property names.
;; - "\\(\\(?:[[:alnum:]_]+\\(?:\\\\-\\)*\\)+\\)" [19b0e03]
;; Incomplete fix of above issue, still resulting in, e.g.,
;; https://orgmode.org/list/87jzv67k3p.fsf@localhost.
;; - "\\(?5:[[:alnum:]_-]+\\)" [f689eb4]
;; Allows for unquoted minus characters in property names, but
;; conflicts with searches like -TAG-PROP="VALUE". See
;; https://orgmode.org/list/87h6oq2nu1.fsf@gmail.com.
;; - current subre
;; Like second solution, but with proper unquoting and allowing
;; for all possible characters in property names to be quoted.
;; Expand group tags.
(setq match (org-tags-expand match))
@ -11404,22 +11409,28 @@ See also `org-scan-tags'."
;; exact tag match in [3].
(tag (match-string 2 term))
(regexp (eq (string-to-char tag) ?{))
(levelp (match-end 4))
(propp (match-end 5))
(mm
(cond
(regexp ; [2]
`(with-syntax-table org-mode-tags-syntax-table
(org-match-any-p ,(substring tag 1 -1) tags-list)))
(levelp
`(,(org-op-to-function (match-string 3 term))
level
,(string-to-number (match-string 4 term))))
(propp
(let* (;; Convert property name to an Elisp
(let* (;; Determine property name.
(pn (upcase
(save-match-data
(replace-regexp-in-string
"\\\\\\(.\\)" "\\1"
(match-string 5 term)
t nil))))
;; Convert property name to an Elisp
;; accessor for that property (aka. as
;; getter value).
(gv (pcase (upcase (match-string 5 term))
;; getter value). Symbols LEVEL and TODO
;; referenced below get bound by the
;; matcher that this function returns.
(gv (pcase pn
("LEVEL"
'(number-to-string level))
("CATEGORY"
'(org-get-category (point)))
("TODO" 'todo)

View File

@ -2862,11 +2862,24 @@ test <point>
(equal '(11)
(org-test-with-temp-text "* Level 1\n** Level 2"
(let (org-odd-levels-only) (org-map-entries #'point "LEVEL>1")))))
;; Level match with (ignored) starred operator.
;; Category match.
(should
(equal '(11)
(org-test-with-temp-text "* Level 1\n** Level 2"
(let (org-odd-levels-only) (org-map-entries #'point "LEVEL>*1")))))
(equal '(59)
(org-test-with-temp-text "
#+CATEGORY: foo
* H1
:PROPERTIES:
:CATEGORY: bar
:END:
* H2"
(org-map-entries #'point "CATEGORY=\"foo\""))))
;; Todo match.
(should
(equal '(6)
(org-test-with-temp-text "* H1\n* TODO H2\n* DONE H3"
(org-map-entries #'point "TODO=\"TODO\""))))
;; Tag match.
(should
(equal '(11)
@ -2948,7 +2961,7 @@ SCHEDULED: <2014-03-04 tue.>"
:END:
* H3"
(org-map-entries #'point "TEST!=*1"))))
;; Property matches on names including minus characters.
;; Property matches on names containing quoted characters.
(org-test-with-temp-text
"
* H1 :BAR:
@ -2967,11 +2980,12 @@ SCHEDULED: <2014-03-04 tue.>"
:PROPERTIES:
:-FOO: 2
:END:
* H5"
(should (equal '(2) (org-map-entries #'point "TEST-FOO!=*0-FOO")))
(should (equal '(2) (org-map-entries #'point "-FOO+TEST-FOO!=*0")))
(should (equal '(88) (org-map-entries #'point "+-FOO!=*0-FOO")))
(should (equal '(88) (org-map-entries #'point "-FOO+-FOO!=*0"))))
* H5 :TEST:"
(should (equal '(2) (org-map-entries #'point "TEST\\-FOO!=*0-FOO")))
(should (equal '(2) (org-map-entries #'point "-FOO+TEST\\-FOO!=*0")))
(should (equal '(88) (org-map-entries #'point "\\-FOO!=*0-FOO")))
(should (equal '(88) (org-map-entries #'point "-FOO+\\-FOO!=*0")))
(should (equal '(88) (org-map-entries #'point "-TEST-FOO-TEST\\-FOO=1"))))
;; Multiple criteria.
(should
(equal '(23)