0

Note: this is building on the solutions to putting images side-by-side in HTML and LaTeX:

orgmode image export side by side to both latex and html

Given the following org-mode document:

#+TITLE: Side-by-Side Test

* Export Configuration                                             :noexport:

  #+begin_src emacs-lisp :results output :session :exports both
    (defun my-org-backend-config (backend)
      "Set specific settings depending on which org-mode backend is used."
      (pcase backend
        ((or 'latex 'beamer)
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re (regexp-opt '(":latex:")))
         (setq my-remove-sections-re (regexp-opt '(":html:"))))
        ('html
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re (regexp-opt '(":html:")))
         (setq my-remove-sections-re (regexp-opt '(":latex:"))))
        (_
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re "")
         (setq my-remove-sections-re (regexp-opt '(":latex:" ":html:")))))
      ;; Remove sections marked by 'my-remove-sections-re'.
      (org-map-entries
       (lambda ()
         (when (save-excursion (re-search-forward my-remove-sections-re
                                                  (line-end-position) :noerror 1))
           (delete-region (point) (save-excursion (org-end-of-subtree t t))))))
      ;; Remove headlines marked by 'my-remove-headlines-re'.
      (org-map-entries
       (lambda ()
         (when (save-excursion (re-search-forward my-remove-headlines-re
                                                  (line-end-position) :noerror 1))
           (delete-region (point) (line-end-position)))))
      )
    (add-hook 'org-export-before-processing-hook #'my-org-backend-config)
  #+end_src

  #+RESULTS:


* Regular Header 1

  This is just some regular test content.

  #+NAME: a
  #+BEGIN_SRC dot :file /tmp/a.png
    digraph {
    1 -> 2;
    2 -> 3;
    }
  #+END_SRC

  #+NAME: b
  #+BEGIN_SRC dot :file /tmp/b.png
    digraph {
    1 -> 3;
    2 -> 3;
    }
  #+END_SRC

* HTML                                                                 :html:

  #+ATTR_HTML: :align center :height 300
  [[/tmp/a.png]]
  [[/tmp/b.png]]

* LaTeX                                                               :latex:

  #+BEGIN_CENTER
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: a
  [[file:/tmp/a.png]]
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: b
  [[file:/tmp/b.png]]
  #+END_CENTER


* Regular Header 2

  Testing a regular header, again.

Essentially, I want to strip out the sections marked with :html: when exporting to LaTeX and remove the headlines marked with :latex:. Vice versa for HTML-exports.

As written, this works fine for LaTeX, however I cannot remove the whole :latex: section when exporting as HTML; the headline is removed, but the content remains. I assume there's something wrong with the elisp code, but I cannot figure out exactly what it is.

(Note that this requires you to C-c C-c on the export configuration source block.)

Xaldew
  • 1,181
  • 9
  • 20
  • I don't know what's wrong but I have a comment: instead of running the function on each headline and depending on the regexp to decide whether to delete or not, I think it would be better to use the `match` argument of `org-map-entries` to select the appropriate headlines: `(org-map-entries (lambda () ...) (format tag))` where `tag` is set to either `latex` or `html`. I think that would simplify the `lambda`s and it also would allow for easier testing. – NickD Feb 02 '23 at 17:57
  • The bug is most probably because you are deleting the subtree which messes up `org-map-entries`'s accounting. Do `C-h v org-map-continue-from` and read the [Mapping API](https://orgmode.org/manual/Using-the-Mapping-API.html) section of the manual. – NickD Feb 02 '23 at 18:24

1 Answers1

1

Here's a fixed-up version of the code block along the lines described in my comments (i.e. 1. using the match argument of org-map-entries instead of visiting every headline and depending on a regexp to decide whether to whack it or not and 2. using org-map-continue-from to make sure that we don't skip a section after we delete one):

  #+begin_src emacs-lisp :results output :session :exports none
    (defun my-org-backend-config (backend)
      "Set specific settings depending on which org-mode backend is used."
      (pcase backend
    ((or 'latex 'beamer)
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag "latex")
     (setq my-remove-sections-tags '("html")))
    ('html
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag "html")
     (setq my-remove-sections-tags '("latex")))
    (_
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag nil)
     (setq my-remove-sections-tags '("latex" "html"))))
      ;; Remove sections marked by 'my-remove-sections-re'.
    (setq match-expr (mapconcat #'identity my-remove-sections-tags "|"))
    (org-map-entries
     (lambda ()
       (let ((beg (point))
         (end (save-excursion (org-end-of-subtree t t))))
         (delete-region beg end)
         (setq org-map-continue-from beg)))
     match-expr)
    ;; Remove headlines marked by 'my-remove-headlines-re'.
    (when my-remove-headlines-tag
      (org-map-entries
       (lambda ()
         (delete-region (point) (line-end-position)))
       my-remove-headlines-tag)))
    (add-hook 'org-export-before-processing-hook #'my-org-backend-config)
  #+end_src

As mentioned in the comment, do C-h v org-map-continue-from to read the doc string of the variable and consult the Mapping API section of the manual for the important details.

BTW, the name of the hook org-export-before-processing-hook has changed in Org 9.6 to org-export-before-processing-functions. The old name is still available for backward compatibility, but will eventually disappear, so when/if you upgrade to Org 9.6, you will want to change the name in the above code.

Also BTW, although I don't think it makes any difference in this case, you might consider using a different hook: org-export-before-parsing-hook (org-export-before-parsing-functions in 9.6 and later). This hook is run after #+INCLUDE: keywords and Org mode macros have been processed (in contrast to the before-processing one, which is run before these steps), so if you are including files and you expect the latex/html processing in the code block to apply to the contents of these files, you should use this second hook.

NickD
  • 27,023
  • 3
  • 23
  • 42
  • Aah, the classical iterator invalidation issues, thanks for the thorough answer and for providing details for these hooks, I *was* wondering what the distinction between them was. – Xaldew Feb 03 '23 at 10:25