feat(org): add native :async support

ob-comint (included with org) added native :async support. It only works
for python currently, but unlike ob-async supports :session for :async
python blocks. In fact, it *requires* :session, so we still fall back to
ob-async in its absence, failing that, it ultimately falls back to
synchronous execution.
This commit is contained in:
Henrik Lissner 2021-07-28 15:00:35 -04:00
parent c48c01ebab
commit 7b274c7dbe

View file

@ -1,5 +1,8 @@
;;; lang/org/config.el -*- lexical-binding: t; -*-
(defvar +org-babel-native-async-langs '(python)
"Languages that will use `ob-comint' instead of `ob-async' for `:async'.")
(defvar +org-babel-mode-alist
'((c . C)
(cpp . C)
@ -215,12 +218,16 @@ Is relative to `org-directory', unless it is absolute. Is used in Doom's default
(after! ob
(add-to-list 'org-babel-default-lob-header-args '(:sync)))
(defadvice! +org-babel-disable-async-if-needed-a (orig-fn &optional fn arg info params)
"Disable ob-async when leaving it on would cause errors or issues.
(defadvice! +org-babel-disable-async-maybe-a (orig-fn &optional fn arg info params)
"Use ob-comint where supported, disable async altogether where it isn't.
Such as when exporting org documents or executing babel blocks with :session
parameters (which ob-async does not support), in which case this advice forces
these blocks to run synchronously.
We have access to two async backends: ob-comint or ob-async, which have
different requirements. This advice tries to pick the best option between them,
falling back to synchronous execution otherwise. Without this advice, they die
with an error; terrible UX!
Note: ob-comint support will only kick in for languages listed in
`+org-babel-native-async-langs'.
Also adds support for a `:sync' parameter to override `:async'."
:around #'ob-async-org-babel-execute-src-block
@ -228,14 +235,24 @@ Also adds support for a `:sync' parameter to override `:async'."
(funcall orig-fn fn arg info params)
(let* ((info (or info (org-babel-get-src-block-info)))
(params (org-babel-merge-params (nth 2 info) params)))
(cond ((or (assq :sync params)
(not (assq :async params))
(member (car info) ob-async-no-async-languages-alist))
(funcall fn arg info params))
((not (member (cdr (assq :session params)) '("none" nil)))
(message "Org babel :: :session is incompatible with :async. Executing synchronously!")
nil)
((funcall orig-fn fn arg info params))))))
(if (or (assq :sync params)
(not (assq :async params))
(member (car info) ob-async-no-async-languages-alist)
;; ob-comint requires a :session, ob-async does not, so fall
;; back to ob-async if no :session is provided.
(unless (member (alist-get :session params) '("none" nil))
(unless (memq (let* ((lang (nth 0 info))
(lang (cond ((symbolp lang) lang)
((stringp lang) (intern lang)))))
(or (alist-get lang +org-babel-mode-alist)
lang))
+org-babel-native-async-langs)
(message "Org babel: %s :session is incompatible with :async. Executing synchronously!"
(car info))
(sleep-for 0.2))
t))
(funcall fn arg info params)
(funcall orig-fn fn arg info params)))))
(defadvice! +org-fix-newline-and-indent-in-src-blocks-a (&optional indent _arg _interactive)
"Mimic `newline-and-indent' in src blocks w/ lang-appropriate indentation."