Fix: (link) Allow brackets in description

Org 9.3 stopped replacing brackets in link descriptions with braces
and started escaping them instead.

Fixes #283.  Thanks to Daniel Borchmann (@exot) for reporting.
This commit is contained in:
Adam Porter 2023-03-10 05:52:06 -06:00
parent 3c73888b98
commit 9e14f9eefa
5 changed files with 115 additions and 68 deletions

View file

@ -560,6 +560,7 @@ Simple links may also be written manually in either sexp or non-sexp form, like:
+ Command ~org-ql-sparse-tree~ accepts both string and sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]].) + Command ~org-ql-sparse-tree~ accepts both string and sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]].)
*Fixed* *Fixed*
+ Predicate ~link~ matches links whose descriptions contain escaped brackets (changed in Org 9.3). (Thanks to [[https://github.com/exot][Daniel Borchmann]] for reporting.)
+ Predicate ~src~'s matching of begin/end block lines, normalization of arguments, and handling in non-sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]] for reporting.) + Predicate ~src~'s matching of begin/end block lines, normalization of arguments, and handling in non-sexp queries. (Thanks to [[https://github.com/akirak][Akira Komamura]] for reporting.)
+ Predicate ~src~'s behavior with various arguments. + Predicate ~src~'s behavior with various arguments.
+ Various compilation warnings. + Various compilation warnings.

View file

@ -794,28 +794,33 @@ DESCRIPTION-OR-TARGET, match it in either description or target.
If DESCRIPTION, match it in the description. If TARGET, match it If DESCRIPTION, match it in the description. If TARGET, match it
in the target. If both DESCRIPTION and TARGET, match both, in the target. If both DESCRIPTION and TARGET, match both,
respectively." respectively."
;; This `rx' part is borrowed from `org-make-link-regexps'. It matches the interior of an
;; Org link target (i.e. the parts between the brackets, including any escaped brackets).
(let ((link-target-part '(0+ (or (not (any "[]\\"))
(and "\\" (0+ "\\\\") (any "[]"))
(and (1+ "\\") (not (any "[]")))))))
(cl-labels (cl-labels
((no-desc ((no-desc
(match) (rx-to-string `(seq (or bol (1+ blank)) (match) (rx-to-string `(seq (or bol (1+ blank))
"[[" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]"))) "[[" ,link-target-part (regexp ,match) ,link-target-part
"]]"))) "]]")))
(match-both (match-both
(description target) (description target)
(rx-to-string `(seq (or bol (1+ blank)) (rx-to-string `(seq (or bol (1+ blank))
"[[" (0+ (not (any "]"))) (regexp ,target) (0+ (not (any "]"))) "[[" ,link-target-part (regexp ,target) ,link-target-part
"][" (0+ (not (any "]"))) (regexp ,description) (0+ (not (any "]"))) "][" (*? anything) (regexp ,description) (*? anything)
"]]"))) "]]")))
;; Note that these actually allow empty descriptions ;; Note that these actually allow empty descriptions
;; or targets, depending on what they are matching. ;; or targets, depending on what they are matching.
(match-desc (match-desc
(match) (rx-to-string `(seq (or bol (1+ blank)) (match) (rx-to-string `(seq (or bol (1+ blank))
"[[" (0+ (not (any "]"))) "[[" ,link-target-part
"][" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]"))) "][" (*? anything) (regexp ,match) (*? anything)
"]]"))) "]]")))
(match-target (match-target
(match) (rx-to-string `(seq (or bol (1+ blank)) (match) (rx-to-string `(seq (or bol (1+ blank))
"[[" (0+ (not (any "]"))) (regexp ,match) (0+ (not (any "]"))) "[[" ,link-target-part (regexp ,match) ,link-target-part
"][" (0+ (not (any "]"))) "][" (*? anything)
"]]")))) "]]"))))
(cond (description-or-target (cond (description-or-target
(rx-to-string `(or (regexp ,(no-desc description-or-target)) (rx-to-string `(or (regexp ,(no-desc description-or-target))
@ -825,7 +830,7 @@ respectively."
(match-both description target)) (match-both description target))
(description (match-desc description)) (description (match-desc description))
(target (rx-to-string `(or (regexp ,(no-desc target)) (target (rx-to-string `(or (regexp ,(no-desc target))
(regexp ,(match-target target)))))))) (regexp ,(match-target target)))))))))
(defun org-ql--format-src-block-regexp (&optional lang) (defun org-ql--format-src-block-regexp (&optional lang)
"Return regexp equivalent to `org-babel-src-block-regexp' with LANG filled in." "Return regexp equivalent to `org-babel-src-block-regexp' with LANG filled in."
@ -1563,12 +1568,8 @@ any link is found."
;; enabled nearly all of the time, in which case this function won't be called anyway, it's ;; enabled nearly all of the time, in which case this function won't be called anyway, it's
;; probably not worth rewriting code all over the place to fix this. ;; probably not worth rewriting code all over the place to fix this.
:preambles ((`(,predicate-names) :preambles ((`(,predicate-names)
(list :regexp ;; Match a link with a target and optionally a description. ;; Match a link with a target and optionally a description.
(rx (or bol (1+ blank)) (list :regexp (org-ql--link-regexp :target ".*")))
"[[" (1+ (not (any "]"))) "]"
(optional (seq "[" (0+ (not (any "]"))) "]"))
"]"
(or eol blank))))
(`(,predicate-names ,(and description-or-target (`(,predicate-names ,(and description-or-target
(guard (not (keywordp description-or-target)))) (guard (not (keywordp description-or-target))))
. ,plist) . ,plist)

View file

@ -1055,6 +1055,9 @@ File: README.info, Node: 07-pre, Next: 063, Up: Changelog
(Thanks to Akira Komamura (https://github.com/akirak).) (Thanks to Akira Komamura (https://github.com/akirak).)
*Fixed* *Fixed*
• Predicate link matches links whose descriptions contain escaped
brackets (changed in Org 9.3). (Thanks to Daniel Borchmann
(https://github.com/exot) for reporting.)
• Predicate srcs matching of begin/end block lines, normalization • Predicate srcs matching of begin/end block lines, normalization
of arguments, and handling in non-sexp queries. (Thanks to Akira of arguments, and handling in non-sexp queries. (Thanks to Akira
Komamura (https://github.com/akirak) for reporting.) Komamura (https://github.com/akirak) for reporting.)
@ -1735,35 +1738,35 @@ Node: Links37255
Node: Tips37942 Node: Tips37942
Node: Changelog38266 Node: Changelog38266
Node: 07-pre39049 Node: 07-pre39049
Node: 06341784 Node: 06341973
Node: 06242319 Node: 06242508
Node: 06142624 Node: 06142813
Node: 0643192 Node: 0643381
Node: 05246246 Node: 05246435
Node: 05146546 Node: 05146735
Node: 0546969 Node: 0547158
Node: 04948498 Node: 04948687
Node: 04848778 Node: 04848967
Node: 04749127 Node: 04749316
Node: 04649536 Node: 04649725
Node: 04549944 Node: 04550133
Node: 04450305 Node: 04450494
Node: 04350664 Node: 04350853
Node: 04250867 Node: 04251056
Node: 04151028 Node: 04151217
Node: 0451275 Node: 0451464
Node: 03255376 Node: 03255565
Node: 03155779 Node: 03155968
Node: 0355976 Node: 0356165
Node: 02359276 Node: 02359465
Node: 02259510 Node: 02259699
Node: 02159790 Node: 02159979
Node: 0259995 Node: 0260184
Node: 0164073 Node: 0164262
Node: Notes64174 Node: Notes64363
Node: Comparison with Org Agenda searches64336 Node: Comparison with Org Agenda searches64525
Node: org-sidebar65225 Node: org-sidebar65414
Node: License65504 Node: License65693
 
End Tag Table End Tag Table

10
tests/data-links.org Normal file
View file

@ -0,0 +1,10 @@
* Alpha
Let us link to: [[id:74d357ac-fb9c-40d1-a63f-eca8a227321d][Bravo [a phrase in brackets]]].
* Bravo [a phrase in brackets]
:PROPERTIES:
:ID: 74d357ac-fb9c-40d1-a63f-eca8a227321d
:END:
* Charlie

View file

@ -1141,7 +1141,39 @@ with keyword arg NOW in PLIST."
'("/r/emacs"))) '("/r/emacs")))
(org-ql-it "with :description and :target regexp" (org-ql-it "with :description and :target regexp"
(org-ql-expect ('(link :description "em.cs" :target "em.cs" :regexp-p t)) (org-ql-expect ('(link :description "em.cs" :target "em.cs" :regexp-p t))
'("/r/emacs")))) '("/r/emacs")))
(describe "matches links whose descriptions contain brackets"
(before-each
(setq org-ql-test-buffer (org-ql-test-data-buffer "data-links.org")))
(org-ql-it "without arguments"
(org-ql-expect ('(link))
'("Alpha")))
(org-ql-it "with description-or-target"
(org-ql-expect ('(link "phrase"))
'("Alpha")))
(org-ql-it "with :description"
(org-ql-expect ('(link :description "phrase"))
'("Alpha")))
(org-ql-it "with :target"
(org-ql-expect ('(link :target "id:"))
'("Alpha")))
(org-ql-it "with :description and :target"
(org-ql-expect ('(link :description "phrase" :target "id"))
'("Alpha")))
(org-ql-it "with description-or-target regexp"
(org-ql-expect ('(link "id:.*" :regexp-p t))
'("Alpha")))
(org-ql-it "with :description regexp"
(org-ql-expect ('(link :description "phr.se" :regexp-p t))
'("Alpha")))
(org-ql-it "with :target regexp"
(org-ql-expect ('(link :target "id:.*" :regexp-p t))
'("Alpha")))
(org-ql-it "with :description and :target regexp"
(org-ql-expect ('(link :description "phr.se" :target "id:.*" :regexp-p t))
'("Alpha")))))
(describe "(outline-path)" (describe "(outline-path)"
(org-ql-it "with one argument" (org-ql-it "with one argument"