alhassy/org-special-block-extras

defblock fails to export output when using latex derived backend

Opened this issue ยท 5 comments

Consider some latex derived backend:

(org-export-define-derived-backend
    'mybackend
    'latex
 ;; implementation detail ... 
)

And a custom special block myblock to go with it

(defblock  myblock
  (when  (or (equals 'latex) (equals 'mybackend)) 
    (concat
     "\\my-latex-command\n"
     raw-contents
     "\n\\my-latex-command")))

Use mybloc in some test.org file:

#+begin_myblock
<some content goes here>
#+end_myblock

Now the issue is myblock is never rendered when exporting test.org to latex

(org-export-to-buffer 'mybackend  "*Export Result Buffer*)

Is there a proper way to make defblock work with latex dervied backends?

Currently overriding org-latex-special-block from my-backend translation table
and fixing org-export-current-backend to point to latex during export seems to
work.

(defun ox-mybackend-special-block ( special-block contents info )
  (let ((org-export-current-backend 'latex))
         (org-latex-special-block special-block contents info))) 

I encounter a similar problem when exporting with ox-gfm. My guess is that #+begin_export gfm blocks are being generated, but then ox-gfm is delegating to ox-md, so they are not present in the output. I couldn't work out how to avoid this problem, but I don't think I understand org's export mechanism very well.

The same when exporting to epub with ox-epub: the special blocks are not present in final file.
Here the trick of @arongile is not applicable because ox-epub already uses org-html-special-block.

I've tried with

(advice-add 'org-hmtl-special-block :around
 (lambda (f &rest r)
   (let ((org-export-current-backend 'html))
     (apply 'f r))))

but nothing changed.

Finally I found a temporay fix to convert all epub exports to html ones:

(add-to-list 'org-export-filter-parse-tree-functions
             (lambda (tree backend info)
               (when (eq backend 'epub)
                 (org-element-map tree 'export-block
                   (lambda (el)
                     (when (string= (org-element-property :type el) "EPUB")
                       (org-element-put-property el :type "HTML")))))
               tree))

Hey @arongile, adopting @DPDmancul's approach, we have a solution ๐Ÿ˜‰

  1. Evaluate ospe-add-support-for-derived-backend
  2. Evaluate the following let to see an example in-action.
(defun ospe-add-support-for-derived-backend (new-backend parent-backend)
  "See subsequent snippet for a working example use."
  (add-to-list 'org-export-filter-parse-tree-functions
                `(lambda (tree backend info)
                  (when (eq backend (quote ,new-backend))
                    (org-element-map tree 'export-block
                      (lambda (el)
                        (when (string= (org-element-property :type el) (s-upcase (symbol-name (quote ,new-backend))))
                          (org-element-put-property el :type (s-upcase (symbol-name (quote ,parent-backend))))))))
                  tree)))

;; โ€œC-x C-eโ€ at the end to see an example of support for derived modes.
(-let [new-backend 'super-duper-new-derived-backend]
  ;; Register new backend
  (org-export-define-derived-backend new-backend 'latex)
  (ospe-add-support-for-derived-backend new-backend 'latex)
  ;; Register new special block
  (o-defblock amyblock nil nil
    "Place a โ€˜โœ“โ€™ before contents when doing latex derived backend exports."
    (if ;; โ‰ˆ (or (equal backend 'latex) (equal backend new-backend) โ‹ฏ)
        (org-export-derived-backend-p backend 'latex)
        (format "โœ“ %s" raw-contents)
      raw-contents))
  ;; Do an example export
  (with-temp-buffer
    (insert (s-join "\n" '("#+begin_amyblock"
                           "It worked!"
                           "#+end_amyblock")))
    ;; (org-export-to-buffer 'html "*Export Result Buffer*" nil nil t t) ;; No โ€œโœ“โ€
    (org-export-to-buffer new-backend "*Export Result Buffer*" nil nil t t) ;; Yes โ€œโœ“โ€
    ))

However, I don't know enough about derived backends to explain why this is needed. Perhaps @DPDmancul can provide more insight ๐Ÿ™


@sopoforic, this solution also works for ox-gfm ๐Ÿ˜ฒ

;; โ€œC-x C-eโ€ at the end to see an example of support for ox-gfm
(progn 
;; Register new backend
(ospe-add-support-for-derived-backend 'gfm 'html)
;; Register new special block
(o-defblock nice (๐’ "1") nil
    "Place ๐’-many โ€˜โœ“โ€™ before contents when doing latex derived backend exports."
    (if ;; โ‰ˆ (or (equal backend 'latex) (equal backend new-backend) โ‹ฏ)
        (org-export-derived-backend-p backend 'html)
        (format "%s %s" (s-repeat (string-to-number ๐’) "โœ“") raw-contents)
      raw-contents))
  ;; Do an example export
(with-temp-buffer
  (insert (s-join "\n" '("#+begin_nice 3"
                         "It worked!"
                         "#+end_nice")))
  (org-export-to-buffer 'gfm "*Export Result Buffer*" nil nil t t)))

Aslo @authsec, and @kaushalmodi of #21, this solution also works for ox-hugo ๐Ÿ˜ฒ Notice that block arguments also work as expected ๐Ÿฅณ

;; โ€œC-x C-eโ€ at the end to see an example of support for ox-hugo
(progn
;; Register new backend
(ospe-add-support-for-derived-backend 'hugo 'html)
;; Register new special block
(o-defblock nice (๐’ "1") nil
    "Place ๐’-many โ€˜โœ“โ€™ before contents when doing latex derived backend exports."
    (if ;; โ‰ˆ (or (equal backend 'latex) (equal backend new-backend) โ‹ฏ)
        (org-export-derived-backend-p backend 'html)
        (format "%s %s" (s-repeat (string-to-number ๐’) "โœ“") raw-contents)
      raw-contents))
  ;; Do an example export
(with-temp-buffer
  (insert (s-join "\n" '("#+begin_nice 3"
                         "It worked!"
                         "#+end_nice")))
  (org-export-to-buffer 'hugo "*Export Result Buffer*" nil nil t t)))

Hi @alhassy, that sounds awesome, but unfortunately I cannot get it to work ๐Ÿ˜ž.

I am using the following configuration, but if I export with C-c C-e H A I end up with Symbol's value as variable is void: org-export-derived-backend-p.

If I execute the temp buffer test however, that seems to work for me and produces:

+++
draft = false
+++

{{% alert title="My new Title" color="secondary"%}}
It worked!
{{% /alert %}}

New Configuration

 (use-package org-special-block-extras
  :ensure t
  :after org
  :hook (org-mode . org-special-block-extras-mode)
  :config
  (defun ospe-add-support-for-derived-backend (new-backend parent-backend)
    "See subsequent snippet for a working example use."
    (add-to-list 'org-export-filter-parse-tree-functions
		 `(lambda (tree backend info)
		    (when (eq backend (quote ,new-backend))
		      (org-element-map tree 'export-block
			(lambda (el)
			  (when (string= (org-element-property :type el) (s-upcase (symbol-name (quote ,new-backend))))
			    (org-element-put-property el :type (s-upcase (symbol-name (quote ,parent-backend))))))))
		    tree)))
;; โ€œC-x C-eโ€ at the end to see an example of support for ox-hugo
(progn
;; Register new backend
(ospe-add-support-for-derived-backend 'hugo 'html)
;; Register new special block
(o-defblock noteblock (title "Note") (titleColor "primary")
	    "Define noteblock export for docsy ox hugo"
	    (if ;; โ‰ˆ (or (equal backend 'latex) (equal backend new-backend) โ‹ฏ)
		(org-export-derived-backend-p backend 'hugo)
		(format "{{%% alert title=\"%s\" color=\"%s\"%%}}\n%s{{%% /alert %%}}" title titleColor raw-contents) title titleColor
		raw-contents))
;; Do an example export
(with-temp-buffer
  (insert (s-join "\n" '("#+begin_noteblock \"My new Title\" :titleColor \"secondary\""
                         "It worked!"
                         "#+end_noteblock")))
  (org-export-to-buffer 'hugo "*Export Result Buffer*" nil nil t t)))
)

"Old" Configuration

The configuration I tried to build before is which works, but is unable to interpret the parameters given.:

 (use-package org-special-block-extras
       :ensure t
       :after org
       :hook (org-mode . org-special-block-extras-mode)
       :config
       (o-defblock noteblock (title "Note") (title-color "primary")
		   "Define noteblock export for docsy ox hugo"
		   (apply #'concat
			  (pcase backend
			    (`latex `("\\begin{noteblock}", contents, "\\end{noteblock}"))
			    (`hugo `("{{% alert title=\"", title, "\" color=\"", title-color, "\" %}}\n", contents, "\n{{% /alert %}}"))
			    )
			  )
		   )
       (o-defblock cautionblock (title "Caution") (title-color "warning")
		   "Awesomebox caution"
		   (apply #'concat
			  (pcase backend
			    (`latex `("\\begin{cautionblock}", contents, "\\end{cautionblock}"))
			    (`hugo `("{{% alert title=\"", title, "\" color=\"", title-color, "\" %}}\n", contents, "\n{{% /alert %}}"))
			    )
			  )
		   )
       )

Can you please update the "old" configuration with the pcase in a way that I might make it work?