org-export: Correctly resolve fuzzy links whose path starts with *

* contrib/lisp/org-export.el (org-export-resolve-fuzzy-link):
  Correctly resolve fuzzy links whose path starts with *
* testing/lisp/test-org-export.el: Add tests.
This commit is contained in:
Nicolas Goaziou 2012-06-07 00:06:19 +02:00
parent ad235400a6
commit 451191bc41
2 changed files with 146 additions and 89 deletions

View File

@ -2949,18 +2949,19 @@ Return value can be an object, an element, or nil:
- Otherwise, return nil.
Assume LINK type is \"fuzzy\"."
(let ((path (org-element-property :path link)))
(let* ((path (org-element-property :path link))
(match-title-p (eq (aref path 0) ?*)))
(cond
;; First try to find a matching "<<path>>" unless user specified
;; he was looking for an headline (path starts with a *
;; character).
((and (not (eq (substring path 0 1) ?*))
((and (not match-title-p)
(loop for target in (plist-get info :target-list)
when (string= (org-element-property :value target) path)
return target)))
;; Then try to find an element with a matching "#+NAME: path"
;; affiliated keyword.
((and (not (eq (substring path 0 1) ?*))
((and (not match-title-p)
(org-element-map
(plist-get info :parse-tree) org-element-all-elements
(lambda (el)
@ -2972,29 +2973,31 @@ Assume LINK type is \"fuzzy\"."
;; is found, return it, otherwise return nil.
(t
(let ((find-headline
(function
;; Return first headline whose `:raw-value' property
;; is NAME in parse tree DATA, or nil.
(lambda (name data)
(org-element-map
data 'headline
(lambda (headline)
(when (string=
(org-element-property :raw-value headline)
name)
headline))
info 'first-match)))))
;; Search among headlines sharing an ancestor with link,
;; from closest to farthest.
(or (catch 'exit
(mapc
(lambda (parent)
(when (eq (org-element-type parent) 'headline)
(let ((foundp (funcall find-headline path parent)))
(when foundp (throw 'exit foundp)))))
(org-export-get-genealogy link info)) nil)
;; No match with a common ancestor: try the full parse-tree.
(funcall find-headline path (plist-get info :parse-tree))))))))
(function
;; Return first headline whose `:raw-value' property
;; is NAME in parse tree DATA, or nil.
(lambda (name data)
(org-element-map
data 'headline
(lambda (headline)
(when (string=
(org-element-property :raw-value headline)
name)
headline))
info 'first-match)))))
;; Search among headlines sharing an ancestor with link,
;; from closest to farthest.
(or (catch 'exit
(mapc
(lambda (parent)
(when (eq (org-element-type parent) 'headline)
(let ((foundp (funcall find-headline path parent)))
(when foundp (throw 'exit foundp)))))
(org-export-get-genealogy link info)) nil)
;; No match with a common ancestor: try the full parse-tree.
(funcall find-headline
(if match-title-p (substring path 1) path)
(plist-get info :parse-tree))))))))
(defun org-export-resolve-id-link (link info)
"Return headline referenced as LINK destination.

View File

@ -478,6 +478,73 @@ Paragraph[fn:1]"
;;; Links
(ert-deftest test-org-export/fuzzy-link ()
"Test fuzzy links specifications."
;; 1. Links to invisible (keyword) targets should be ignored.
(org-test-with-parsed-data
"Paragraph.\n#+TARGET: Test\n[[Test]]"
(should-not
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info)))
;; 2. Link to an headline should return headline's number.
(org-test-with-parsed-data
"Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
(should
;; Note: Headline's number is in fact a list of numbers.
(equal '(2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 3. Link to a target in an item should return item's number.
(org-test-with-parsed-data
"- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
(should
;; Note: Item's number is in fact a list of numbers.
(equal '(1 2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 4. Link to a target in a footnote should return footnote's
;; number.
(org-test-with-parsed-data "
Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
(should
(equal '(2 3)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info))))
;; 5. Link to a named element should return sequence number of that
;; element.
(org-test-with-parsed-data
"#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
(should
(= 2
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 6. Link to a target not within an item, a table, a footnote
;; reference or definition should return section number.
(org-test-with-parsed-data
"* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
(should
(equal '(2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t)))))
(ert-deftest test-org-export/resolve-coderef ()
"Test `org-export-resolve-coderef' specifications."
(let ((org-coderef-label-format "(ref:%s)"))
@ -543,72 +610,59 @@ Another text. (ref:text)
"#+BEGIN_EXAMPLE -l \"[ref:%s]\"\nText. [ref:text]\n#+END_EXAMPLE"
(should (equal (org-export-resolve-coderef "text" info) "text")))))
(ert-deftest test-org-export/resolve-fuzzy-link ()
(ert-deftest test-org-exprot/resolve-fuzzy-link ()
"Test `org-export-resolve-fuzzy-link' specifications."
;; 1. Links to invisible (keyword) targets should be ignored.
;; 1. Match target objects.
(org-test-with-parsed-data "<<target>> [[target]]"
(should
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))
;; 2. Match target elements.
(org-test-with-parsed-data "#+TARGET: target\n[[target]]"
(should
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))
;; 3. Match named elements.
(org-test-with-parsed-data "#+NAME: target\nParagraph\n\n[[target]]"
(should
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))
;; 4. Match exact headline's name.
(org-test-with-parsed-data "* My headline\n[[My headline]]"
(should
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))
;; 5. Targets objects have priority over named elements and headline
;; titles.
(org-test-with-parsed-data
"Paragraph.\n#+TARGET: Test\n[[Test]]"
"* target\n#+NAME: target\n<<target>>\n\n[[target]]"
(should
(eq 'target
(org-element-type
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))))
;; 6. Named elements have priority over headline titles.
(org-test-with-parsed-data
"* target\n#+NAME: target\nParagraph\n\n[[target]]"
(should
(eq 'paragraph
(org-element-type
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))))
;; 7. If link's path starts with a "*", only match headline titles,
;; though.
(org-test-with-parsed-data
"* target\n#+NAME: target\n<<target>>\n\n[[*target]]"
(should
(eq 'headline
(org-element-type
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info)))))
;; 8. Return nil if no match.
(org-test-with-parsed-data "[[target]]"
(should-not
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info)))
;; 2. Link to an headline should return headline's number.
(org-test-with-parsed-data
"Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
(should
;; Note: Headline's number is in fact a list of numbers.
(equal '(2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 3. Link to a target in an item should return item's number.
(org-test-with-parsed-data
"- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
(should
;; Note: Item's number is in fact a list of numbers.
(equal '(1 2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 4. Link to a target in a footnote should return footnote's
;; number.
(org-test-with-parsed-data "
Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2] <<test>>B"
(should
(equal '(2 3)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info))))
;; 5. Link to a named element should return sequence number of that
;; element.
(org-test-with-parsed-data
"#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
(should
(= 2
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t))))
;; 6. Link to a target not within an item, a table, a footnote
;; reference or definition should return section number.
(org-test-with-parsed-data
"* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
(should
(equal '(2)
(org-element-map
tree 'link
(lambda (link)
(org-export-get-ordinal
(org-export-resolve-fuzzy-link link info) info)) info t)))))
(org-export-resolve-fuzzy-link
(org-element-map tree 'link 'identity info t) info))))
(ert-deftest test-org-export/resolve-id-link ()
"Test `org-export-resolve-id-link' specifications."