فهرست منبع

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'.
Nicolas Goaziou 9 سال پیش
والد
کامیت
bef3fc6f82
2فایلهای تغییر یافته به همراه63 افزوده شده و 96 حذف شده
  1. 52 93
      lisp/ox-publish.el
  2. 11 3
      lisp/ox.el

+ 52 - 93
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))))))
 
 
 

+ 11 - 3
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))))