summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2017-09-10 00:16:12 +0200
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2017-09-10 00:23:42 +0200
commit007bbddbccfd06ab9c97d51bf833a068cb1b07a2 (patch)
tree485d699d6dc14ba0befac3906bbc62f6a234391a
parentb3ab012d6992e1989b10b81d8a1dbb71b0dfd0cf (diff)
downloadorg-mode-007bbddbccfd06ab9c97d51bf833a068cb1b07a2.tar.gz
ox-html: Prevent spurious target below headlines
* lisp/ox-html.el (org-html-headline): (org-html-link): Do not insert an additional target. * lisp/ox-publish.el (org-publish-resolve-external-link): Add an optional argument. * lisp/ox.el (org-export-get-reference): Improve docstring. * testing/examples/pub/a.org: * testing/examples/pub/b.org: New files. * testing/lisp/test-ox-publish.el (test-org-publish/resolve-external-link): New test.
-rw-r--r--etc/ORG-NEWS4
-rw-r--r--lisp/ox-html.el42
-rw-r--r--lisp/ox-publish.el35
-rw-r--r--lisp/ox.el16
-rw-r--r--testing/examples/pub/a.org7
-rw-r--r--testing/examples/pub/b.org3
-rw-r--r--testing/lisp/test-ox-publish.el63
7 files changed, 124 insertions, 46 deletions
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index e6ad838..59e6cb3 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -58,6 +58,10 @@ size.
,#+STARTUP: shrink
#+END_EXAMPLE
+** Miscellaneous
+
+*** ~org-publish-resolve-external-link~ accepts a new optional argument.
+
* Version 9.1
** Incompatible changes
diff --git a/lisp/ox-html.el b/lisp/ox-html.el
index 48a3b3b..87de2be 100644
--- a/lisp/ox-html.el
+++ b/lisp/ox-html.el
@@ -2599,18 +2599,8 @@ holding contextual information."
(full-text (funcall (plist-get info :html-format-headline-function)
todo todo-type priority text tags info))
(contents (or contents ""))
- (ids (delq nil
- (list (org-element-property :CUSTOM_ID headline)
- (org-export-get-reference headline info)
- (org-element-property :ID headline))))
- (preferred-id (car ids))
- (extra-ids
- (mapconcat
- (lambda (id)
- (org-html--anchor
- (if (org-uuidgen-p id) (concat "ID-" id) id)
- nil nil info))
- (cdr ids) "")))
+ (id (or (org-element-property :CUSTOM_ID headline)
+ (org-export-get-reference headline info))))
(if (org-export-low-level-p headline info)
;; This is a deep sub-tree: export it as a list item.
(let* ((html-type (if numberedp "ol" "ul")))
@@ -2619,11 +2609,9 @@ holding contextual information."
(apply #'format "<%s class=\"org-%s\">\n"
(make-list 2 html-type)))
(org-html-format-list-item
- contents (if numberedp 'ordered 'unordered)
- nil info nil
- (concat (org-html--anchor preferred-id nil nil info)
- extra-ids
- full-text)) "\n"
+ contents (if numberedp 'ordered 'unordered)
+ nil info nil
+ (concat (org-html--anchor id nil nil info) full-text)) "\n"
(and (org-export-last-sibling-p headline info)
(format "</%s>\n" html-type))))
;; Standard headline. Export it as a section.
@@ -2636,10 +2624,9 @@ holding contextual information."
(concat (format "outline-%d" level)
(and extra-class " ")
extra-class)
- (format "\n<h%d id=\"%s\">%s%s</h%d>\n"
+ (format "\n<h%d id=\"%s\">%s</h%d>\n"
level
- preferred-id
- extra-ids
+ id
(concat
(and numberedp
(format
@@ -3010,16 +2997,11 @@ INFO is a plist holding contextual information. See
;; relative to a custom-id, a headline title, a name or
;; a target.
(let ((option (org-element-property :search-option link)))
- (cond ((not option) raw-path)
- ;; Since HTML back-end use custom-id value as-is,
- ;; resolving is them is trivial.
- ((eq (string-to-char option) ?#) (concat raw-path option))
- (t
- (concat raw-path
- "#"
- (org-publish-resolve-external-link
- option
- (org-element-property :path link)))))))
+ (if (not option) raw-path
+ (let ((path (org-element-property :path link)))
+ (concat raw-path
+ "#"
+ (org-publish-resolve-external-link option path t))))))
(t raw-path)))
;; Extract attributes from parent's paragraph. HACK: Only do
;; this for the first link in parent (inner image link for
diff --git a/lisp/ox-publish.el b/lisp/ox-publish.el
index 8ae13d6..8fca544 100644
--- a/lisp/ox-publish.el
+++ b/lisp/ox-publish.el
@@ -1131,7 +1131,7 @@ This function is meant to be used as a final output filter. See
;; Return output unchanged.
output)
-(defun org-publish-resolve-external-link (search file)
+(defun org-publish-resolve-external-link (search file &optional prefer-custom)
"Return reference for element matching string SEARCH in FILE.
Return value is an internal reference, as a string.
@@ -1139,18 +1139,31 @@ Return value is an internal reference, as a string.
This function allows resolving external links with a search
option, e.g.,
- [[file.org::*heading][description]]
- [[file.org::#custom-id][description]]
- [[file.org::fuzzy][description]]
+ [[file:file.org::*heading][description]]
+ [[file:file.org::#custom-id][description]]
+ [[file:file.org::fuzzy][description]]
+
+When PREFER-CUSTOM is non-nil, and SEARCH targets a headline in
+FILE, return its custom ID, if any.
It only makes sense to use this if export back-end builds
references with `org-export-get-reference'."
- (if (not org-publish-cache)
- (progn
- (message "Reference %S in file %S cannot be resolved without publishing"
- search
- file)
- "MissingReference")
+ (cond
+ ((and prefer-custom
+ (if (string-prefix-p "#" search)
+ (substring search 1)
+ (with-current-buffer (find-file-noselect file)
+ (org-with-point-at 1
+ (org-link-search search nil t)
+ (and (org-at-heading-p)
+ (org-string-nw-p (org-entry-get (point) "CUSTOM_ID"))))))))
+ ((not org-publish-cache)
+ (progn
+ (message "Reference %S in file %S cannot be resolved without publishing"
+ search
+ file)
+ "MissingReference"))
+ (t
(let* ((filename (file-truename file))
(crossrefs
(org-publish-cache-get-file-property filename :crossrefs nil t))
@@ -1167,7 +1180,7 @@ references with `org-export-get-reference'."
(let ((new (org-export-new-reference crossrefs)))
(dolist (cell cells) (push (cons cell new) crossrefs))
(org-publish-cache-set-file-property filename :crossrefs crossrefs)
- (org-export-format-reference new))))))
+ (org-export-format-reference new)))))))
diff --git a/lisp/ox.el b/lisp/ox.el
index b6528d9..14da82c 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4436,9 +4436,19 @@ REFERENCE is a number representing a reference, as returned by
DATUM is either an element or an object. INFO is the current
export state, as a plist.
-This function checks `:crossrefs' property in INFO for search
-cells matching DATUM before creating a new reference. Returned
-reference consists of alphanumeric characters only."
+References for the current document are stored in
+`:internal-references' property. Its value is an alist with
+associations of the following types:
+
+ (REFERENCE . DATUM) and (SEARCH-CELL . ID)
+
+REFERENCE is the reference string to be used for object or
+element DATUM. SEARCH-CELL is a search cell, as returned by
+`org-export-search-cells'. ID is a number or a string uniquely
+identifying DATUM within the document.
+
+This function also checks `:crossrefs' property for search cells
+matching DATUM before creating a new reference."
(let ((cache (plist-get info :internal-references)))
(or (car (rassq datum cache))
(let* ((crossrefs (plist-get info :crossrefs))
diff --git a/testing/examples/pub/a.org b/testing/examples/pub/a.org
index 41a9a0f..daa82f1 100644
--- a/testing/examples/pub/a.org
+++ b/testing/examples/pub/a.org
@@ -1,4 +1,9 @@
#+title: A
#+date: <2014-03-04 Tue>
-Contents
+* Headline1
+:PROPERTIES:
+:CUSTOM_ID: a1
+:END:
+
+[[file:b.org::*Headline1]]
diff --git a/testing/examples/pub/b.org b/testing/examples/pub/b.org
index 707ee18..6038746 100644
--- a/testing/examples/pub/b.org
+++ b/testing/examples/pub/b.org
@@ -1,3 +1,6 @@
#+title: b
#+date: <2012-03-29 Thu>
+* Headline1
+
+[[file:a.org::#a1]]
diff --git a/testing/lisp/test-ox-publish.el b/testing/lisp/test-ox-publish.el
index cefddee..3553807 100644
--- a/testing/lisp/test-ox-publish.el
+++ b/testing/lisp/test-ox-publish.el
@@ -94,7 +94,6 @@ Unless set otherwise in PROPERTIES, `:base-directory' is set to
(cl-remove-if #'file-directory-p
(directory-files dir))))))))
-
;;; Site-map
@@ -328,6 +327,68 @@ Unless set otherwise in PROPERTIES, `:base-directory' is set to
(buffer-string)))))))
+;;; Cross references
+
+(ert-deftest test-org-publish/resolve-external-link ()
+ "Test `org-publish-resolve-external-link' specifications."
+ ;; Function should preserve internal reference when used between
+ ;; published files.
+ (should
+ (apply
+ #'equal
+ (let* ((ids nil)
+ (backend
+ (org-export-create-backend
+ :transcoders
+ '((headline . (lambda (h c i)
+ (concat (org-export-get-reference h i) " " c)))
+ (paragraph . (lambda (p c i) c))
+ (section . (lambda (s c i) c))
+ (link . (lambda (l c i)
+ (let ((option (org-element-property :search-option l))
+ (path (org-element-property :path l)))
+ (and option
+ (org-publish-resolve-external-link
+ option path))))))))
+ (publish
+ (lambda (plist filename pub-dir)
+ (org-publish-org-to backend filename ".test" plist pub-dir))))
+ (org-test-publish
+ (list :publishing-function (list publish))
+ (lambda (dir)
+ (cl-subseq
+ (split-string
+ (mapconcat (lambda (f) (org-file-contents (expand-file-name f dir)))
+ (directory-files dir nil "\\.test\\'")
+ " "))
+ 1 3))))))
+ ;; When optional argument PREFER-CUSTOM is non-nil, use custom ID
+ ;; instead of internal reference, whenever possible.
+ (should
+ (equal
+ "a1"
+ (let* ((ids nil)
+ (backend
+ (org-export-create-backend
+ :transcoders
+ '((headline . (lambda (h c i) c))
+ (paragraph . (lambda (p c i) c))
+ (section . (lambda (s c i) c))
+ (link . (lambda (l c i)
+ (let ((option (org-element-property :search-option l))
+ (path (org-element-property :path l)))
+ (when option
+ (throw :exit (org-publish-resolve-external-link
+ option path t)))))))))
+ (publish
+ (lambda (plist filename pub-dir)
+ (push (catch :exit
+ (org-publish-org-to backend filename ".test" plist pub-dir))
+ ids))))
+ (org-test-publish (list :publishing-function (list publish)) #'ignore)
+ (car ids)))))
+
+
;;; Tools
(ert-deftest test-org-publish/get-project-from-filename ()