jkitchin / ox-ipynb

org-mode exporter to Jupyter notebooks
172 stars 40 forks source link

Support for org-cite #51

Open colormotor opened 1 month ago

colormotor commented 1 month ago

Hi, I am unable to export bibliographies when using org-cite, e.g. as a minimal example:

#+TITLE: Test export
#+cite_export: csl

Test some citations such as [cite:@Schumaker1981SplineFB]
#+BEGIN_SRC jupyter-python :session py :exports both
print("Hello world")
#+END_SRC

* Bibliography
#+print_bibliography:

This will work fine with html/latex but will produce an empty bibliography for notebooks. I did not notice any errors when exporting. Is ox-ipynb designed to work with org-ref only?

jkitchin commented 1 month ago

ox-ipynb in general can't support many org-export features because it exports cells one at at time without the broader context of the rest of the document. I am not sure of a better way to do it. For something like citations, the best solution is probably to use the preprocess hook to convert citations to plain text or markdown.

For org-ref I think something like this works:

#+TITLE: Test export
#+cite_export: csl

Test some citations such as [[cite:&kreitz-2024-unify]].

#+BEGIN_SRC jupyter-python :session py :exports both
print("Hello world")
#+END_SRC

bibliography:~/Dropbox/emacs/bibliography/references.bib

* build                                                            :noexport:

#+BEGIN_SRC emacs-lisp
(let ((ox-ipynb-preprocess-hook  '((lambda ()
                     (org-ref-csl-preprocess-buffer 'md)))))

  (ox-ipynb-export-to-ipynb-file-and-open))
#+END_SRC

I guess there is something like this for the native org-format. The code in org-ref-export.el actually uses the CSL code to do this.

colormotor commented 1 month ago

Thanks for the quick reply! I was unable to find a simple way to retrieve formatted text directly from the org-cite API, but ended up solving this with a bit of a hack. I set ox-ipynb-preprocess-hook to a function that extends the current buffer with a org-formatted "References" section. To do this I first export the buffer as a temporary org file (without executing code to save time) and then copy the relevant section into the current buffer for then exporting to ipynb. Happy to post the code here if relevant, but this is probably not the ideal solution:)

However, I see that the ox-ipynb-export-to-ipynb-no-results-file-and-open backend option (which I usually go for) defines it's own hook that overrides the custom one. Is there a recommended way to either modify or extend the interface so I can access my functionality when accessing the export menu?

jkitchin commented 1 month ago

That is a poor design choice that I should update. I am traveling shortly though so it will be a while. These functions are just small wrappers like:

(let ((ox-ipynb-preprocess-hook '((lambda ()
                      (org-babel-map-src-blocks nil
                    (org-babel-remove-result))))))
    (ox-ipynb-export-to-ipynb-file-and-open))

I would just make a heading tagged noexport and put the variant you want in a src block.

I think a solution will look like this:

(defun ox-ipynb-export-to-ipynb-no-results-file-and-open (&optional async subtreep visible-only body-only info)
  "Export current buffer to a file and open it. Strip results first.
Optional argument ASYNC to asynchronously export.
Optional argument SUBTREEP to export current subtree.
Optional argument VISIBLE-ONLY to only export visible content.
Optional argument BODY-ONLY export only the body.
Optional argument INFO is a plist of options."

  (let ((ox-ipynb-preprocess-hook ox-ipynb-preprocess-hook))
    (add-hook 'ox-ipynb-preprocess-hook (lambda ()
                      (org-babel-map-src-blocks nil
                        (org-babel-remove-result))))

    (ox-ipynb-export-to-ipynb-file-and-open)))

I don't have a lot of time for testing now, and will update this in a week or so after I can try it out.