emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Ihor Radchenko <yantar92@posteo.net>
To: David Lukes <dafydd.lukes@gmail.com>
Cc: emacs-orgmode@gnu.org
Subject: Re: [PATCH] ox-odt: Prevent auto-formatting in export buffers
Date: Sat, 18 Mar 2023 11:42:59 +0000	[thread overview]
Message-ID: <87zg8axp30.fsf@localhost> (raw)
In-Reply-To: <20221002035931.12191-1-dafydd.lukes@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1117 bytes --]

David Lukes <dafydd.lukes@gmail.com> writes:

> * lisp/ox-odt.el (org-odt-template, org-odt--export-wrap):
> `write-region' instead of `save-buffer'.
>
> `write-file' and `save-buffer' trigger major mode changes, which leads
> to various mode-related hooks being run.  This is undesirable: running
> these on generated files is wasted time and computation, and it can even
> lead to hard to track data corruption when auto-formatting hooks are
> involved.  One such case is the 2006 version of the tidy program which
> ships with stock macOS and can corrupt multi-byte UTF-8 codepoints in
> HTML and ODT (via XML) exports.  And even recent versions of tidy can
> re-arrange whitespace in the exported documents in unwanted ways.

See the attached patch where I applied the idea across Org, where it
made sense. Note that I did not alter `org-odt--export-wrap' because
`save-buffer' there is applied only when XML files are opened as buffers
in Emacs, presumably manually. Interactive `save-buffer' makes sense
then. (Though maybe that code is not needed at all, IDK)

Please let me know if there are any objections.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Prefer-write-region-to-save-file.patch --]
[-- Type: text/x-patch, Size: 9278 bytes --]

From 8d8884bb6be0ba7cb7f9662f067d42b53393e92e Mon Sep 17 00:00:00 2001
Message-Id: <8d8884bb6be0ba7cb7f9662f067d42b53393e92e.1679139580.git.yantar92@posteo.net>
From: Ihor Radchenko <yantar92@posteo.net>
Date: Sat, 18 Mar 2023 12:34:17 +0100
Subject: [PATCH] Prefer `write-region' to `save-file'

* lisp/ob-haskell.el (org-babel-haskell-export-to-lhs): Use
non-interactive `insert-file-contents' + `write-region' to avoid
triggering various interactive hooks.  Ensure that temp files are
always deleted.
* lisp/org-agenda.el (org-agenda-write):
* lisp/org-table.el: Simplify code using `write-region'.
* lisp/ox-odt.el (org-odt-template): Use `insert-file-contents' +
`write-region' instead of `find-file-noselect' that may trigger
various hooks.  The new approach makes `revert-buffer' not
necessary (and do not trigger `revert-buffer' hooks).  Also, the
problem with backups will no longer exists.

Original idea: https://list.orgmode.org/orgmode/20221002035931.12191-1-dafydd.lukes@gmail.com/
---
 lisp/ob-haskell.el | 41 ++++++++++++------------
 lisp/org-agenda.el |  9 ++----
 lisp/org-table.el  | 10 ++----
 lisp/ox-odt.el     | 78 ++++++++++++++++++++--------------------------
 4 files changed, 59 insertions(+), 79 deletions(-)

