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:
parent
dbf415b840
commit
234650af2e
|
@ -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.
|
||||||
|
|
55
lisp/org.el
55
lisp/org.el
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue