summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Goaziou <mail@nicolasgoaziou.fr>2016-03-10 21:50:44 +0100
committerNicolas Goaziou <mail@nicolasgoaziou.fr>2016-03-12 23:18:55 +0100
commitbef3fc6f821dd7533308a0849963fef2b3f889df (patch)
tree7767d7862725e484d90710b5971abf804428eea7
parent32c3f33d00b3dc9affa44b4af432dc349d41e444 (diff)
downloadorg-mode-bef3fc6f821dd7533308a0849963fef2b3f889df.tar.gz
ox-publish: Better handling of cross-references
* lisp/ox-publish.el (org-publish--collect-references): Renamed... (org-publish--store-crossrefs): ... to this. (org-publish-org-to): Use previous function. Small refactoring. (org-publish-resolve-external-link): Use tight integration with `org-export-get-reference' so as to provide reliable cross references. * lisp/ox.el (org-export-get-reference): Conversely, take into consideration references suggested by `org-publish-resolve-external-link'.
-rw-r--r--lisp/ox-publish.el145
-rw-r--r--lisp/ox.el14
2 files changed, 63 insertions, 96 deletions
diff --git a/lisp/ox-publish.el b/lisp/ox-publish.el
index 27f06ff..92d7408 100644
--- a/lisp/ox-publish.el
+++ b/lisp/ox-publish.el
@@ -568,27 +568,25 @@ Return output file name."
(unless (or (not pub-dir) (file-exists-p pub-dir)) (make-directory pub-dir t))
;; Check if a buffer visiting FILENAME is already open.
(let* ((org-inhibit-startup t)
- (visitingp (find-buffer-visiting filename))
- (work-buffer (or visitingp (find-file-noselect filename))))
- (prog1 (with-current-buffer work-buffer
- (let ((output-file
- (org-export-output-file-name extension nil pub-dir))
- (body-p (plist-get plist :body-only)))
- (org-export-to-file backend output-file
- nil nil nil body-p
- ;; Add `org-publish--collect-references' and
- ;; `org-publish-collect-index' to final output
- ;; filters. The latter isn't dependent on
- ;; `:makeindex', since we want to keep it up-to-date
- ;; in cache anyway.
- (org-combine-plists
- plist
- `(:filter-final-output
- ,(cons 'org-publish--collect-references
- (cons 'org-publish-collect-index
- (plist-get plist :filter-final-output))))))))
+ (visiting (find-buffer-visiting filename))
+ (work-buffer (or visiting (find-file-noselect filename))))
+ (unwind-protect
+ (with-current-buffer work-buffer
+ (let ((output (org-export-output-file-name extension nil pub-dir)))
+ (org-export-to-file backend output
+ nil nil nil (plist-get plist :body-only)
+ ;; Add `org-publish--store-crossrefs' and
+ ;; `org-publish-collect-index' to final output filters.
+ ;; The latter isn't dependent on `:makeindex', since we
+ ;; want to keep it up-to-date in cache anyway.
+ (org-combine-plists
+ plist
+ `(:filter-final-output
+ (org-publish--store-crossrefs
+ org-publish-collect-index
+ ,@(plist-get plist :filter-final-output)))))))
;; Remove opened buffer in the process.
- (unless visitingp (kill-buffer work-buffer)))))
+ (unless visiting (kill-buffer work-buffer)))))
(defun org-publish-attachment (_plist filename pub-dir)
"Publish a file with no transformation of any kind.
@@ -1061,68 +1059,23 @@ publishing directory."
;; This part implements tools to resolve [[file.org::*Some headline]]
;; links, where "file.org" belongs to the current project.
-(defun org-publish--collect-references (output _backend info)
- "Store references for current published file.
+(defun org-publish--store-crossrefs (output _backend info)
+ "Store cross-references for current published file.
OUPUT is the produced output, as a string. BACKEND is the export
back-end used, as a symbol. INFO is the final export state, as
a plist.
-References are stored as an alist ((TYPE SEARCH) . VALUE) where
-
- TYPE is a symbol among `headline', `custom-id', `target' and
- `other'.
-
- SEARCH is the string a link is expected to match. It is
-
- - headline's title, as a string, with all whitespace
- characters and statistics cookies removed, if TYPE is
- `headline'.
-
- - CUSTOM_ID value if TYPE is `custom-id'.
-
- - target's or radio-target's name if TYPE is `target'.
-
- - NAME affiliated keyword is TYPE is `other'.
-
- VALUE is an internal reference used in the document, as
- a string.
-
This function is meant to be used as a final output filter. See
`org-publish-org-to'."
(org-publish-cache-set-file-property
- (plist-get info :input-file) :references
- (let (refs)
- (when (hash-table-p (plist-get info :internal-references))
- (maphash
- (lambda (k v)
- (pcase (org-element-type k)
- (`nil nil)
- ((or `headline `inlinetask)
- (push (cons
- (cons 'headline
- (org-split-string
- (replace-regexp-in-string
- "\\[[0-9]+%\\]\\|\\[[0-9]+/[0-9]+\\]" ""
- (org-element-property :raw-value k))))
- v)
- refs)
- (let ((custom-id (org-element-property :CUSTOM_ID k)))
- (when custom-id
- (push (cons (cons 'custom-id custom-id) v) refs))))
- ((or `radio-target `target)
- (push
- (cons (cons 'target
- (org-split-string (org-element-property :value k)))
- v)
- refs))
- ((and (let name (org-element-property :name k))
- (guard name))
- (push (cons (cons 'other (org-split-string name)) v)
- refs)))
- refs)
- (plist-get info :internal-references)))
- refs))
+ (plist-get info :input-file) :crossrefs
+ ;; Update `:crossrefs' so as to remove unused references and search
+ ;; cells. Actually used references are extracted from
+ ;; `:internal-references', with references as strings removed. See
+ ;; `org-export-get-reference' for details.
+ (cl-remove-if (lambda (pair) (stringp (car pair)))
+ (plist-get info :internal-references)))
;; Return output unchanged.
output)
@@ -1131,32 +1084,38 @@ This function is meant to be used as a final output filter. See
Return value is an internal reference, as a string.
-This function allows the resolution of external links like:
+This function allows resolving external links with a search
+option, e.g.,
- [[file.org::*fuzzy][description]]
+ [[file.org::*heading][description]]
[[file.org::#custom-id][description]]
- [[file.org::fuzzy][description]]"
+ [[file.org::fuzzy][description]]
+
+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"
+ (message "Reference %S in file %S cannot be resolved without publishing"
search
file)
"MissingReference")
- (let ((references (org-publish-cache-get-file-property
- (expand-file-name file) :references nil t)))
- (cond
- ((cdr (pcase (aref search 0)
- (?* (assoc (cons 'headline (org-split-string (substring search 1)))
- references))
- (?# (assoc (cons 'custom-id (substring search 1)) references))
- (_
- (let ((s (org-split-string search)))
- (or (assoc (cons 'target s) references)
- (assoc (cons 'other s) references)
- (assoc (cons 'headline s) references)))))))
- (t (message "Unknown cross-reference \"%s\" in file \"%s\"" search file)
- "MissingReference")))))
+ (let* ((filename (expand-file-name file))
+ (crossrefs
+ (org-publish-cache-get-file-property filename :crossrefs nil t))
+ (cells (org-export-string-to-search-cell search)))
+ (or
+ ;; Look for reference associated to search cells triggered by
+ ;; LINK. It can match when targeted file has been published
+ ;; already.
+ (let ((known (cdr (cl-some (lambda (c) (assoc c crossrefs)) cells))))
+ (and known (org-export-format-reference known)))
+ ;; Search cell is unknown so far. Generate a new internal
+ ;; reference that will be used when the targeted file will be
+ ;; published.
+ (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))))))
diff --git a/lisp/ox.el b/lisp/ox.el
index 4bb58f6..d93493f 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -4354,13 +4354,21 @@ 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))
+ (let* ((crossrefs (plist-get info :crossrefs))
+ (cells (org-export-search-cells datum))
+ ;; If any other published document relies on an
+ ;; association between a search cell and a reference,
+ ;; make sure to preserve it. See
+ ;; `org-publish-resolve-external-link' for details.
+ (new (or (cdr (cl-some (lambda (c) (assoc c crossrefs)) cells))
+ (org-export-new-reference cache)))
(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)
+ (dolist (cell cells) (push (cons cell new) cache))
+ ;; Keep an associated related to DATUM as not every object
+ ;; and element can be associated to a search cell.
(push (cons reference-string datum) cache)
(plist-put info :internal-references cache)
reference-string))))