diff --git a/lisp/ob-haskell.el b/lisp/ob-haskell.el
index 2b1441c2a..3e64c1657 100644
--- a/lisp/ob-haskell.el
+++ b/lisp/ob-haskell.el
@@ -255,26 +255,27 @@ (defun org-babel-haskell-export-to-lhs (&optional arg)
                        t t)
         (indent-code-rigidly (match-beginning 0) (match-end 0) indentation)))
     (save-excursion
-      ;; export to latex w/org and save as .lhs
-      (require 'ox-latex)
-      (find-file tmp-org-file)
-      ;; Ensure we do not clutter kill ring with incomplete results.
-      (let (org-export-copy-to-kill-ring)
-	(org-export-to-file 'latex tmp-tex-file))
-      (kill-buffer nil)
-      (delete-file tmp-org-file)
-      (find-file tmp-tex-file)
-      (goto-char (point-min)) (forward-line 2)
-      (insert "%include polycode.fmt\n")
-      ;; ensure all \begin/end{code} statements start at the first column
-      (while (re-search-forward "^[ \t]+\\\\begin{code}[^\000]+\\\\end{code}" nil t)
-        (replace-match (save-match-data (org-remove-indentation (match-string 0)))
-                       t t))
-      (setq contents (buffer-string))
-      (save-buffer) (kill-buffer nil))
-    (delete-file tmp-tex-file)
-    ;; save org exported latex to a .lhs file
-    (with-temp-file lhs-file (insert contents))
+      (unwind-protect
+          (with-temp-buffer
+            ;; Export to latex w/org and save as .lhs
+            (require 'ox-latex)
+            (insert-file-contents tmp-org-file)
+            ;; Ensure we do not clutter kill ring with incomplete results.
+            (let (org-export-copy-to-kill-ring)
+	      (org-export-to-file 'latex tmp-tex-file)))
+        (delete-file tmp-org-file))
+      (unwind-protect
+          (with-temp-buffer
+            (insert-file-contents tmp-tex-file)
+            (goto-char (point-min)) (forward-line 2)
+            (insert "%include polycode.fmt\n")
+            ;; ensure all \begin/end{code} statements start at the first column
+            (while (re-search-forward "^[ \t]+\\\\begin{code}[^\000]+\\\\end{code}" nil t)
+              (replace-match (save-match-data (org-remove-indentation (match-string 0)))
+                             t t))
+            ;; save org exported latex to a .lhs file
+            (write-region nil nil lhs-file))
+        (delete-file tmp-tex-file)))
     (if (not arg)
         (find-file lhs-file)
       ;; process .lhs file with lhs2tex
diff --git a/lisp/org-agenda.el b/lisp/org-agenda.el
index 3da0967f0..859a80c47 100644
--- a/lisp/org-agenda.el
+++ b/lisp/org-agenda.el
@@ -3667,13 +3667,8 @@ (defun org-agenda-write (file &optional open nosettings agenda-bufname)
 	                        "ox-icalendar" (file))
 	      (org-icalendar-export-current-agenda (expand-file-name file)))
 	     (t
-	      (let ((bs (buffer-string)))
-		(find-file file)
-		(erase-buffer)
-		(insert bs)
-		(save-buffer 0)
-		(kill-buffer (current-buffer))
-		(message "Plain text written to %s" file))))))))
+              (write-region nil nil file)
+              (message "Plain text written to %s" file)))))))
     (set-buffer (or agenda-bufname
 		    ;; FIXME: I'm pretty sure called-interactively-p
                     ;; doesn't do what we want here!
diff --git a/lisp/org-table.el b/lisp/org-table.el
index 5116b1127..97120fffd 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -4332,14 +4332,8 @@ (defun org-table-export (&optional file format)
 		(table (org-table-to-lisp)))
 	    (unless (fboundp transform)
 	      (user-error "No such transformation function %s" transform))
-	    (let (buf)
-	      (with-current-buffer (find-file-noselect file)
-		(setq buf (current-buffer))
-		(erase-buffer)
-		(fundamental-mode)
-		(insert (funcall transform table params) "\n")
-		(save-buffer))
-	      (kill-buffer buf))
+            (with-temp-file file
+              (insert (funcall transform table params) "\n"))
 	    (message "Export done."))
 	(user-error "TABLE_EXPORT_FORMAT invalid")))))
 
diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index cf217c9e7..8fc34a749 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1365,50 +1365,40 @@ (defun org-odt-template (contents info)
     ;; Ensure we have write permissions to this file.
     (set-file-modes (concat org-odt-zip-dir "styles.xml") #o600)
 
-    ;; FIXME: Who is opening an empty styles.xml before this point?
-    (with-current-buffer
-	(find-file-noselect (concat org-odt-zip-dir "styles.xml") t)
-      (revert-buffer t t)
-
-      ;; Write custom styles for source blocks
-      ;; Save STYLES used for colorizing of source blocks.
-      ;; Update styles.xml with styles that were collected as part of
-      ;; `org-odt-hfy-face-to-css' callbacks.
-      (let ((styles (mapconcat (lambda (style) (format " %s\n" (cddr style)))
-			       hfy-user-sheet-assoc "")))
-	(when styles
-	  (goto-char (point-min))
-	  (when (re-search-forward "</office:styles>" nil t)
-	    (goto-char (match-beginning 0))
-	    (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n"))))
-
-      ;; Update styles.xml - take care of outline numbering
-
-      ;; Don't make automatic backup of styles.xml file. This setting
-      ;; prevents the backed-up styles.xml file from being zipped in to
-      ;; odt file. This is more of a hackish fix. Better alternative
-      ;; would be to fix the zip command so that the output odt file
-      ;; includes only the needed files and excludes any auto-generated
-      ;; extra files like backups and auto-saves etc etc. Note that
-      ;; currently the zip command zips up the entire temp directory so
-      ;; that any auto-generated files created under the hood ends up in
-      ;; the resulting odt file.
-      (setq-local backup-inhibited t)
-
-      ;; Outline numbering is retained only up to LEVEL.
-      ;; To disable outline numbering pass a LEVEL of 0.
-
-      (goto-char (point-min))
-      (let ((regex
-	     "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
-	    (replacement
-	     "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
-	(while (re-search-forward regex nil t)
-	  (unless (let ((sec-num (plist-get info :section-numbers))
-			(level (string-to-number (match-string 2))))
-		    (if (wholenump sec-num) (<= level sec-num) sec-num))
-	    (replace-match replacement t nil))))
-      (save-buffer 0)))
+    (let ((styles-xml (concat org-odt-zip-dir "styles.xml")))
+      (with-temp-buffer
+        (when (file-exists-p styles-xml)
+          (insert-file-contents styles-xml))
+        
+        ;; Write custom styles for source blocks
+        ;; Save STYLES used for colorizing of source blocks.
+        ;; Update styles.xml with styles that were collected as part of
+        ;; `org-odt-hfy-face-to-css' callbacks.
+        (let ((styles (mapconcat (lambda (style) (format " %s\n" (cddr style)))
+			         hfy-user-sheet-assoc "")))
+          (when styles
+	    (goto-char (point-min))
+	    (when (re-search-forward "</office:styles>" nil t)
+	      (goto-char (match-beginning 0))
+	      (insert "\n<!-- Org Htmlfontify Styles -->\n" styles "\n"))))
+
+        ;; Update styles.xml - take care of outline numbering
+        ;; Outline numbering is retained only up to LEVEL.
+        ;; To disable outline numbering pass a LEVEL of 0.
+
+        (let ((regex
+	       "<text:outline-level-style\\([^>]*\\)text:level=\"\\([^\"]*\\)\"\\([^>]*\\)>")
+	      (replacement
+	       "<text:outline-level-style\\1text:level=\"\\2\" style:num-format=\"\">"))
+          (goto-char (point-min))
+          (while (re-search-forward regex nil t)
+	    (unless (let ((sec-num (plist-get info :section-numbers))
+		          (level (string-to-number (match-string 2))))
+		      (if (wholenump sec-num) (<= level sec-num) sec-num))
+	      (replace-match replacement t nil))))
+        
+        ;; Write back the new contents.
+        (write-region nil nil styles-xml))))
   ;; Update content.xml.
 
   (let* ( ;; `org-display-custom-times' should be accessed right
-- 
2.39.1


[-- Attachment #3: Type: text/plain, Size: 224 bytes --]


-- 
Ihor Radchenko // yantar92,
Org mode contributor,
Learn more about Org mode at <https://orgmode.org/>.
Support Org development at <https://liberapay.com/org-mode>,
or support my work at <https://liberapay.com/yantar92>

  parent reply	other threads:[~2023-03-18 11:42 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-02  3:59 [PATCH] ox-odt: Prevent auto-formatting in export buffers David Lukes
2022-10-02  7:25 ` Ihor Radchenko
2022-10-03 12:10   ` David Lukeš
2023-03-18 11:42 ` Ihor Radchenko [this message]
2023-04-02 14:27   ` Ihor Radchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87zg8axp30.fsf@localhost \
    --to=yantar92@posteo.net \
    --cc=dafydd.lukes@gmail.com \
    --cc=emacs-orgmode@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).