Add jupyter-reply-message

This commit is contained in:
Nathaniel Nicandro 2020-11-22 17:19:23 -06:00
parent 52847c2f51
commit c1bff794d0
5 changed files with 121 additions and 131 deletions

View file

@ -1182,52 +1182,49 @@ DETAIL is the detail level to use for the request and defaults to
(object-of-class-p jupyter-current-client 'jupyter-kernel-client))
(error "Need a valid `jupyter-current-client'"))
(condition-case nil
(jupyter-mlet* ((msgs
(jupyter-messages
(jupyter-inspect-request
:code code
:pos pos
:detail detail)
jupyter-long-timeout)))
(when-let* ((msg (jupyter-find-message "inspect_reply" msgs)))
(jupyter-with-message-content msg
(status found)
(if (and (equal status "ok") (eq found t))
(let ((inhibit-read-only t))
(if (buffer-live-p buffer)
(with-current-buffer buffer
;; Insert MSG here so that `jupyter-insert'
;; has access to the message type. This is
;; needed since the python kernel and others
;; may use this information.
(jupyter-insert msg)
(current-buffer))
(with-help-window (help-buffer)
(with-current-buffer standard-output
(setq other-window-scroll-buffer (current-buffer))
(setq jupyter-current-client client)
(help-setup-xref
(list
;; Don't capture a strong reference to the
;; client object since we don't know when
;; this reference will be cleaned up.
(let ((ref (jupyter-weak-ref client)))
(lambda ()
(let ((jupyter-current-client
(jupyter-weak-ref-resolve ref)))
(if jupyter-current-client
(jupyter-inspect code pos nil detail)
;; TODO: Skip over this xref, need
;; to figure out if going forward or
;; backward first.
(error "Client has been removed"))))))
nil)
(jupyter-insert msg)))))
(message "Nothing found for %s"
(with-temp-buffer
(insert code)
(goto-char pos)
(symbol-at-point)))))))
(jupyter-mlet* ((msg (jupyter-reply-message
(jupyter-inspect-request
:code code
:pos pos
:detail detail))))
(jupyter-with-message-content msg
(status found)
(if (and (equal status "ok") (eq found t))
(let ((inhibit-read-only t))
(if (buffer-live-p buffer)
(with-current-buffer buffer
;; Insert MSG here so that `jupyter-insert'
;; has access to the message type. This is
;; needed since the python kernel and others
;; may use this information.
(jupyter-insert msg)
(current-buffer))
(with-help-window (help-buffer)
(with-current-buffer standard-output
(setq other-window-scroll-buffer (current-buffer))
(setq jupyter-current-client client)
(help-setup-xref
(list
;; Don't capture a strong reference to the
;; client object since we don't know when
;; this reference will be cleaned up.
(let ((ref (jupyter-weak-ref client)))
(lambda ()
(let ((jupyter-current-client
(jupyter-weak-ref-resolve ref)))
(if jupyter-current-client
(jupyter-inspect code pos nil detail)
;; TODO: Skip over this xref, need
;; to figure out if going forward or
;; backward first.
(error "Client has been removed"))))))
nil)
(jupyter-insert msg)))))
(message "Nothing found for %s"
(with-temp-buffer
(insert code)
(goto-char pos)
(symbol-at-point))))))
(jupyter-timeout-before-idle
(message "Inspect timed out"))))
@ -1686,19 +1683,18 @@ name are changed to \"-\" and all uppercase characters lowered."
(progn
(message "Requesting kernel info...")
(let ((jupyter-current-client client))
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-kernel-info-request
:handlers nil)
(* 3 jupyter-long-timeout))))
(jupyter-mlet* ((msg (jupyter-reply-message
(jupyter-kernel-info-request
:handlers nil)
(* 3 jupyter-long-timeout))))
(message "Requesting kernel info...done")
(let ((msg (jupyter-find-message "kernel_info_reply" msgs)))
(oset client kernel-info (jupyter-message-content msg))
;; Canonicalize language name to a language symbol for
;; method dispatching
(let* ((info (plist-get (oref client kernel-info) :language_info))
(lang (plist-get info :name))
(name (jupyter-canonicalize-language-string lang)))
(plist-put info :name (intern name))))))
(oset client kernel-info (jupyter-message-content msg))
;; Canonicalize language name to a language symbol for
;; method dispatching
(let* ((info (plist-get (oref client kernel-info) :language_info))
(lang (plist-get info :name))
(name (jupyter-canonicalize-language-string lang)))
(plist-put info :name (intern name)))))
(oref client kernel-info))))
(defun jupyter-kernel-language-mode-properties (client)

View file

@ -122,19 +122,18 @@ Make the character after `point' invisible."
If the Pkg prompt can't be retrieved from the kernel, return
nil."
(let ((prompt-code "import Pkg; Pkg.REPLMode.promptf()"))
(jupyter-mlet* ((msgs
(jupyter-messages
(jupyter-mlet* ((msg
(jupyter-reply-message
(jupyter-execute-request
:code ""
:silent t
:user-expressions (list :prompt prompt-code)))))
(when-let* ((msg (jupyter-find-message "execute_reply" msgs)))
(cl-destructuring-bind (&key prompt &allow-other-keys)
(jupyter-message-get msg :user_expressions)
(cl-destructuring-bind (&key status data &allow-other-keys)
prompt
(when (equal status "ok")
(plist-get data :text/plain))))))))
(cl-destructuring-bind (&key prompt &allow-other-keys)
(jupyter-message-get msg :user_expressions)
(cl-destructuring-bind (&key status data &allow-other-keys)
prompt
(when (equal status "ok")
(plist-get data :text/plain)))))))
(cl-defmethod jupyter-repl-after-change ((_type (eql insert)) beg _end
&context (jupyter-lang julia))

View file

@ -415,12 +415,15 @@ when it is idle."
(string= type msg-type)))
msgs))
(defun jupyter-reply-message (msgs)
(cl-find-if
(lambda (msg)
(let ((type (jupyter-message-type msg)))
(string-suffix-p "_reply" type)))
msgs))
(defun jupyter-reply-message (io-req &optional timeout)
(make-jupyter-delayed
:value (lambda ()
(jupyter-mlet* ((msgs (jupyter-messages io-req timeout)))
(cl-find-if
(lambda (msg)
(let ((type (jupyter-message-type msg)))
(string-suffix-p "_reply" type)))
msgs)))))
(defun jupyter-message-subscribed (io-req cbs)
(make-jupyter-delayed

View file

@ -1792,28 +1792,27 @@ it."
"Synchronize the `jupyter-current-client's kernel state.
Also update the cell count of the current REPL input prompt using
the updated state."
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-execute-request
:code ""
:silent t
:handlers nil)
;; Waiting longer here to account for initial
;; startup of the Jupyter kernel. Sometimes
;; the idle message won't be received if
;; another long running execute request is
;; sent right after.
jupyter-long-timeout)))
(when-let* ((msg (jupyter-find-message "execute_reply" msgs)))
(jupyter-with-message-content msg (execution_count)
(let ((client jupyter-current-client))
(oset client execution-count (1+ execution_count))
(unless (equal (jupyter-execution-state client) "busy")
;; Set the cell count and update the prompt
(jupyter-with-repl-buffer client
(save-excursion
(goto-char (point-max))
(jupyter-repl-update-cell-count
(oref client execution-count))))))))))
(jupyter-mlet* ((msg (jupyter-reply-message
(jupyter-execute-request
:code ""
:silent t
:handlers nil)
;; Waiting longer here to account for initial
;; startup of the Jupyter kernel. Sometimes
;; the idle message won't be received if
;; another long running execute request is
;; sent right after.
jupyter-long-timeout)))
(jupyter-with-message-content msg (execution_count)
(let ((client jupyter-current-client))
(oset client execution-count (1+ execution_count))
(unless (equal (jupyter-execution-state client) "busy")
;; Set the cell count and update the prompt
(jupyter-with-repl-buffer client
(save-excursion
(goto-char (point-max))
(jupyter-repl-update-cell-count
(oref client execution-count)))))))))
;;; `jupyter-repl-interaction-mode'

View file

@ -382,26 +382,23 @@
:tags '(client messages)
(jupyter-test-with-python-client client
(ert-info ("Kernel info")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((res (jupyter-reply-message
(jupyter-kernel-info-request))))
(let ((res (jupyter-reply-message msgs)))
(should res)
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "kernel_info_reply")))))
(should res)
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "kernel_info_reply"))))
(ert-info ("Comm info")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-comm-info-request))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "comm_info_reply")))))
(jupyter-mlet* ((res (jupyter-reply-message
(jupyter-comm-info-request))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "comm_info_reply"))))
(ert-info ("Execute")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((res (jupyter-reply-message
(jupyter-execute-request :code "y = 1 + 2"))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "execute_reply")))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "execute_reply"))))
(ert-info ("Input")
(cl-letf (((symbol-function 'read-from-minibuffer)
(lambda (_prompt &rest _args) "foo")))
@ -414,40 +411,36 @@
(should (string= (jupyter-message-type res) "execute_result"))
(should (equal (jupyter-message-data res :text/plain) "'foo'"))))))
(ert-info ("Inspect")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((res (jupyter-reply-message
(jupyter-inspect-request
:code "list((1, 2, 3))"
:pos 2
:detail 0))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "inspect_reply")))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "inspect_reply"))))
(ert-info ("Complete")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((res (jupyter-reply-message
(jupyter-complete-request
:code "foo = lis"
:pos 8))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "complete_reply")))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "complete_reply"))))
(ert-info ("History")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((msgs (jupyter-reply-message
(jupyter-history-request
:hist-access-type "tail" :n 2))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "history_reply")))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "history_reply"))))
(ert-info ("Is Complete")
(jupyter-mlet* ((msgs (jupyter-messages
(jupyter-mlet* ((msgs (jupyter-reply-message
(jupyter-is-complete-request
:code "for i in range(5):"))))
(let ((res (jupyter-reply-message msgs)))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "is_complete_reply")))))
(should-not (null res))
(should (json-plist-p res))
(should (string= (jupyter-message-type res) "is_complete_reply"))))
;; TODO: Why does this fail now?
;; (ert-info ("Shutdown")
;; (let ((res (jupyter-wait-until-received "shutdown_reply"