[PATCH] ox-odt: Prevent auto-formatting in export buffers

2022-10-01 Thread David Lukes
* 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.

TINYCHANGE
---
 lisp/ox-odt.el | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 208a39d9d..c678f22e7 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1414,7 +1414,7 @@ original parsed data.  INFO is a plist holding export 
options."
(level (string-to-number (match-string 2
(if (wholenump sec-num) (<= level sec-num) sec-num))
(replace-match replacement t nil
-  (save-buffer 0)))
+  (write-region nil nil buffer-file-name)))
   ;; Update content.xml.
 
   (let* ( ;; `org-display-custom-times' should be accessed right
@@ -4007,7 +4007,7 @@ contextual information."
   ;; Prettify output if needed.
   (when org-odt-prettify-xml
 (indent-region (point-min) (point-max)))
-  (save-buffer 0)
+  (write-region nil nil buffer-file-name)
   ;; Run zip.
   (let* ((target --out-file)
  (target-name (file-name-nondirectory target))
-- 
2.37.1




[PATCH] ox.el: Protect export from auto-formatting hooks

2022-06-21 Thread David Lukes
* ox.el, ox-odt.el: Use `write-region' instead of `write-file' or
`save-buffer' to protect generated export buffers from auto-formatting
hooks.

In particular, `tidy' is often configured as the auto-formatter for HTML
and XML, and it can corrupt the exports.

TINYCHANGE
---
 lisp/ox-odt.el | 4 ++--
 lisp/ox.el | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 9d47067..ec1c360 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1411,7 +1411,7 @@ original parsed data.  INFO is a plist holding export 
options."
(level (string-to-number (match-string 2
(if (wholenump sec-num) (<= level sec-num) sec-num))
(replace-match replacement t nil
-  (save-buffer 0)))
+  (write-region nil nil buffer-file-name)))
   ;; Update content.xml.
 
   (let* ( ;; `org-display-custom-times' should be accessed right
@@ -4004,7 +4004,7 @@ contextual information."
   ;; Prettify output if needed.
   (when org-odt-prettify-xml
 (indent-region (point-min) (point-max)))
-  (save-buffer 0)
+  (write-region nil nil buffer-file-name)
   ;; Run zip.
   (let* ((target --out-file)
  (target-name (file-name-nondirectory target))
diff --git a/lisp/ox.el b/lisp/ox.el
index c75357b..66d18c4 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -6553,14 +6553,14 @@ or FILE."
   (with-temp-buffer
 (insert output)
 (let ((coding-system-for-write ',encoding))
-  (write-file ,file)))
+  (write-region nil nil ,file)))
   (or (ignore-errors (funcall ',post-process ,file)) ,file)))
 (let ((output (org-export-as
backend subtreep visible-only body-only ext-plist)))
   (with-temp-buffer
 (insert output)
 (let ((coding-system-for-write encoding))
- (write-file file)))
+ (write-region nil nil file)))
   (when (and (org-export--copy-to-kill-ring-p) (org-string-nw-p 
output))
 (org-kill-new output))
   ;; Get proper return value.
-- 
2.36.1




[PATCH] oc-basic.el: Stringify year from CSL-JSON date-parts

2022-06-21 Thread David Lukes
* lisp/oc-basic.el (org-cite-basic--parse-json): Make sure year
extracted from date-parts is returned as string.  Raise error if
original type other than number or string.

The stringifiation is motivated by errors like the following on Emacs 28
with nativecomp:

Error during redisplay: (jit-lock-function 544) signaled
(wrong-type-argument "Argument is not a string or a secondary string:
2007")

Additionally, the type check will warn users about problems in their
CSL-JSON bibliographies.

TINYCHANGE
---
 lisp/oc-basic.el | 9 -
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el
index a937f75..f10b95b 100644
--- a/lisp/oc-basic.el
+++ b/lisp/oc-basic.el
@@ -189,7 +189,14 @@ Return a hash table with citation references as keys and 
fields alist as values.
 (cons 'year
   (cond
((consp date)
-(caar date))
+ (let ((year (caar date)))
+   (cond
+ ((numberp year) (number-to-string 
year))
+ ((stringp year) year)
+ (t
+   (error
+ "First element of CSL-JSON 
date-parts should be a number or string, got %s: %S"
+ (type-of year) year)
((stringp date)
 (replace-regexp-in-string
   (rx
-- 
2.36.1




[PATCH] ox: Prevent auto-formatting in export buffers

2022-02-28 Thread David Lukes
* ox.el (org-export-to-file): `write-region' instead of  `write-file'.

* 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.

TINYCHANGE
---
 lisp/ox-odt.el |  4 ++--
 lisp/ox.el | 16 ++--
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
index 7f2e8ba47..6a8e75e9d 100644
--- a/lisp/ox-odt.el
+++ b/lisp/ox-odt.el
@@ -1427,7 +1427,7 @@ original parsed data.  INFO is a plist holding export 
options."
(level (string-to-number (match-string 2
(if (wholenump sec-num) (<= level sec-num) sec-num))
(replace-match replacement t nil
-  (save-buffer 0)))
+  (write-region nil nil buffer-file-name)))
   ;; Update content.xml.
 
   (let* ( ;; `org-display-custom-times' should be accessed right
@@ -4018,7 +4018,7 @@ contextual information."
   ;; Prettify output if needed.
   (when org-odt-prettify-xml
 (indent-region (point-min) (point-max)))
-  (save-buffer 0)
+  (write-region nil nil buffer-file-name)
   ;; Run zip.
   (let* ((target --out-file)
  (target-name (file-name-nondirectory target))
diff --git a/lisp/ox.el b/lisp/ox.el
index 2a3edaa50..8ec1e25ee 100644
--- a/lisp/ox.el
+++ b/lisp/ox.el
@@ -6459,18 +6459,14 @@ or FILE."
`(let ((output
(org-export-as
 ',backend ,subtreep ,visible-only ,body-only
-',ext-plist)))
-  (with-temp-buffer
-(insert output)
-(let ((coding-system-for-write ',encoding))
-  (write-file ,file)))
+',ext-plist))
+  (coding-system-for-write ',encoding))
+  (write-region output nil ,file)
   (or (ignore-errors (funcall ',post-process ,file)) ,file)))
 (let ((output (org-export-as
-   backend subtreep visible-only body-only ext-plist)))
-  (with-temp-buffer
-(insert output)
-(let ((coding-system-for-write encoding))
- (write-file file)))
+   backend subtreep visible-only body-only ext-plist))
+  (coding-system-for-write encoding))
+  (write-region output nil file)
   (when (and (org-export--copy-to-kill-ring-p) (org-string-nw-p 
output))
 (org-kill-new output))
   ;; Get proper return value.
-- 
2.34.1




[PATCH] oc-basic.el: Better handling of CSL-JSON dates

2022-02-25 Thread David Lukes
* lisp/oc-basic.el (org-cite-basic--parse-json): Make date-parsing and
year extraction more resilient.  Provide more informative errors when it
fails.

A string-based date is not only indicated by the key 'raw, but also
possibly by the key 'literal.

String-based dates come in various formats, not necessarily -mm-dd.
So extracting the first sequence of 4 digits is arguably a better
heuristic for getting the publication year than splitting the string on
- and getting the car of that.

On error, include `value' in the message, which contains the original
value with actionable information, whereas the previously included
`date' is always nil in that case.

TINYCHANGE
---
 lisp/oc-basic.el | 20 ++--
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/lisp/oc-basic.el b/lisp/oc-basic.el
index d82406aff..81b7e4471 100644
--- a/lisp/oc-basic.el
+++ b/lisp/oc-basic.el
@@ -178,21 +178,29 @@ Return a hash table with citation references as keys and 
fields alist as values.
  " and ")))
  ('issued
   ;; Date are expressed as an array
-  ;; (`date-parts') or a "string (`raw').
-  ;; In both cases, extract the year and
-  ;; associate it to `year' field, for
-  ;; compatibility with BibTeX format.
+  ;; (`date-parts') or a "string (`raw'
+  ;; or `literal'). In both cases,
+  ;; extract the year and associate it
+  ;; to `year' field, for compatibility
+  ;; with BibTeX format.
   (let ((date (or (alist-get 'date-parts value)
+  (alist-get 'literal value)
   (alist-get 'raw value
 (cons 'year
   (cond
((consp date)
 (caar date))
((stringp date)
-(car (split-string date "-")))
+(replace-regexp-in-string
+  (rx
+(minimal-match (zero-or-more 
anything))
+(group-n 1 (repeat 4 digit))
+(zero-or-more anything))
+  (rx (backref 1))
+  date))
(t
 (error "Unknown CSL-JSON date format: 
%S"
-   date))
+   value))
  (_
   (cons field value
  item)
-- 
2.34.1




[PATCH] org-indent: Allow indentation per level to be 0

2021-08-31 Thread David Lukes
* lisp/org-indent.el (org-indent--compute-prefixes): Prefixes should
only be computed when `org-indent-indentation-per-level' is greater than
0.  For one thing, the current algorithm leads to an error otherwise,
and for another, this makes it possible to use org-indent just to
preserve indentation on continuation lines, without adding any
additional indentation per level (by setting the option to 0).

TINYCHANGE
---
 lisp/org-indent.el | 49 +++---
 1 file changed, 25 insertions(+), 24 deletions(-)

diff --git a/lisp/org-indent.el b/lisp/org-indent.el
index ea7ea071b..b87cc4e5f 100644
--- a/lisp/org-indent.el
+++ b/lisp/org-indent.el
@@ -126,31 +126,32 @@ useful to make it ever so slightly different."
(make-vector org-indent--deepest-level nil))
   (setq org-indent--text-line-prefixes
(make-vector org-indent--deepest-level nil))
-  (dotimes (n org-indent--deepest-level)
-(let ((indentation (if (<= n 1) 0
-(* (1- org-indent-indentation-per-level)
-   (1- n)
-  ;; Headlines line prefixes.
-  (let ((heading-prefix (make-string indentation ?*)))
-   (aset org-indent--heading-line-prefixes
+  (when (> org-indent-indentation-per-level 0)
+(dotimes (n org-indent--deepest-level)
+  (let ((indentation (if (<= n 1) 0
+  (* (1- org-indent-indentation-per-level)
+ (1- n)
+;; Headlines line prefixes.
+(let ((heading-prefix (make-string indentation ?*)))
+ (aset org-indent--heading-line-prefixes
+   n
+   (org-add-props heading-prefix nil 'face 'org-indent))
+ ;; Inline tasks line prefixes
+ (aset org-indent--inlinetask-line-prefixes
+   n
+   (cond ((<= n 1) "")
+ ((bound-and-true-p org-inlinetask-show-first-star)
+  (concat org-indent-inlinetask-first-star
+  (substring heading-prefix 1)))
+ (t (org-add-props heading-prefix nil 'face 
'org-indent)
+;; Text line prefixes.
+(aset org-indent--text-line-prefixes
  n
- (org-add-props heading-prefix nil 'face 'org-indent))
-   ;; Inline tasks line prefixes
-   (aset org-indent--inlinetask-line-prefixes
- n
- (cond ((<= n 1) "")
-   ((bound-and-true-p org-inlinetask-show-first-star)
-(concat org-indent-inlinetask-first-star
-(substring heading-prefix 1)))
-   (t (org-add-props heading-prefix nil 'face 'org-indent)
-  ;; Text line prefixes.
-  (aset org-indent--text-line-prefixes
-   n
-   (org-add-props
-   (concat (make-string (+ n indentation) ?\s)
-   (and (> n 0)
-(char-to-string org-indent-boundary-char)))
-   nil 'face 'org-indent)
+ (org-add-props
+  (concat (make-string (+ n indentation) ?\s)
+  (and (> n 0)
+   (char-to-string org-indent-boundary-char)))
+  nil 'face 'org-indent))
 
 (defsubst org-indent-remove-properties (beg end)
   "Remove indentations between BEG and END."
-- 
2.32.0