Browse Source

org-export-with-buffer-copy: Allow safe reusable buffer copy

* lisp/ox.el (org-export--generate-copy-script):
(org-export-copy-buffer):  Accept cl-style key arguments.
* lisp/ox.el (org-export-with-buffer-copy): Allow optional cl-style
key arguments for fine-grained control on what to copy from the target
buffer and which buffer to use as a target.  Do not kill the target
buffer upon finished, when the target is provided.  Make sure that
remaining buffer copy does not preserve `buffer-file-name' from the
original buffer and that it never overwrites the file associated with
the original buffer.
* lisp/ox-html.el (org-html-format-latex): Use the new version of
`org-export-with-buffer-copy' instead of managing edge cases by
itself.

Reported-by: Rudolf Adamkovič <salutis@me.com>
Link: https://orgmode.org/list/87zge8j5iu.fsf@localhost
Ihor Radchenko 1 year ago
parent
commit
192742c9c5
2 changed files with 59 additions and 50 deletions
  1. 8 19
      lisp/ox-html.el
  2. 51 31
      lisp/ox.el

+ 8 - 19
lisp/ox-html.el

@@ -2879,25 +2879,14 @@ INFO is a plist containing export properties."
 	;; temporary buffer so that dvipng/imagemagick can properly
 	;; turn the fragment into an image.
 	(setq latex-frag (concat latex-header latex-frag))))
-    (with-current-buffer
-        (org-export-copy-buffer
-         (get-buffer-create " *Org HTML Export LaTeX*")
-         'drop-visible 'drop-narrowing 'drop-contents)
-      (erase-buffer)
-      (insert latex-frag)
-      (org-format-latex cache-relpath nil nil cache-dir nil
-		        "Creating LaTeX Image..." nil processing-type)
-      ;; Present save dialogue to be shown for this buffer and prevent
-      ;; Emacs to jump into this buffer when opening
-      ;; `buffer-file-name' file.  We need this because
-      ;; `org-export-copy-buffer' copies `buffer-file-name' local
-      ;; variable thus making Emacs think that the buffer copy is
-      ;; associated with file.  Note that despite `buffer-file-name',
-      ;; `org-export-copy-buffer' arranges saving to not perform
-      ;; actual writing onto the disk.
-      (setq buffer-file-name nil)
-      (restore-buffer-modified-p nil)
-      (buffer-string))))
+    (org-export-with-buffer-copy
+     :to-buffer (get-buffer-create " *Org HTML Export LaTeX*")
+     :drop-visibility t :drop-narrowing t :drop-contents t
+     (erase-buffer)
+     (insert latex-frag)
+     (org-format-latex cache-relpath nil nil cache-dir nil
+		       "Creating LaTeX Image..." nil processing-type)
+     (buffer-string))))
 
 (defun org-html--wrap-latex-environment (contents _ &optional caption label)
   "Wrap CONTENTS string within appropriate environment for equations.

+ 51 - 31
lisp/ox.el

@@ -2544,9 +2544,9 @@ Return the updated communication channel."
 ;; a default template (or a back-end specific template) at point or in
 ;; current subtree.
 
-(defun org-export-copy-buffer (&optional buffer drop-visibility
-                                         drop-narrowing drop-contents
-                                         drop-locals)
+(cl-defun org-export-copy-buffer (&key to-buffer drop-visibility
+                                       drop-narrowing drop-contents
+                                       drop-locals)
   "Return a copy of the current buffer.
 The copy preserves Org buffer-local variables, visibility and
 narrowing.
@@ -2561,61 +2561,81 @@ then re-opened.  Making edits in the buffer copy may also trigger
 Emacs save dialogue.  Prefer using `org-export-with-buffer-copy' macro
 when possible.
 
-When optional argument BUFFER is non-nil, copy into BUFFER.
+When optional key `:to-buffer' is non-nil, copy into BUFFER.
 
-Optional arguments DROP-VISIBILITY, DROP-NARROWING, DROP-CONTENTS, and
-DROP-LOCALS are passed to `org-export--generate-copy-script'."
+Optional keys `:drop-visibility', `:drop-narrowing', `:drop-contents',
+and `:drop-locals' are passed to `org-export--generate-copy-script'."
   (let ((copy-buffer-fun (org-export--generate-copy-script
                           (current-buffer)
-                          'do-not-check-unreadable
-                          drop-visibility
-                          drop-narrowing
-                          drop-contents
-                          drop-locals))
-	(new-buf (or buffer (generate-new-buffer (buffer-name)))))
+                          :copy-unreadable 'do-not-check
+                          :drop-visibility drop-visibility
+                          :drop-narrowing drop-narrowing
+                          :drop-contents drop-contents
+                          :drop-locals drop-locals))
+	(new-buf (or to-buffer (generate-new-buffer (buffer-name)))))
     (with-current-buffer new-buf
       (funcall copy-buffer-fun)
       (set-buffer-modified-p nil))
     new-buf))
 
