From 229a563dc38e1fdfd63be2dfebb1a9e9023e44b2 Mon Sep 17 00:00:00 2001 Message-ID: <229a563dc38e1fdfd63be2dfebb1a9e9023e44b2.1713812419.git.yantar92@posteo.net> From: Ihor Radchenko Date: Sun, 21 Apr 2024 15:37:18 +0300 Subject: [PATCH v2 1/2] org-export-data: Handle trailing spaces when transcoder returns nil * lisp/ox.el (org-export--keep-spaces): New helper function containing logic about keeping spaces in place of removed object from `org-export--prune-tree'. The logic is modified to keep spaces in the case when previous plain-string object ends with a whitespace, but not " " or "\t". This can happen, for example, when there is a trailing zero-width space. We do want to keep spaces in such scenario. (org-export-data): When transcoder returns nil, handle trailing spaces after an object the same way `org-export--prune-tree' does. Remove special handling of export snippets that unconditionally keep their trailing spaces. (org-export--prune-tree): Use the helper function. Link: https://orgmode.org/list/87h6fwmgkm.fsf@localhost --- lisp/ox.el | 67 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/lisp/ox.el b/lisp/ox.el index fc746950d..6f6689188 100644 --- a/lisp/ox.el +++ b/lisp/ox.el @@ -1880,6 +1880,38 @@ (defun org-export-transcoder (blob info) (let ((transcoder (cdr (assq type (plist-get info :translate-alist))))) (and (functionp transcoder) transcoder))))) +(defun org-export--keep-spaces (data info) + "Non-nil, when post-blank spaces after removing DATA should be preserved. +INFO is the info channel. + +This function returns nil, when previous exported element already has +trailing spaces or when DATA does not have non-zero non-nil +`:post-blank' property. + +When the return value is non-nil, it is a string containing the trailing +spaces." + ;; When DATA is an object, interpret this as if DATA should be + ;; ignored (see `org-export--prune-tree'). Keep spaces in place of + ;; removed element, if necessary. Example: "Foo.[10%] Bar" would + ;; become "Foo.Bar" if we do not keep spaces. Another example: "A + ;; space@@ascii:*@@ character." should become "A space character" + ;; in non-ASCII export. + (let ((post-blank (org-element-post-blank data))) + (unless (or (not post-blank) + (zerop post-blank) + (eq 'element (org-element-class data))) + (let ((previous (org-export-get-previous-element data info))) + (unless (or (not previous) + (pcase (org-element-type previous) + (`plain-text + (string-match-p + (rx (any " \t") eos) previous)) + (_ (org-element-post-blank previous)))) + ;; When previous element does not have + ;; trailing spaces, keep the trailing + ;; spaces from DATA. + (make-string post-blank ?\s)))))) + ;;;###autoload (defun org-export-data (data info) "Convert DATA into current backend format. @@ -1930,15 +1962,11 @@ (defun org-export-data (data info) (eq (plist-get info :with-archived-trees) 'headline) (org-element-property :archivedp data))) (let ((transcoder (org-export-transcoder data info))) - (or (and (functionp transcoder) - (if (eq type 'link) - (broken-link-handler - (funcall transcoder data nil info)) - (funcall transcoder data nil info))) - ;; Export snippets never return a nil value so - ;; that white spaces following them are never - ;; ignored. - (and (eq type 'export-snippet) "")))) + (and (functionp transcoder) + (if (eq type 'link) + (broken-link-handler + (funcall transcoder data nil info)) + (funcall transcoder data nil info))))) ;; Element/Object with contents. (t (let ((transcoder (org-export-transcoder data info))) @@ -1979,8 +2007,8 @@ (defun org-export-data (data info) (puthash data (cond - ((not results) "") - ((memq type '(nil org-data plain-text raw)) results) + ((not results) (or (org-export--keep-spaces data info) "")) + ((memq type '(nil org-data plain-text raw)) results) ;; Append the same white space between elements or objects ;; as in the original buffer, and call appropriate filters. (t @@ -2641,24 +2669,13 @@ (defun org-export--prune-tree (data info) (let ((type (org-element-type data))) (if (org-export--skip-p data info selected excluded) (if (memq type '(table-cell table-row)) (push data ignore) - (let ((post-blank (org-element-post-blank data))) - (if (or (not post-blank) (zerop post-blank) - (eq 'element (org-element-class data))) - (org-element-extract data) + (if-let ((keep-spaces (org-export--keep-spaces data info))) ;; Keep spaces in place of removed ;; element, if necessary. ;; Example: "Foo.[10%] Bar" would become ;; "Foo.Bar" if we do not keep spaces. - (let ((previous (org-export-get-previous-element data info))) - (if (or (not previous) - (pcase (org-element-type previous) - (`plain-text - (string-match-p - (rx whitespace eos) previous)) - (_ (org-element-post-blank previous)))) - ;; Previous object ends with whitespace already. - (org-element-extract data) - (org-element-set data (make-string post-blank ?\s))))))) + (org-element-set data keep-spaces) + (org-element-extract data))) (if (and (eq type 'headline) (eq (plist-get info :with-archived-trees) 'headline) -- 2.44.0