[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [O] [dev] Implement "ref" link types
From: |
Nicolas Goaziou |
Subject: |
Re: [O] [dev] Implement "ref" link types |
Date: |
Mon, 27 Feb 2012 20:38:46 +0100 |
Hello,
Here is a new version of the patch built on top of master, along with
test cases.
If there is no objection, I'll push it to master in a couple of days.
I really think that's a great feature to have in Org.
Regards,
--
Nicolas Goaziou
>From 2fdde87bb7f1241f3d24dbd8ae030a300fe8f0fc Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <address@hidden>
Date: Mon, 20 Feb 2012 22:24:38 +0100
Subject: [PATCH] Implement numbered cross-references
* lisp/org.el (org-link-search): Search for #+name affiliated keywords
and invisible targets.
* contrib/lisp/org-element.el (org-element-link-parser): Remove "ref"
links relative part.
(org-element-target-parser): Move property name from `:raw-value' to
`:value'.
(org-element-recursive-objects): Remove targets from tables. Cells
are not parsed unless explicitely asked by back-end developer, too
late. A target wouldn't be noticed in time. One solution could be to
parse every table, but that's time consumming.
(org-element-object-restrictions): Target are not recursive anymore.
* contrib/lisp/org-export.el (org-export-resolve-fuzzy-link): Find
elements with a matching "#+name: path" affiliated keyword.
(org-export-get-ordinal): Make special cases for headlines, items,
footnotes definitions and references.
(org-export-resolve-ref-link): Removed function.
* EXPERIMENTAL/org-e-latex.el (org-e-latex-link): Handle
cross-reference numbers.
(org-e-latex-target): Targets have no contents.
* EXPERIMENTAL/org-e-ascii.el (org-e-ascii--describe-links): Ignore
fuzzy links in link description at the end of the section.
(org-e-ascii-link): Handle cross-reference numbers.
* testing/contrib/lisp/test-org-export.el: Add tests.
* testing/lisp/test-org.el: Add tests.
---
EXPERIMENTAL/org-e-ascii.el | 80 ++++++++----------
EXPERIMENTAL/org-e-latex.el | 50 +++++------
contrib/lisp/org-element.el | 20 ++---
contrib/lisp/org-export.el | 141 ++++++++++++++++++++-----------
lisp/org.el | 16 ++++
testing/contrib/lisp/test-org-export.el | 91 ++++++++++++++++++++
testing/lisp/test-org.el | 41 +++++++++
7 files changed, 299 insertions(+), 140 deletions(-)
diff --git a/EXPERIMENTAL/org-e-ascii.el b/EXPERIMENTAL/org-e-ascii.el
index 0eb547b..c9cca4a 100644
--- a/EXPERIMENTAL/org-e-ascii.el
+++ b/EXPERIMENTAL/org-e-ascii.el
@@ -825,28 +825,24 @@ channel."
(if (not desc) (org-element-property :raw-link link)
(org-export-secondary-string desc 'e-ascii info)))))
(cond
- ;; Coderefs, radio links and ref links are ignored.
- ((member type '("coderef" "radio" "ref")) nil)
- ;; Id, custom-id and fuzzy links (with the exception of
- ;; targets): Headlines refer to their numbering.
- ((member type '("custom-id" "fuzzy" "id"))
- (let ((destination (if (string= type "fuzzy")
- (org-export-resolve-fuzzy-link link info)
- (org-export-resolve-id-link link info))))
- (unless (eq (org-element-type destination) 'target)
- (concat
- (org-e-ascii--fill-string
- (format
- "[%s] %s"
- anchor
- (if (not destination)
- (org-e-ascii--translate "Unknown reference" info)
- (format
- (org-e-ascii--translate "See section %s" info)
- (mapconcat 'number-to-string
- (org-export-get-headline-number destination info)
- "."))))
- width info) "\n\n"))))
+ ;; Coderefs, radio links and fuzzy links are ignored.
+ ((member type '("coderef" "radio" "fuzzy")) nil)
+ ;; Id and custom-id links: Headlines refer to their numbering.
+ ((member type '("custom-id" "id"))
+ (let ((destination (org-export-resolve-id-link link info)))
+ (concat
+ (org-e-ascii--fill-string
+ (format
+ "[%s] %s"
+ anchor
+ (if (not destination)
+ (org-e-ascii--translate "Unknown reference" info)
+ (format
+ (org-e-ascii--translate "See section %s" info)
+ (mapconcat 'number-to-string
+ (org-export-get-headline-number destination info)
+ "."))))
+ width info) "\n\n")))
;; Do not add a link that cannot be resolved and doesn't have
;; any description: destination is already visible in the
;; paragraph.
@@ -1390,29 +1386,23 @@ INFO is a plist holding contextual information."
(org-element-property :path link)
(cdr (assq 'radio-target org-element-object-restrictions)))
'e-ascii info))
- ;; Ref link: If there's no description (DESC, return link's
- ;; destination sequence number among elements of same
- ;; type. Otherwise, use DESC.
- ((string= type "ref")
- (if (org-string-nw-p desc) desc
- (format "%d"
- (org-export-get-ordinal
- (org-export-resolve-ref-link link info)
- info nil nil
- (lambda (el) (or (org-element-property :caption el)
- (org-element-property :name el)))))))
;; Do not apply a special syntax on fuzzy links pointing to
;; targets.
- ((and (string= type "fuzzy")
- (let ((path (org-element-property :path link)))
- (loop for target in (plist-get info :target-list)
- thereis (string=
- (org-element-property :raw-value target)
- path))))
- (if (org-string-nw-p desc) desc raw-link))
+ ((string= type "fuzzy")
+ (let ((destination (org-export-resolve-fuzzy-link link info)))
+ ;; Ignore invisible "#+target: path".
+ (unless (eq (org-element-type destination) 'keyword)
+ (if (org-string-nw-p desc) desc
+ (when destination
+ (let ((number (org-export-get-ordinal destination info)))
+ (when number
+ (if (atom number) (number-to-string number)
+ (mapconcat 'number-to-string number ".")))))))))
(t
- (concat (format "[%s]" (if (org-string-nw-p desc) desc raw-link))
- (unless org-e-ascii-links-to-notes (format " (%s)" raw-link)))))))
+ (if (not (org-string-nw-p desc)) (format "[%s]" raw-link)
+ (concat
+ (format "[%s]" desc)
+ (unless org-e-ascii-links-to-notes (format " (%s)" raw-link))))))))
;;;; Macro
@@ -1850,11 +1840,7 @@ INFO is a plist used as a communication channel."
;;;; Target
-(defun org-e-ascii-target (target contents info)
- "Transcode a TARGET object from Org to ASCII.
-CONTENTS is the contents of the target. INFO is a plist holding
-contextual information."
- contents)
+;; Targets are invisible.
;;;; Time-stamp
diff --git a/EXPERIMENTAL/org-e-latex.el b/EXPERIMENTAL/org-e-latex.el
index 43bbde7..01b8ee2 100644
--- a/EXPERIMENTAL/org-e-latex.el
+++ b/EXPERIMENTAL/org-e-latex.el
@@ -1291,8 +1291,8 @@ CONTENTS is nil. INFO is a plist holding contextual
information."
(cond
((string= key "latex") value)
((string= key "index") (format "\\index{%s}" value))
- ((string= key "target")
- (format "\\label{%s}" (org-export-solidify-link-text value)))
+ ;; Invisible targets.
+ ((string= key "target") nil)
((string= key "toc")
(let ((value (downcase value)))
(cond
@@ -1451,32 +1451,26 @@ INFO is a plist holding contextual information. See
(org-element-parse-secondary-string
path (cdr (assq 'radio-target org-element-object-restrictions)))
'e-latex info)))
- ;; Ref link: If no description is provided, reference label PATH
- ;; and display table number. Otherwise move to label but display
- ;; description instead.
- ((string= type "ref")
- (if (not desc) (format "\\ref{%s}" path)
- (format "\\hyperref[%s]{%s}" path desc)))
;; Links pointing to an headline: Find destination and build
;; appropriate referencing command.
((member type '("custom-id" "fuzzy" "id"))
(let ((destination (if (string= type "fuzzy")
(org-export-resolve-fuzzy-link link info)
(org-export-resolve-id-link link info))))
- ;; Fuzzy link points to a target. Do as above.
(case (org-element-type destination)
- (target
- (format "\\hyperref[%s]{%s}"
- (org-export-solidify-link-text
- (org-element-property :raw-value destination))
+ ;; Fuzzy link points nowhere.
+ ('nil
+ (format "\\texttt{%s}"
(or desc
(org-export-secondary-string
(org-element-property :raw-link link)
'e-latex info))))
- ;; Fuzzy link points to an headline. If headlines are
- ;; numbered and the link has no description, display
- ;; headline's number. Otherwise, display description or
- ;; headline's title.
+ ;; Fuzzy link points to an invisible target.
+ (keyword nil)
+ ;; LINK points to an headline. If headlines are numbered
+ ;; and the link has no description, display headline's
+ ;; number. Otherwise, display description or headline's
+ ;; title.
(headline
(let ((label
(format "sec-%s"
@@ -1491,13 +1485,11 @@ INFO is a plist holding contextual information. See
(org-export-secondary-string
(org-element-property :title destination)
'e-latex info))))))
- ;; Fuzzy link points nowhere.
+ ;; Fuzzy link points to a target. Do as above.
(otherwise
- (format "\\texttt{%s}"
- (or desc
- (org-export-secondary-string
- (org-element-property :raw-link link)
- 'e-latex info)))))))
+ (let ((path (org-export-solidify-link-text path)))
+ (if (not desc) (format "\\ref{%s}" path)
+ (format "\\hyperref[%s]{%s}" path desc)))))))
;; Coderef: replace link with the reference name or the
;; equivalent line number.
((string= type "coderef")
@@ -1970,14 +1962,12 @@ CONTENTS is nil. INFO is a plist holding contextual
information."
;;;; Target
-(defun org-e-latex-target (target text info)
+(defun org-e-latex-target (target contents info)
"Transcode a TARGET object from Org to LaTeX.
-TEXT is the text of the target. INFO is a plist holding
-contextual information."
- (format "\\label{%s}%s"
- (org-export-solidify-link-text
- (org-element-property :raw-value target))
- text))
+CONTENTS is nil. INFO is a plist holding contextual
+information."
+ (format "\\label{%s}"
+ (org-export-solidify-link-text (org-element-property :value target))))
;;;; Time-stamp
diff --git a/contrib/lisp/org-element.el b/contrib/lisp/org-element.el
index 4e5e7fd..de5d4ea 100644
--- a/contrib/lisp/org-element.el
+++ b/contrib/lisp/org-element.el
@@ -1967,9 +1967,6 @@ Assume point is at the beginning of the link."
;; Explicit type (http, irc, bbdb...). See `org-link-types'.
((string-match org-link-re-with-space3 link)
(setq type (match-string 1 link) path (match-string 2 link)))
- ;; Ref type: PATH is the name of the target element.
- ((string-match "^ref:\\(.*\\)" link)
- (setq type "ref" path (org-trim (match-string 1 link))))
;; Id type: PATH is the id.
((string-match "^id:\\([-a-f0-9]+\\)" link)
(setq type "id" path (match-string 1 link)))
@@ -2269,25 +2266,21 @@ CONTENTS is the contents of the object."
"Parse target at point.
Return a list whose car is `target' and cdr a plist with
-`:begin', `:end', `:contents-begin', `:contents-end', `raw-value'
-and `:post-blank' as keywords.
+`:begin', `:end', `:contents-begin', `:contents-end', `value' and
+`:post-blank' as keywords.
Assume point is at the target."
(save-excursion
(looking-at org-target-regexp)
(let ((begin (point))
- (contents-begin (match-beginning 1))
- (contents-end (match-end 1))
- (raw-value (org-match-string-no-properties 1))
+ (value (org-match-string-no-properties 1))
(post-blank (progn (goto-char (match-end 0))
(skip-chars-forward " \t")))
(end (point)))
`(target
(:begin ,begin
:end ,end
- :contents-begin ,contents-begin
- :contents-end ,contents-end
- :raw-value ,raw-value
+ :value ,value
:post-blank ,post-blank)))))
(defun org-element-target-interpreter (target contents)
@@ -2481,7 +2474,7 @@ regexp matching one object can also match the other
object.")
"Complete list of object types.")
(defconst org-element-recursive-objects
- '(emphasis link macro subscript superscript target radio-target)
+ '(emphasis link macro subscript superscript radio-target)
"List of recursive object types.")
(defconst org-element-non-recursive-block-alist
@@ -2551,8 +2544,7 @@ This list is checked after translations have been
applied. See
(subscript entity export-snippet inline-babel-call inline-src-block
latex-fragment sub/superscript text-markup)
(superscript entity export-snippet inline-babel-call inline-src-block
- latex-fragment sub/superscript text-markup)
- (target entity export-snippet latex-fragment sub/superscript text-markup))
+ latex-fragment sub/superscript text-markup))
"Alist of recursive objects restrictions.
CAR is a recursive object type and CDR is a list of successors
diff --git a/contrib/lisp/org-export.el b/contrib/lisp/org-export.el
index b809758..e7cca50 100644
--- a/contrib/lisp/org-export.el
+++ b/contrib/lisp/org-export.el
@@ -1289,7 +1289,13 @@ Following tree properties are set:
`(:parse-tree
,data
:target-list
- ,(org-element-map data 'target 'identity info)
+ ,(org-element-map
+ data '(keyword target)
+ (lambda (blob)
+ (when (or (eq (org-element-type blob) 'target)
+ (string= (upcase (org-element-property :key blob))
+ "TARGET"))
+ blob)) info)
:headline-numbering ,(org-export-collect-headline-numbering data info)
:back-end ,backend)
info))
@@ -2697,8 +2703,11 @@ INFO is a plist holding contextual information.
Return value can be an object, an element, or nil:
-- If LINK path exactly matches any target, return the target
- object.
+- If LINK path matches a target object (i.e. <<path>>) or
+ element (i.e. \"#+target: path\"), return it.
+
+- If LINK path exactly matches the name affiliated keyword
+ \(i.e. #+name: path) of an element, return that element.
- If LINK path exactly matches any headline name, return that
element. If more than one headline share that name, priority
@@ -2709,16 +2718,29 @@ Return value can be an object, an element, or nil:
Assume LINK type is \"fuzzy\"."
(let ((path (org-element-property :path link)))
- ;; Link points to a target: return it.
- (or (loop for target in (plist-get info :target-list)
- when (string= (org-element-property :raw-value target) path)
- return target)
- ;; Link either points to an headline or nothing. Try to find
- ;; the source, with priority given to headlines with the closest
- ;; common ancestor. If such candidate is found, return its
- ;; beginning position as an unique identifier, otherwise return
- ;; nil.
- (let ((find-headline
+ (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) ?*))
+ (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) ?*))
+ (org-element-map
+ (plist-get info :parse-tree) org-element-all-elements
+ (lambda (el)
+ (when (string= (org-element-property :name el) path) el))
+ info 'first-match)))
+ ;; Last case: link either points to an headline or to
+ ;; nothingness. Try to find the source, with priority given to
+ ;; headlines with the closest common ancestor. If such candidate
+ ;; is found, return its beginning position as an unique
+ ;; identifier, otherwise return nil.
+ (t
+ (let ((find-headline
(function
;; Return first headline whose `:raw-value' property
;; is NAME in parse tree DATA, or nil.
@@ -2741,7 +2763,7 @@ Assume LINK type is \"fuzzy\"."
(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)))))))
+ (funcall find-headline path (plist-get info :parse-tree))))))))
(defun org-export-resolve-id-link (link info)
"Return headline referenced as LINK destination.
@@ -2759,20 +2781,6 @@ is either \"id\" or \"custom-id\"."
headline))
info 'first-match)))
-(defun org-export-resolve-ref-link (link info)
- "Return element referenced as LINK destination.
-
-INFO is a plist used as a communication channel.
-
-Assume LINK type is \"ref\" and. Return value is the first
-element whose `:name' property matches LINK's `:path', or nil."
- (let ((name (org-element-property :path link)))
- (org-element-map
- (plist-get info :parse-tree) org-element-all-elements
- (lambda (el)
- (when (string= (org-element-property :name el) name) el))
- info 'first-match)))
-
(defun org-export-resolve-coderef (ref info)
"Resolve a code reference REF.
@@ -2863,27 +2871,62 @@ Optional argument PREDICATE is a function returning a
non-nil
value if the current element or object should be counted in. It
accepts one argument: the element or object being considered.
This argument allows to count only a certain type of objects,
-like inline images, which are a subset of links \(in that case,
-`org-export-inline-image-p' might be an useful predicate\)."
- (let ((counter 0)
- ;; Determine if search should apply to current section, in
- ;; which case it should be retrieved first, or to full parse
- ;; tree. As a special case, an element or object without
- ;; a parent headline will also trigger a full search,
- ;; notwithstanding WITHIN-SECTION value.
- (data
- (if (not within-section) (plist-get info :parse-tree)
- (or (org-export-get-parent-headline element info)
- (plist-get info :parse-tree)))))
- ;; Increment counter until ELEMENT is found again.
- (org-element-map
- data (or types (org-element-type element))
- (lambda (el)
- (cond
- ((equal element el) (1+ counter))
- ((not predicate) (incf counter) nil)
- ((funcall predicate el) (incf counter) nil)))
- info 'first-match)))
+like inline images, which are a subset of links (in that case,
+`org-export-inline-image-p' might be an useful predicate).
+
+Return value is a list of numbers if ELEMENT is an headline or an
+item. It is nil for keywords. It represents the footnote number
+for footnote definitions and footnote references. If ELEMENT is
+a target, return the same value as if ELEMENT was the closest
+table, item or headline containing the target. In any other
+case, return the sequence number of ELEMENT among elements or
+objects of the same type."
+ ;; A target keyword, representing an invisible target, never has
+ ;; a sequence number.
+ (unless (eq (org-element-type element) 'keyword)
+ ;; Ordinal of a target object refer to the ordinal of the closest
+ ;; table, item, or headline containing the object.
+ (when (eq (org-element-type element) 'target)
+ (setq element
+ (loop for parent in (org-export-get-genealogy element info)
+ when
+ (memq
+ (org-element-type parent)
+ '(footnote-definition footnote-reference headline item
+ table))
+ return parent)))
+ (case (org-element-type element)
+ ;; Special case 1: An headline returns its number as a list.
+ (headline (org-export-get-headline-number element info))
+ ;; Special case 2: An item returns its number as a list.
+ (item (let ((struct (org-element-property :structure element)))
+ (org-list-get-item-number
+ (org-element-property :begin element)
+ struct
+ (org-list-prevs-alist struct)
+ (org-list-parents-alist struct))))
+ ((footnote definition footnote-reference)
+ (org-export-get-footnote-number element info))
+ (otherwise
+ (let ((counter 0)
+ ;; Determine if search should apply to current section,
+ ;; in which case it should be retrieved first, or to full
+ ;; parse tree. As a special case, an element or object
+ ;; without a parent headline will also trigger a full
+ ;; search, notwithstanding WITHIN-SECTION value.
+ (data
+ (if (not within-section) (plist-get info :parse-tree)
+ (or (org-export-get-parent-headline element info)
+ (plist-get info :parse-tree)))))
+ ;; Increment counter until ELEMENT is found again.
+ (org-element-map
+ data (or types (org-element-type element))
+ (lambda (el)
+ (cond
+ ((equal element el) (1+ counter))
+ ((not predicate) (incf counter) nil)
+ ((funcall predicate el) (incf counter) nil)))
+ info 'first-match))))))
;;;; For Src-Blocks
diff --git a/lisp/org.el b/lisp/org.el
index a81f7fc..b8dd292 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -9896,6 +9896,22 @@ visibility around point, thus ignoring
pos (match-beginning 0))))
;; There is an exact target for this
(goto-char pos))
+ ((save-excursion
+ (goto-char (point-min))
+ (and
+ (re-search-forward
+ (format "^[ \t]*#\\+TARGET: %s" (regexp-quote s0)) nil t)
+ (setq type 'dedicated pos (match-beginning 0))))
+ ;; Found an invisible target.
+ (goto-char pos))
+ ((save-excursion
+ (goto-char (point-min))
+ (and
+ (re-search-forward
+ (format "^[ \t]*#\\+NAME: %s" (regexp-quote s0)) nil t)
+ (setq type 'dedicated pos (match-beginning 0))))
+ ;; Found an element with a matching #+name affiliated keyword.
+ (goto-char pos))
((and (string-match "^(\\(.*\\))$" s0)
(save-excursion
(goto-char (point-min))
diff --git a/testing/contrib/lisp/test-org-export.el
b/testing/contrib/lisp/test-org-export.el
index c9923d4..f791391 100644
--- a/testing/contrib/lisp/test-org-export.el
+++ b/testing/contrib/lisp/test-org-export.el
@@ -369,3 +369,94 @@ body\n")))
;; Both footnotes should be seen.
(should
(= (length (org-export-collect-footnote-definitions tree info)) 2))))))
+
+(ert-deftest test-org-export/fuzzy-links ()
+ "Test fuzz link export specifications."
+ ;; 1. Links to invisible (keyword) targets should be ignored.
+ (org-test-with-temp-text
+ "Paragraph.\n#+TARGET: Test\n[[Test]]"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info '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-temp-text
+ "Paragraph.\n* Head1\n* Head2\n* Head3\n[[Head2]]"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info 'test)))
+ (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-temp-text
+ "- Item1\n - Item11\n - <<test>>Item12\n- Item2\n\n\n[[test]]"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info '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-temp-text
+ "Paragraph[1][2][fn:lbl3:C<<target>>][[test]][[target]]\n[1] A\n\n[2]
<<test>>B"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info 'test)))
+ (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-temp-text
+ "#+NAME: tbl1\n|1|2|\n#+NAME: tbl2\n|3|4|\n#+NAME: tbl3\n|5|6|\n[[tbl2]]"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info 'test)))
+ (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-temp-text
+ "* Head1\n* Head2\nParagraph<<target>>\n* Head3\n[[target]]"
+ (let* ((tree (org-element-parse-buffer))
+ (info (org-combine-plists (org-export-initial-options))))
+ (setq info (org-combine-plists
+ info (org-export-collect-tree-properties tree info 'test)))
+ (should
+ (equal '(2)
+ (org-element-map
+ tree 'link
+ (lambda (link)
+ (org-export-get-ordinal
+ (org-export-resolve-fuzzy-link link info) info)) info t))))))
diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el
index 4fc9ac9..3639367 100644
--- a/testing/lisp/test-org.el
+++ b/testing/lisp/test-org.el
@@ -98,6 +98,47 @@ http://article.gmane.org/gmane.emacs.orgmode/21459/"
(org-babel-next-src-block)
(should (equal '(2 1) (org-babel-execute-src-block)))))
+
+
+;;; Links
+
+;;;; Fuzzy links
+
+;; Fuzzy links [[text]] encompass links to a target (<<text>>), to
+;; a target keyword (aka an invisible target: #+TARGET: text), to
+;; a named element (#+name: text) and to headlines (* Text).
+
+(ert-deftest test-org-export/fuzzy-links ()
+ "Test fuzzy links specifications."
+ ;; 1. Fuzzy link goes in priority to a matching target.
+ (org-test-with-temp-text
+ "#+TARGET: Test\n#+NAME: Test\n|a|b|\n<<Test>>\n* Test\n[[Test]]"
+ (goto-line 4)
+ (org-open-at-point)
+ (should (looking-at "<<Test>>")))
+ ;; 2. Fuzzy link should then go to a matching target keyword.
+ (org-test-with-temp-text
+ "#+NAME: Test\n|a|b|\n#+TARGET: Test\n* Test\n[[Test]]"
+ (goto-line 4)
+ (org-open-at-point)
+ (should (looking-at "#\\+TARGET: Test")))
+ ;; 3. Then fuzzy link points to an element with a given name.
+ (org-test-with-temp-text "Test\n#+NAME: Test\n|a|b|\n* Test\n[[Test]]"
+ (goto-line 5)
+ (org-open-at-point)
+ (should (looking-at "#\\+NAME: Test")))
+ ;; 4. A target still lead to a matching headline otherwise.
+ (org-test-with-temp-text "* Head1\n* Head2\n*Head3\n[[Head2]]"
+ (goto-line 4)
+ (org-open-at-point)
+ (should (looking-at "\\* Head2")))
+ ;; 5. With a leading star in link, enforce heading match.
+ (org-test-with-temp-text "#+TARGET: Test\n* Test\n<<Test>>\n[[*Test]]"
+ (goto-line 4)
+ (org-open-at-point)
+ (should (looking-at "\\* Test"))))
+
+
(provide 'test-org)
;;; test-org.el ends here
--
1.7.9.2
- Re: [O] [dev] Implement "ref" link types, (continued)
- Re: [O] [dev] Implement "ref" link types, Carsten Dominik, 2012/02/19
- Re: [O] [dev] Implement "ref" link types, Nicolas Goaziou, 2012/02/19
- Re: [O] [dev] Implement "ref" link types, Carsten Dominik, 2012/02/20
- Re: [O] [dev] Implement "ref" link types, Nicolas Goaziou, 2012/02/20
- Re: [O] [dev] Implement "ref" link types, Nicolas Goaziou, 2012/02/20
- Re: [O] [dev] Implement "ref" link types, Thomas S. Dye, 2012/02/20
- Re: [O] [dev] Implement "ref" link types, David Maus, 2012/02/21
- Re: [O] [dev] Implement "ref" link types, Nicolas Goaziou, 2012/02/21
- Re: [O] [dev] Implement "ref" link types,
Nicolas Goaziou <=
- Re: [O] [dev] Implement "ref" link types, David Maus, 2012/02/27