forked from mirrors/org-mode
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.
This commit is contained in:
parent
7c8e9125cb
commit
933c0fa441
|
@ -820,28 +820,22 @@ 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 ((dest (org-export-resolve-id-link link info)))
|
||||
(concat
|
||||
(org-e-ascii--fill-string
|
||||
(format
|
||||
"[%s] %s"
|
||||
anchor
|
||||
(if (not dest) (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 dest 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.
|
||||
|
@ -1385,29 +1379,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
|
||||
|
@ -1845,11 +1833,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
|
||||
|
|
|
@ -1289,8 +1289,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
|
||||
|
@ -1449,32 +1449,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"
|
||||
|
@ -1489,13 +1483,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")
|
||||
|
@ -1968,14 +1960,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
@ -2704,8 +2710,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
|
||||
|
@ -2716,16 +2725,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.
|
||||
|
@ -2748,7 +2770,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.
|
||||
|
@ -2766,20 +2788,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.
|
||||
|
||||
|
@ -2870,27 +2878,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
|
||||
|
|
16
lisp/org.el
16
lisp/org.el
|
@ -9898,6 +9898,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))
|
||||
|
|
|
@ -364,3 +364,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))))))
|
||||
|
|
|
@ -88,6 +88,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
|
||||
|
|
Loading…
Reference in New Issue