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 2 years 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
 	;; temporary buffer so that dvipng/imagemagick can properly
 	;; turn the fragment into an image.
 	;; turn the fragment into an image.
 	(setq latex-frag (concat latex-header latex-frag))))
 	(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)
 (defun org-html--wrap-latex-environment (contents _ &optional caption label)
   "Wrap CONTENTS string within appropriate environment for equations.
   "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
 ;; a default template (or a back-end specific template) at point or in
 ;; current subtree.
 ;; 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.
   "Return a copy of the current buffer.
 The copy preserves Org buffer-local variables, visibility and
 The copy preserves Org buffer-local variables, visibility and
 narrowing.
 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
 Emacs save dialogue.  Prefer using `org-export-with-buffer-copy' macro
 when possible.
 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
   (let ((copy-buffer-fun (org-export--generate-copy-script
                           (current-buffer)
                           (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
     (with-current-buffer new-buf
       (funcall copy-buffer-fun)
       (funcall copy-buffer-fun)
       (set-buffer-modified-p nil))
       (set-buffer-modified-p nil))
     new-buf))
     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.
   "Apply BODY in a copy of the current buffer.
 The copy preserves local variables, visibility and contents of
 The copy preserves local variables, visibility and contents of
 the original buffer.  Point is at the beginning of the buffer
 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))
   (declare (debug t))
   (org-with-gensyms (buf-copy)
   (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
        (unwind-protect
 	   (with-current-buffer ,buf-copy
 	   (with-current-buffer ,buf-copy
 	     (goto-char (point-min))
 	     (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)
 	 (and (buffer-live-p ,buf-copy)
 	      ;; Kill copy without confirmation.
 	      ;; Kill copy without confirmation.
 	      (progn (with-current-buffer ,buf-copy
 	      (progn (with-current-buffer ,buf-copy
 		       (restore-buffer-modified-p nil))
 		       (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.
   "Generate a function duplicating BUFFER.
 
 
 The copy will preserve local variables, visibility, contents and
 The copy will preserve local variables, visibility, contents and
 narrowing of the original buffer.  If a region was active in
 narrowing of the original buffer.  If a region was active in
 BUFFER, contents will be narrowed to that region instead.
 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
 The resulting function can be evaluated at a later time, from
 another buffer, effectively cloning the original buffer there.
 another buffer, effectively cloning the original buffer there.