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 an =EFFORT= property as having a zero effort and would include them in
the result as well. the result as well.
Currently, you can use only property names including alphanumeric You can use all characters valid in property names when matching
characters, underscores, and minus characters in search strings. In properties. However, you have to quote some characters in property
addition, if you want to search for a property whose name starts with names with backslashes when using them in search strings, namely all
a minus character, you have to "quote" that leading minus character characters different from alphanumerics and underscores[fn:: If you
with an explicit positive selection plus character, like this: 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 #+begin_example
+-long-and-twisted-property-name-="foo" boss\-prio="C"
boss\:prio="C"
boss\\prio="C"
#+end_example #+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 You can configure Org mode to use property inheritance during
a search, but beware that this can slow down searches considerably. a search, but beware that this can slow down searches considerably.
See [[*Property Inheritance]], for details. See [[*Property Inheritance]], for details.

View File

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

View File

@ -2862,11 +2862,24 @@ test <point>
(equal '(11) (equal '(11)
(org-test-with-temp-text "* Level 1\n** Level 2" (org-test-with-temp-text "* Level 1\n** Level 2"
(let (org-odd-levels-only) (org-map-entries #'point "LEVEL>1"))))) (let (org-odd-levels-only) (org-map-entries #'point "LEVEL>1")))))
;; Level match with (ignored) starred operator. ;; Category match.
(should (should
(equal '(11) (equal '(59)
(org-test-with-temp-text "* Level 1\n** Level 2" (org-test-with-temp-text "
(let (org-odd-levels-only) (org-map-entries #'point "LEVEL>*1"))))) #+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. ;; Tag match.
(should (should
(equal '(11) (equal '(11)
@ -2948,7 +2961,7 @@ SCHEDULED: <2014-03-04 tue.>"
:END: :END:
* H3" * H3"
(org-map-entries #'point "TEST!=*1")))) (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 (org-test-with-temp-text
" "
* H1 :BAR: * H1 :BAR:
@ -2967,11 +2980,12 @@ SCHEDULED: <2014-03-04 tue.>"
:PROPERTIES: :PROPERTIES:
:-FOO: 2 :-FOO: 2
:END: :END:
* H5" * H5 :TEST:"
(should (equal '(2) (org-map-entries #'point "TEST-FOO!=*0-FOO"))) (should (equal '(2) (org-map-entries #'point "TEST\\-FOO!=*0-FOO")))
(should (equal '(2) (org-map-entries #'point "-FOO+TEST-FOO!=*0"))) (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!=*0-FOO")))
(should (equal '(88) (org-map-entries #'point "-FOO+-FOO!=*0")))) (should (equal '(88) (org-map-entries #'point "-FOO+\\-FOO!=*0")))
(should (equal '(88) (org-map-entries #'point "-TEST-FOO-TEST\\-FOO=1"))))
;; Multiple criteria. ;; Multiple criteria.
(should (should
(equal '(23) (equal '(23)