mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-06 07:51:39 -05:00
Add jupyter-return-delayed-thunk
This commit is contained in:
parent
3db7446f3a
commit
13935fe38f
1 changed files with 86 additions and 91 deletions
|
@ -47,15 +47,20 @@
|
||||||
|
|
||||||
(cl-defstruct jupyter-delayed value)
|
(cl-defstruct jupyter-delayed value)
|
||||||
|
|
||||||
(defconst jupyter-io-nil (make-jupyter-delayed :value (lambda () nil)))
|
|
||||||
|
|
||||||
(defvar jupyter-io-cache (make-hash-table :weakness 'key))
|
|
||||||
|
|
||||||
(defun jupyter-return-delayed (value)
|
(defun jupyter-return-delayed (value)
|
||||||
"Return an I/O value wrapping VALUE."
|
"Return an I/O value wrapping VALUE."
|
||||||
(declare (indent 0))
|
(declare (indent 0))
|
||||||
(make-jupyter-delayed :value (lambda () value)))
|
(make-jupyter-delayed :value (lambda () value)))
|
||||||
|
|
||||||
|
(defmacro jupyter-return-delayed-thunk (&rest body)
|
||||||
|
"Return an I/O value that evaluates BODY."
|
||||||
|
(declare (debug (body)) (indent 0))
|
||||||
|
`(make-jupyter-delayed :value (lambda () ,@body)))
|
||||||
|
|
||||||
|
(defconst jupyter-io-nil (jupyter-return-delayed nil))
|
||||||
|
|
||||||
|
(defvar jupyter-io-cache (make-hash-table :weakness 'key))
|
||||||
|
|
||||||
(defvar jupyter-current-io
|
(defvar jupyter-current-io
|
||||||
(lambda (content)
|
(lambda (content)
|
||||||
(error "Unhandled I/O: %s" content))
|
(error "Unhandled I/O: %s" content))
|
||||||
|
@ -107,11 +112,10 @@ Return the result of evaluating BODY."
|
||||||
The result of the returned action is the result of the I/O action
|
The result of the returned action is the result of the I/O action
|
||||||
BODY evaluates to."
|
BODY evaluates to."
|
||||||
(declare (indent 1) (debug (form body)))
|
(declare (indent 1) (debug (form body)))
|
||||||
`(make-jupyter-delayed
|
`(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(let ((jupyter-current-io ,io))
|
||||||
(let ((jupyter-current-io ,io))
|
(jupyter-mlet* ((result (progn ,@body)))
|
||||||
(jupyter-mlet* ((result (progn ,@body)))
|
result))))
|
||||||
result)))))
|
|
||||||
|
|
||||||
(defmacro jupyter-run-with-io (io &rest body)
|
(defmacro jupyter-run-with-io (io &rest body)
|
||||||
"Return the result of evaluating the I/O value BODY evaluates to.
|
"Return the result of evaluating the I/O value BODY evaluates to.
|
||||||
|
@ -146,11 +150,10 @@ returned action is the result of the last action in IO-ACTIONS."
|
||||||
"Return an I/O action that performs IO-A then IO-B.
|
"Return an I/O action that performs IO-A then IO-B.
|
||||||
The result of the returned action is the result of IO-B."
|
The result of the returned action is the result of IO-B."
|
||||||
(declare (indent 1))
|
(declare (indent 1))
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(jupyter-mlet* ((_ io-a)
|
||||||
(jupyter-mlet* ((_ io-a)
|
(result io-b))
|
||||||
(result io-b))
|
result)))
|
||||||
result))))
|
|
||||||
|
|
||||||
;;; Publisher/subscriber
|
;;; Publisher/subscriber
|
||||||
|
|
||||||
|
@ -296,18 +299,16 @@ Ex. Subscribe to a publisher and unsubscribe after receiving two
|
||||||
(jupyter-publish x)))
|
(jupyter-publish x)))
|
||||||
(reverse msgs)) ; => '(1 2)"
|
(reverse msgs)) ; => '(1 2)"
|
||||||
(declare (indent 0))
|
(declare (indent 0))
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(funcall jupyter-current-io (list 'subscribe sub))
|
||||||
(funcall jupyter-current-io (list 'subscribe sub))
|
nil))
|
||||||
nil)))
|
|
||||||
|
|
||||||
(defun jupyter-publish (value)
|
(defun jupyter-publish (value)
|
||||||
"Return an I/O action that submits VALUE to publish as content."
|
"Return an I/O action that submits VALUE to publish as content."
|
||||||
(declare (indent 0))
|
(declare (indent 0))
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(funcall jupyter-current-io (jupyter-content value))
|
||||||
(funcall jupyter-current-io (jupyter-content value))
|
nil))
|
||||||
nil)))
|
|
||||||
|
|
||||||
;;; Working with requests
|
;;; Working with requests
|
||||||
|
|
||||||
|
@ -319,21 +320,20 @@ Evaluate IO-REQ, an IO action that results in a sent request, and
|
||||||
wait for that request to become idle. Signal a
|
wait for that request to become idle. Signal a
|
||||||
`jupyter-timeout-before-idle' error if TIMEOUT seconds elapses
|
`jupyter-timeout-before-idle' error if TIMEOUT seconds elapses
|
||||||
and the request has not become idle yet."
|
and the request has not become idle yet."
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(jupyter-mlet* ((req io-req))
|
||||||
(jupyter-mlet* ((req io-req))
|
(or (jupyter-wait-until-idle req timeout)
|
||||||
(or (jupyter-wait-until-idle req timeout)
|
(signal 'jupyter-timeout-before-idle (list req)))
|
||||||
(signal 'jupyter-timeout-before-idle (list req)))
|
req)))
|
||||||
req))))
|
|
||||||
|
|
||||||
(defun jupyter-messages (io-req &optional timeout)
|
(defun jupyter-messages (io-req &optional timeout)
|
||||||
"Return an IO action that returns the messages of IO-REQ.
|
"Return an IO action that returns the messages of IO-REQ.
|
||||||
IO-REQ is an IO action that evaluates to a sent request. TIMEOUT
|
IO-REQ is an IO action that evaluates to a sent request. TIMEOUT
|
||||||
has the same meaning as in `jupyter-idle'."
|
has the same meaning as in `jupyter-idle'."
|
||||||
(make-jupyter-delayed
|
(let ((idle-req (jupyter-idle io-req timeout)))
|
||||||
:value (lambda ()
|
(jupyter-return-delayed-thunk
|
||||||
(jupyter-mlet* ((req (jupyter-idle io-req timeout)))
|
(jupyter-mlet* ((req idle-req))
|
||||||
(jupyter-request-messages req)))))
|
(jupyter-request-messages req)))))
|
||||||
|
|
||||||
(defun jupyter-find-message (msg-type msgs)
|
(defun jupyter-find-message (msg-type msgs)
|
||||||
"Return a message whose type is MSG-TYPE in MSGS."
|
"Return a message whose type is MSG-TYPE in MSGS."
|
||||||
|
@ -347,14 +347,13 @@ has the same meaning as in `jupyter-idle'."
|
||||||
"Return an IO action that returns the reply message of IO-REQ.
|
"Return an IO action that returns the reply message of IO-REQ.
|
||||||
IO-REQ is an IO action that evaluates to a sent request. TIMEOUT
|
IO-REQ is an IO action that evaluates to a sent request. TIMEOUT
|
||||||
has the same meaning as in `jupyter-idle'."
|
has the same meaning as in `jupyter-idle'."
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(jupyter-mlet* ((msgs (jupyter-messages io-req timeout)))
|
||||||
(jupyter-mlet* ((msgs (jupyter-messages io-req timeout)))
|
(cl-find-if
|
||||||
(cl-find-if
|
(lambda (msg)
|
||||||
(lambda (msg)
|
(let ((type (jupyter-message-type msg)))
|
||||||
(let ((type (jupyter-message-type msg)))
|
(string-suffix-p "_reply" type)))
|
||||||
(string-suffix-p "_reply" type)))
|
msgs))))
|
||||||
msgs)))))
|
|
||||||
|
|
||||||
(defun jupyter-message-subscribed (io-req cbs)
|
(defun jupyter-message-subscribed (io-req cbs)
|
||||||
"Return an IO action that subscribes CBS to a request's message publisher.
|
"Return an IO action that subscribes CBS to a request's message publisher.
|
||||||
|
@ -366,19 +365,18 @@ an alist mapping message types to callback functions like
|
||||||
|
|
||||||
The returned IO action returns the sent request after subscribing
|
The returned IO action returns the sent request after subscribing
|
||||||
the callbacks."
|
the callbacks."
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(jupyter-mlet* ((req io-req))
|
||||||
(jupyter-mlet* ((req io-req))
|
(jupyter-run-with-io
|
||||||
(jupyter-run-with-io
|
(jupyter-request-message-publisher req)
|
||||||
(jupyter-request-message-publisher req)
|
(jupyter-subscribe
|
||||||
(jupyter-subscribe
|
(jupyter-subscriber
|
||||||
(jupyter-subscriber
|
(lambda (msg)
|
||||||
(lambda (msg)
|
(when-let*
|
||||||
(when-let*
|
((msg-type (jupyter-message-type msg))
|
||||||
((msg-type (jupyter-message-type msg))
|
(fn (car (alist-get msg-type cbs nil nil #'string=))))
|
||||||
(fn (car (alist-get msg-type cbs nil nil #'string=))))
|
(funcall fn msg))))))
|
||||||
(funcall fn msg))))))
|
req)))
|
||||||
req))))
|
|
||||||
|
|
||||||
(defun jupyter-client-subscribed (io-req)
|
(defun jupyter-client-subscribed (io-req)
|
||||||
"Return an IO action that subscribes a client to a request's message publisher.
|
"Return an IO action that subscribes a client to a request's message publisher.
|
||||||
|
@ -388,22 +386,21 @@ of evaluation of the action.
|
||||||
|
|
||||||
The returned IO action returns the sent request after subscribing
|
The returned IO action returns the sent request after subscribing
|
||||||
the client."
|
the client."
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value (lambda ()
|
(jupyter-with-client jupyter-current-client
|
||||||
(jupyter-with-client jupyter-current-client
|
(let ((client jupyter-current-client))
|
||||||
(let ((client jupyter-current-client))
|
(jupyter-mlet* ((req io-req))
|
||||||
(jupyter-mlet* ((req io-req))
|
(when (string= (jupyter-request-type req)
|
||||||
(when (string= (jupyter-request-type req)
|
"execute_request")
|
||||||
"execute_request")
|
(jupyter-server-mode-set-client client))
|
||||||
(jupyter-server-mode-set-client client))
|
(jupyter-run-with-io
|
||||||
(jupyter-run-with-io
|
(jupyter-request-message-publisher req)
|
||||||
(jupyter-request-message-publisher req)
|
(jupyter-subscribe
|
||||||
(jupyter-subscribe
|
(jupyter-subscriber
|
||||||
(jupyter-subscriber
|
(lambda (msg)
|
||||||
(lambda (msg)
|
(let ((channel (plist-get msg :channel)))
|
||||||
(let ((channel (plist-get msg :channel)))
|
(jupyter-handle-message client channel msg))))))
|
||||||
(jupyter-handle-message client channel msg))))))
|
req)))))
|
||||||
req))))))
|
|
||||||
|
|
||||||
;;; Request
|
;;; Request
|
||||||
|
|
||||||
|
@ -458,28 +455,26 @@ the client."
|
||||||
(ch (if (member type '("input_reply" "input_request"))
|
(ch (if (member type '("input_reply" "input_request"))
|
||||||
"stdin"
|
"stdin"
|
||||||
"shell")))
|
"shell")))
|
||||||
(make-jupyter-delayed
|
(jupyter-return-delayed-thunk
|
||||||
:value
|
(let ((req (jupyter-generate-request
|
||||||
(lambda ()
|
jupyter-current-client
|
||||||
(let ((req (jupyter-generate-request
|
:type type
|
||||||
jupyter-current-client
|
:content content
|
||||||
:type type
|
:client jupyter-current-client
|
||||||
:content content
|
;; Anything sent to stdin is a reply not a request
|
||||||
:client jupyter-current-client
|
;; so consider the "request" completed.
|
||||||
;; Anything sent to stdin is a reply not a request
|
:idle-p (string= ch "stdin")
|
||||||
;; so consider the "request" completed.
|
:inhibited-handlers ih)))
|
||||||
:idle-p (string= ch "stdin")
|
(setf (jupyter-request-message-publisher req)
|
||||||
:inhibited-handlers ih)))
|
(jupyter-message-publisher req))
|
||||||
(setf (jupyter-request-message-publisher req)
|
(jupyter-mlet*
|
||||||
(jupyter-message-publisher req))
|
((_ (jupyter-do
|
||||||
(jupyter-mlet*
|
(jupyter-subscribe
|
||||||
((_ (jupyter-do
|
(jupyter-request-message-publisher req))
|
||||||
(jupyter-subscribe
|
(jupyter-publish
|
||||||
(jupyter-request-message-publisher req))
|
(list 'send ch type content
|
||||||
(jupyter-publish
|
(jupyter-request-id req)))))))
|
||||||
(list 'send ch type content
|
req))))
|
||||||
(jupyter-request-id req)))))))
|
|
||||||
req)))))
|
|
||||||
|
|
||||||
(cl-defun jupyter-request (type &rest content)
|
(cl-defun jupyter-request (type &rest content)
|
||||||
"Return an IO action that sends a `jupyter-request'.
|
"Return an IO action that sends a `jupyter-request'.
|
||||||
|
|
Loading…
Add table
Reference in a new issue