-(defmacro org-export-with-buffer-copy (&rest body)
+(cl-defmacro org-export-with-buffer-copy ( &rest body
+                                           &key to-buffer drop-visibility
+                                           drop-narrowing drop-contents
+                                           drop-locals
+                                           &allow-other-keys)
   "Apply BODY in a copy of the current buffer.
 The copy preserves local variables, visibility and contents of
 the original buffer.  Point is at the beginning of the buffer
-when BODY is applied."
+when BODY is applied.
+
+Optional keys can modify what is being copied and the generated buffer
+copy.  `:to-buffer', `:drop-visibility', `:drop-narrowing',
+`:drop-contents', and `:drop-locals' are passed as arguments to
+`org-export-copy-buffer'."
   (declare (debug t))
   (org-with-gensyms (buf-copy)
-    `(let ((,buf-copy (org-export-copy-buffer)))
+    `(let ((,buf-copy (org-export-copy-buffer
+                       :to-buffer ,to-buffer
+                       :drop-visibility ,drop-visibility
+                       :drop-narrowing ,drop-narrowing
+                       :drop-contents ,drop-contents
+                       :drop-locals ,drop-locals)))
        (unwind-protect
 	   (with-current-buffer ,buf-copy
 	     (goto-char (point-min))
-	     (progn ,@body))
+             (prog1
+	         (progn ,@body)
+               ;; `org-export-copy-buffer' carried the value of
+               ;; `buffer-file-name' from the original buffer.  When not
+               ;; killed, the new buffer copy may become a target of
+               ;; `find-file'.  Prevent this.
+               (setq buffer-file-name nil)))
 	 (and (buffer-live-p ,buf-copy)
 	      ;; Kill copy without confirmation.
 	      (progn (with-current-buffer ,buf-copy
 		       (restore-buffer-modified-p nil))
-		     (kill-buffer ,buf-copy)))))))
-
-(defun org-export--generate-copy-script (buffer
-                                         &optional
-                                         copy-unreadable
-                                         drop-visibility
-                                         drop-narrowing
-                                         drop-contents
-                                         drop-locals)
+                     (unless ,to-buffer
+		       (kill-buffer ,buf-copy))))))))
+
+(cl-defun org-export--generate-copy-script (buffer
+                                            &key
+                                            copy-unreadable
+                                            drop-visibility
+                                            drop-narrowing
+                                            drop-contents
+                                            drop-locals)
   "Generate a function duplicating BUFFER.
 
 The copy will preserve local variables, visibility, contents and
 narrowing of the original buffer.  If a region was active in
 BUFFER, contents will be narrowed to that region instead.
 
-When optional argument COPY-UNREADABLE is non-nil, do not ensure that
-all the copied local variables will be readable in another Emacs
-session.
+When optional key `:copy-unreadable' is non-nil, do not ensure that all
+the copied local variables will be readable in another Emacs session.
 
-When optional arguments DROP-VISIBILITY, DROP-NARROWING,
-DROP-CONTENTS, or DROP-LOCALS are non-nil, do not preserve visibility,
-narrowing, contents, or local variables correspondingly.
+When optional keys `:drop-visibility', `:drop-narrowing',
+`:drop-contents', or `:drop-locals' are non-nil, do not preserve
+visibility, narrowing, contents, or local variables correspondingly.
 
 The resulting function can be evaluated at a later time, from
 another buffer, effectively cloning the original buffer there.