Fix output order when using pandoc conversion

Fixes #351.
This commit is contained in:
Nathaniel Nicandro 2021-11-12 13:50:52 -06:00 committed by Nathaniel Nicandro
parent 57306bf385
commit 4729e21184
2 changed files with 114 additions and 4 deletions

View file

@ -694,7 +694,10 @@ If PARAMS has non-nil value for key ':pandoc' and TYPE is in
Otherwise, wrap it in an export block." Otherwise, wrap it in an export block."
(if (and (alist-get :pandoc params) (if (and (alist-get :pandoc params)
(member type jupyter-org-pandoc-convertable)) (member type jupyter-org-pandoc-convertable))
(jupyter-org-raw-string (jupyter-pandoc-convert type "org" value)) (list 'pandoc
(list :text "Converting..."
:type type
:value value))
(jupyter-org-export-block type value))) (jupyter-org-export-block type value)))
(defun jupyter-org-export-block (type value) (defun jupyter-org-export-block (type value)
@ -1469,6 +1472,43 @@ Assumes `point' is on the #+RESULTS keyword line."
(set-marker end nil))) (set-marker end nil)))
(jupyter-org--mark-stream-result-newline result)))))) (jupyter-org--mark-stream-result-newline result))))))
(defun jupyter-org--start-pandoc-conversion (el cb)
(jupyter-pandoc-convert
(org-element-property :type el) "org"
(org-element-property :value el)
cb))
(defun jupyter-org-pandoc-placeholder-element (req el)
"Launch a Pandoc conversion process of EL, return a placeholder string.
REQ is the `jupyter-org-request' which generated EL as a result.
The placeholder string is meant to be inserted into the Org
buffer and replaced with the result of conversion when ready.
EL is an Org element with the properties
:text The placeholder text to use.
:type The type of syntax from which to convert.
:value The code with the corresponding syntax."
(letrec ((buf (current-buffer))
(src-pos (copy-marker (jupyter-org-request-marker req)))
(cb (lambda ()
(let ((to-string (buffer-string)))
(with-current-buffer buf
(save-excursion
(goto-char src-pos)
(set-marker src-pos nil)
(when (text-property-search-forward 'jupyter-pandoc proc)
(delete-region (point)
(1+ (next-single-property-change
(point) 'jupyter-pandoc)))
(insert to-string)))))))
(proc (jupyter-org--start-pandoc-conversion el cb)))
(jupyter-org-raw-string
(propertize
(org-element-property :text el)
'jupyter-pandoc proc))))
(cl-defgeneric jupyter-org--insert-result (req context result) (cl-defgeneric jupyter-org--insert-result (req context result)
"For REQ and given CONTEXT, insert RESULT. "For REQ and given CONTEXT, insert RESULT.
REQ is a `jupyter-org-request' that contains the context of the REQ is a `jupyter-org-request' that contains the context of the
@ -1479,7 +1519,10 @@ source block associated with REQ.
RESULT is the new result, as an org element, to be inserted.") RESULT is the new result, as an org element, to be inserted.")
(cl-defmethod jupyter-org--insert-result (_req context result) (cl-defmethod jupyter-org--insert-result (req context result)
(when (eq (org-element-type result) 'pandoc)
(setq result (jupyter-org-pandoc-placeholder-element req result)))
(insert (org-element-interpret-data (insert (org-element-interpret-data
(jupyter-org--wrap-result-maybe (jupyter-org--wrap-result-maybe
context (if (jupyter-org--stream-result-p result) context (if (jupyter-org--stream-result-p result)
@ -1513,7 +1556,10 @@ RESULT is the new result, as an org element, to be inserted.")
(cond (cond
((jupyter-org-request-silent-p req) ((jupyter-org-request-silent-p req)
(unless (equal (jupyter-org-request-silent-p req) "none") (unless (equal (jupyter-org-request-silent-p req) "none")
(message "%s" (org-element-interpret-data result)))) (if (eq (org-element-type result) 'pandoc)
(message "[%s] %s" (org-element-property :type result)
(org-element-property :value result))
(message "%s" (org-element-interpret-data result)))))
((jupyter-org-request-async-p req) ((jupyter-org-request-async-p req)
(jupyter-org--clear-request-id req) (jupyter-org--clear-request-id req)
(jupyter-org--do-insert-result req result)) (jupyter-org--do-insert-result req result))
@ -1573,12 +1619,31 @@ example-block elements."
results results
:initial-value nil))))) :initial-value nil)))))
(defun jupyter-org--process-pandoc-results (results)
(let* ((results (copy-sequence results))
(head results)
(procs '()))
(while head
(when (eq (org-element-type (car head)) 'pandoc)
(push
(jupyter-org--start-pandoc-conversion
(car head)
(let ((h head))
(lambda ()
(setcar h (jupyter-org-raw-string (buffer-string))))))
procs))
(setq head (cdr head)))
(while (cl-find-if #'process-live-p procs)
(accept-process-output nil 0.1))
results))
(defun jupyter-org-sync-results (req) (defun jupyter-org-sync-results (req)
"Return the result string in org syntax for the results of REQ. "Return the result string in org syntax for the results of REQ.
Meant to be used as the return value of Meant to be used as the return value of
`org-babel-execute:jupyter'." `org-babel-execute:jupyter'."
(when-let* ((results (jupyter-org--coalesce-stream-results (when-let* ((results (jupyter-org--coalesce-stream-results
(nreverse (jupyter-org-request-results req)))) (jupyter-org--process-pandoc-results
(nreverse (jupyter-org-request-results req)))))
(params (jupyter-org-request-block-params req)) (params (jupyter-org-request-block-params req))
(result-params (alist-get :result-params params))) (result-params (alist-get :result-params params)))
(org-element-interpret-data (org-element-interpret-data

View file

@ -2929,6 +2929,51 @@ publish_display_data({'text/plain': \"foo\", 'text/latex': \"$\\alpha$\"});"
(forward-line) (forward-line)
(should (looking-at-p ": hello")))))) (should (looking-at-p ": hello"))))))
(ert-deftest org-babel-jupyter-pandoc-output-order ()
:tags '(org pandoc)
;; See #351
(ert-info ("Ensure output order doesn't depend on Pandoc processing time")
(ert-info ("Async")
(jupyter-org-test-src-block
"\
from IPython.display import HTML, Markdown, Latex
print(1)
display(HTML('<b>bold</b>'),
Latex('\\\\bf{lbold}'),
Markdown('**mbold**'))
print(2)"
"\
:RESULTS:
: 1
*bold*
*lbold*
*mbold*
: 2
:END:
"
:async "yes"
:pandoc "t"))
(ert-info ("Sync")
(jupyter-org-test-src-block
"\
from IPython.display import HTML, Markdown, Latex
print(1)
display(HTML('<b>bold</b>'),
Latex('\\\\bf{lbold}'),
Markdown('**mbold**'))
print(2)"
"\
:RESULTS:
: 1
*bold*
*lbold*
*mbold*
: 2
:END:
"
:pandoc "t"))))
;; Local Variables: ;; Local Variables:
;; byte-compile-warnings: (unresolved obsolete lexical) ;; byte-compile-warnings: (unresolved obsolete lexical)