summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2016-03-07 23:43:23 +0100
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2016-03-12 23:18:55 +0100
commit32c3f33d00b3dc9affa44b4af432dc349d41e444 (patch)
tree48211b6185257395fa9a1528dfd77e978ef13c2b
parent6ec06dcff98e2db9811d1d1e9da01399e9cc1fe3 (diff)
downloadorg-mode-32c3f33d00b3dc9affa44b4af432dc349d41e444.tar.gz
ox: Use a new scheme for internal references
* lisp/ox.el (org-export-get-reference): Use randomly generated labels. (org-export-new-reference): (org-export-format-reference): New functions. * testing/lisp/test-ox.el (test-org-export/get-reference): New test. The new scheme is better when datum type cannot be known ahead of time or when references are not created sequentially, e.g., during a publishing process where a reference to a file can be require before the file is published.
-rw-r--r--lisp/ox.el58
-rw-r--r--testing/lisp/test-ox.el22
2 files changed, 64 insertions, 16 deletions
diff --git a/lisp/ox.el b/lisp/ox.el
index bb94559..4bb58f6 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4315,29 +4315,55 @@ has type \"radio\"."
;;;; For References
;;
;; `org-export-get-reference' associate a unique reference for any
-;; object or element.
+;; object or element. It uses `org-export-new-reference' and
+;; `org-export-format-reference' to, respectively, generate new
+;; internal references and turn them into a string suitable for
+;; output.
;;
;; `org-export-get-ordinal' associates a sequence number to any object
;; or element.
+(defun org-export-new-reference (references)
+ "Return a unique reference, among REFERENCES.
+REFERENCES is an alist whose values are in-use references, as
+numbers. Returns a number, which is the internal representation
+of a reference. See also `org-export-format-reference'."
+ ;; Generate random 7 digits hexadecimal numbers. Collisions
+ ;; increase exponentially with the numbers of references. However,
+ ;; the odds for encountering at least one collision with 1000 active
+ ;; references in the same document are roughly 0.2%, so this
+ ;; shouldn't be the bottleneck.
+ (let ((new (random #x10000000)))
+ (while (rassq new references) (setq new (random #x10000000)))
+ new))
+
+(defun org-export-format-reference (reference)
+ "Format REFERENCE into a string.
+REFERENCE is a number representing a reference, as returned by
+`org-export-new-reference', which see."
+ (format "org%x" reference))
+
(defun org-export-get-reference (datum info)
"Return a unique reference for DATUM, as a string.
+
DATUM is either an element or an object. INFO is the current
-export state, as a plist. Returned reference consists of
-alphanumeric characters only."
- (let ((type (org-element-type datum))
- (cache (or (plist-get info :internal-references)
- (let ((h (make-hash-table :test #'eq)))
- (plist-put info :internal-references h)
- h))))
- (or (gethash datum cache)
- (puthash datum
- (format "org%s%d"
- (if type
- (replace-regexp-in-string "-" "" (symbol-name type))
- "secondarystring")
- (cl-incf (gethash type cache 0)))
- cache))))
+export state, as a plist.
+
+This functions checks `:crossrefs' property in INFO for search
+cells matching DATUM before creating a new reference. Returned
+reference consists of alphanumeric characters only."
+ (let ((cache (plist-get info :internal-references)))
+ (or (car (rassq datum cache))
+ (let* ((new (org-export-new-reference cache))
+ (search-cells (org-export-search-cells datum))
+ (reference-string (org-export-format-reference new)))
+ ;; Cache contains both data already associated to
+ ;; a reference and in-use internal references, so as to make
+ ;; unique references.
+ (push (cons search-cells new) cache)
+ (push (cons reference-string datum) cache)
+ (plist-put info :internal-references cache)
+ reference-string))))
(defun org-export-get-ordinal (element info &optional types predicate)
"Return ordinal number of an element or object.
diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
index 0b89d42..f51288f 100644
--- a/testing/lisp/test-ox.el
+++ b/testing/lisp/test-ox.el
@@ -2873,6 +2873,28 @@ Another text. (ref:text)
(should (equal (org-export-file-uri "~/file.org")
(concat "file://" (expand-file-name "~/file.org")))))
+(ert-deftest test-org-export/get-reference ()
+ "Test `org-export-get-reference' specifications."
+ (should
+ (org-test-with-parsed-data "* Headline"
+ (org-export-get-reference (org-element-map tree 'headline #'identity nil t)
+ info)))
+ ;; For a given element always return the same reference.
+ (should
+ (org-test-with-parsed-data "* Headline"
+ (let ((headline (org-element-map tree 'headline #'identity nil t)))
+ (equal (org-export-get-reference headline info)
+ (org-export-get-reference headline info)))))
+ ;; Use search cells defined in `:crossrefs'.
+ (should
+ (equal "org1"
+ (org-test-with-parsed-data "* Headline"
+ (let* ((headline (org-element-map tree 'headline #'identity nil t))
+ (search-cell (car (org-export-search-cells headline))))
+ (setq info
+ (plist-put info :crossrefs (list (cons search-cell 1))))
+ (org-export-get-reference headline info))))))
+
;;; Src-block and example-block