2018-01-08 21:38:32 -06:00
|
|
|
;;; jupyter-client.el --- A Jupyter kernel client -*- lexical-binding: t -*-
|
|
|
|
|
2020-04-07 15:13:51 -05:00
|
|
|
;; Copyright (C) 2018-2020 Nathaniel Nicandro
|
2018-01-08 21:38:32 -06:00
|
|
|
|
|
|
|
;; Author: Nathaniel Nicandro <nathanielnicandro@gmail.com>
|
|
|
|
;; Created: 06 Jan 2018
|
|
|
|
|
|
|
|
;; This program is free software; you can redistribute it and/or
|
|
|
|
;; modify it under the terms of the GNU General Public License as
|
2019-05-31 09:44:39 -05:00
|
|
|
;; published by the Free Software Foundation; either version 3, or (at
|
2018-01-08 21:38:32 -06:00
|
|
|
;; your option) any later version.
|
|
|
|
|
|
|
|
;; This program is distributed in the hope that it will be useful, but
|
|
|
|
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
;; General Public License for more details.
|
|
|
|
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
|
|
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
|
|
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
|
|
;; Boston, MA 02111-1307, USA.
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
2019-02-06 18:09:09 -06:00
|
|
|
;; The default implementation of a Jupyter kernel client.
|
2018-01-08 21:38:32 -06:00
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
2018-01-12 17:51:16 -06:00
|
|
|
(defgroup jupyter-client nil
|
|
|
|
"A Jupyter client."
|
|
|
|
:group 'jupyter)
|
|
|
|
|
2019-03-10 19:53:54 -05:00
|
|
|
(eval-when-compile (require 'subr-x))
|
2018-01-04 23:03:18 -06:00
|
|
|
(require 'jupyter-base)
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(require 'jupyter-comm-layer)
|
2018-11-17 16:29:59 -06:00
|
|
|
(require 'jupyter-mime)
|
2017-12-13 11:27:13 -06:00
|
|
|
(require 'jupyter-messages)
|
2018-01-22 19:12:47 -06:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(defface jupyter-eval-overlay
|
|
|
|
'((((class color) (min-colors 88) (background light))
|
|
|
|
:foreground "navy"
|
|
|
|
:weight bold)
|
|
|
|
(((class color) (min-colors 88) (background dark))
|
|
|
|
:foreground "dodger blue"
|
|
|
|
:weight bold))
|
|
|
|
"Face used for the input prompt."
|
|
|
|
:group 'jupyter-client)
|
|
|
|
|
|
|
|
(defcustom jupyter-eval-use-overlays nil
|
|
|
|
"Display evaluation results as overlays in the `current-buffer'.
|
|
|
|
If this variable is non-nil, evaluation results are displayed as
|
|
|
|
overlays at the end of the line if possible."
|
|
|
|
:group 'jupyter-client
|
|
|
|
:type 'boolean)
|
|
|
|
|
2019-10-13 22:39:49 +02:00
|
|
|
(defcustom jupyter-eval-overlay-prefix "=> "
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
"Evaluation result overlays will be prefixed with this string."
|
|
|
|
:group 'jupyter-client
|
|
|
|
:type 'string)
|
|
|
|
|
2019-03-13 17:04:20 -05:00
|
|
|
(defcustom jupyter-eval-short-result-display-function
|
|
|
|
(lambda (result) (message "%s" result))
|
2019-02-09 02:28:54 +01:00
|
|
|
"Function for displaying short evaluation results.
|
|
|
|
Evaluation results are considered short when they are less than
|
2019-02-10 02:25:05 -06:00
|
|
|
`jupyter-eval-short-result-max-lines' long.
|
2019-02-09 02:28:54 +01:00
|
|
|
|
2019-02-10 02:25:05 -06:00
|
|
|
The default function is `message', but any function that takes a
|
2020-03-11 20:50:52 +09:00
|
|
|
single string argument can be used. For example, to display the
|
2019-02-10 02:25:05 -06:00
|
|
|
result in a tooltip, the variable can be set to `popup-tip' from
|
|
|
|
the `popup' package."
|
2019-02-09 02:28:54 +01:00
|
|
|
:group 'jupyter-client
|
|
|
|
:type 'function)
|
|
|
|
|
|
|
|
(defcustom jupyter-eval-short-result-max-lines 10
|
2019-02-10 02:25:05 -06:00
|
|
|
"Maximum number of lines for short evaluation results.
|
|
|
|
Short evaluation results are displayed using
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-eval-short-result-display-function'. Longer results are
|
2019-02-09 02:28:54 +01:00
|
|
|
forwarded to a separate buffer."
|
|
|
|
:group 'jupyter-client
|
|
|
|
:type 'integer)
|
|
|
|
|
2019-06-28 20:02:00 -05:00
|
|
|
(defcustom jupyter-include-other-output nil
|
|
|
|
"Whether or not to handle IOPub messages from other clients.
|
|
|
|
A Jupyter client can receive messages from other clients
|
2020-03-11 20:50:52 +09:00
|
|
|
connected to the same kernel on the IOPub channel. You can choose
|
2019-06-28 20:02:00 -05:00
|
|
|
to ignore these messages by setting
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-include-other-output' to nil. If
|
2019-06-28 20:02:00 -05:00
|
|
|
`jupyter-include-other-output' is non-nil, then any messages that
|
|
|
|
are not associated with a request from a client are sent to the
|
|
|
|
client's handler methods with a nil value for the request
|
2020-03-11 20:50:52 +09:00
|
|
|
argument. To change the value of this variable for a particular
|
2019-06-28 20:02:00 -05:00
|
|
|
client use `jupyter-set'."
|
|
|
|
:group 'jupyter
|
|
|
|
:type 'boolean)
|
|
|
|
|
|
|
|
(defcustom jupyter-iopub-message-hook nil
|
|
|
|
"Hook run when a message is received on the IOPub channel.
|
|
|
|
The hook is called with two arguments, the Jupyter client and the
|
|
|
|
message it received.
|
|
|
|
|
|
|
|
Do not add to this hook variable directly, use
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-add-hook'. If any of the message hooks return a non-nil
|
2019-06-28 20:02:00 -05:00
|
|
|
value, the client handlers will be prevented from running for the
|
|
|
|
message."
|
|
|
|
:group 'jupyter
|
|
|
|
:type 'hook)
|
|
|
|
(put 'jupyter-iopub-message-hook 'permanent-local t)
|
|
|
|
|
|
|
|
(defcustom jupyter-shell-message-hook nil
|
|
|
|
"Hook run when a message is received on the SHELL channel.
|
|
|
|
The hook is called with two arguments, the Jupyter client and the
|
|
|
|
message it received.
|
|
|
|
|
|
|
|
Do not add to this hook variable directly, use
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-add-hook'. If any of the message hooks return a non-nil
|
2019-06-28 20:02:00 -05:00
|
|
|
value, the client handlers will be prevented from running for the
|
|
|
|
message."
|
|
|
|
:group 'jupyter
|
|
|
|
:type 'hook)
|
|
|
|
(put 'jupyter-shell-message-hook 'permanent-local t)
|
|
|
|
|
|
|
|
(defcustom jupyter-stdin-message-hook nil
|
|
|
|
"Hook run when a message is received on the STDIN channel.
|
|
|
|
The hook is called with two arguments, the Jupyter client and the
|
|
|
|
message it received.
|
|
|
|
|
|
|
|
Do not add to this hook variable directly,
|
2020-03-11 20:50:52 +09:00
|
|
|
use `jupyter-add-hook'. If any of the message hooks return a
|
2019-06-28 20:02:00 -05:00
|
|
|
non-nil value, the client handlers will be prevented from running
|
|
|
|
for the message."
|
|
|
|
:group 'jupyter
|
|
|
|
:type 'hook)
|
|
|
|
(put 'jupyter-stdin-message-hook 'permanent-local t)
|
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
(declare-function company-begin-backend "ext:company" (backend &optional callback))
|
|
|
|
(declare-function company-doc-buffer "ext:company" (&optional string))
|
2018-11-19 22:16:04 -06:00
|
|
|
(declare-function company-idle-begin "ext:company")
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
(declare-function yas-minor-mode "ext:yasnippet" (&optional arg))
|
|
|
|
(declare-function yas-expand-snippet "ext:yasnippet" (content &optional start end expand-env))
|
|
|
|
|
2018-11-14 13:12:43 -06:00
|
|
|
(declare-function jupyter-insert "jupyter-mime")
|
2018-01-04 20:58:28 -06:00
|
|
|
|
2018-09-16 23:01:54 -05:00
|
|
|
;; This is mainly used by the REPL code, but is also set by
|
|
|
|
;; the `org-mode' client whenever `point' is inside a code
|
|
|
|
;; block.
|
|
|
|
(defvar jupyter-current-client nil
|
2018-11-14 18:51:50 -06:00
|
|
|
"The kernel client for the `current-buffer'.
|
|
|
|
This is also let bound whenever a message is handled by a
|
|
|
|
kernel.")
|
2018-09-16 23:01:54 -05:00
|
|
|
|
|
|
|
(put 'jupyter-current-client 'permanent-local t)
|
|
|
|
(make-variable-buffer-local 'jupyter-current-client)
|
|
|
|
|
2018-01-17 20:28:46 -06:00
|
|
|
(defvar jupyter-inhibit-handlers nil
|
2018-08-27 20:46:58 -05:00
|
|
|
"Whether or not new requests inhibit client handlers.
|
|
|
|
If set to t, prevent new requests from running any of the client
|
2020-03-11 20:50:52 +09:00
|
|
|
handler methods. If set to a list of `jupyter-message-types',
|
2018-08-27 20:46:58 -05:00
|
|
|
prevent handler methods from running only for those message
|
|
|
|
types.
|
|
|
|
|
|
|
|
For example to prevent a client from calling its :execute-reply
|
|
|
|
handler:
|
2018-02-08 13:38:27 -06:00
|
|
|
|
|
|
|
(let ((jupyter-inhibit-handlers '(:execute-reply)))
|
2018-05-15 23:40:09 -05:00
|
|
|
(jupyter-send-execute-request client ...))
|
2018-02-08 13:38:27 -06:00
|
|
|
|
2018-10-18 12:45:00 -05:00
|
|
|
In addition, if the first element of the list is the symbol
|
|
|
|
`not', then inhibit handlers not in the list.
|
|
|
|
|
2018-08-27 20:46:58 -05:00
|
|
|
Do not set this variable directly, let bind it around specific
|
|
|
|
requests like the above example.")
|
2018-01-12 17:54:15 -06:00
|
|
|
|
2018-11-13 18:21:11 -06:00
|
|
|
(defvar jupyter--clients nil)
|
|
|
|
|
2018-02-03 00:02:33 -06:00
|
|
|
;; Define channel classes for method dispatching based on the channel type
|
|
|
|
|
2018-11-13 18:21:11 -06:00
|
|
|
(defclass jupyter-kernel-client (jupyter-finalized-object
|
|
|
|
jupyter-instance-tracker)
|
|
|
|
((tracking-symbol :initform 'jupyter--clients)
|
2018-11-11 13:42:43 -06:00
|
|
|
(execution-state
|
|
|
|
:type string
|
|
|
|
:initform "idle"
|
2020-03-11 20:50:52 +09:00
|
|
|
:documentation "The current state of the kernel. Can be
|
2018-11-11 13:42:43 -06:00
|
|
|
either \"idle\", \"busy\", or \"starting\".")
|
2019-01-13 13:44:32 -06:00
|
|
|
(execution-count
|
|
|
|
:type integer
|
|
|
|
:initform 1
|
|
|
|
:documentation "The *next* execution count of the kernel.
|
|
|
|
I.e., the execution count that will be assigned to the
|
|
|
|
next :execute-request sent to the kernel.")
|
2018-05-20 12:09:00 -05:00
|
|
|
(requests
|
2017-12-13 11:27:13 -06:00
|
|
|
:type hash-table
|
2017-12-15 22:26:21 -06:00
|
|
|
:initform (make-hash-table :test 'equal)
|
2018-09-09 21:33:05 -05:00
|
|
|
:documentation "A hash table with message ID's as keys.
|
|
|
|
This is used to register callback functions to run once a reply
|
2020-03-11 20:50:52 +09:00
|
|
|
from a previously sent request is received. See
|
|
|
|
`jupyter-add-callback'. Note that this is also used to filter
|
2018-09-09 21:33:05 -05:00
|
|
|
received messages that originated from a previous request by this
|
2020-03-11 20:50:52 +09:00
|
|
|
client. Whenever the client sends a message in which a reply is
|
2018-09-09 21:33:05 -05:00
|
|
|
expected, it sets an entry in this table to represent the fact
|
2020-03-11 20:50:52 +09:00
|
|
|
that the message has been sent. So if there is a non-nil value
|
2018-09-09 21:33:05 -05:00
|
|
|
for a message ID it means that a message has been sent and the
|
|
|
|
client is expecting a reply from the kernel.")
|
2018-09-16 21:17:10 -05:00
|
|
|
(kernel-info
|
|
|
|
:type json-plist
|
|
|
|
:initform nil
|
|
|
|
:documentation "The saved kernel info created when first
|
2020-03-11 20:50:52 +09:00
|
|
|
initializing this client. When `jupyter-start-channels' is
|
2018-09-16 21:17:10 -05:00
|
|
|
called, this will be set to the kernel info plist returned
|
|
|
|
from an initial `:kernel-info-request'.")
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(kcomm
|
|
|
|
:type jupyter-comm-layer
|
2018-09-09 21:33:05 -05:00
|
|
|
:documentation "The process which receives events from channels.")
|
2018-05-06 23:38:09 -05:00
|
|
|
(session
|
|
|
|
:type jupyter-session
|
|
|
|
:documentation "The session for this client.")
|
2018-05-26 20:01:29 -05:00
|
|
|
(comms
|
|
|
|
:type hash-table
|
|
|
|
:initform (make-hash-table :test 'equal)
|
2018-09-09 21:33:05 -05:00
|
|
|
:documentation "A hash table with comm ID's as keys.
|
2020-03-11 20:50:52 +09:00
|
|
|
Contains all of the open comms. Each value is a cons cell (REQ .
|
2018-09-09 21:33:05 -05:00
|
|
|
DATA) which contains the generating `jupyter-request' that caused
|
|
|
|
the comm to open and the initial DATA passed to the comm for
|
2018-05-26 20:01:29 -05:00
|
|
|
initialization.")
|
2018-05-06 23:38:09 -05:00
|
|
|
(manager
|
|
|
|
:initform nil
|
|
|
|
:documentation "If this client was initialized using a
|
|
|
|
`jupyter-kernel-manager' this slot will hold the manager which
|
|
|
|
initialized the client.")
|
2018-01-16 12:05:53 -06:00
|
|
|
(-buffer
|
|
|
|
:type buffer
|
|
|
|
:documentation "An internal buffer used to store client local
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
variables.")))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-10-01 23:11:30 -05:00
|
|
|
;;; `jupyter-current-client' language method specializer
|
|
|
|
|
2019-03-07 22:22:51 -06:00
|
|
|
(defvar jupyter--generic-lang-used (make-hash-table :test #'eq))
|
2018-10-01 23:11:30 -05:00
|
|
|
|
|
|
|
(cl-generic-define-generalizer jupyter--generic-lang-generalizer
|
|
|
|
50 (lambda (name &rest _)
|
2018-10-17 01:17:05 -05:00
|
|
|
`(when (and ,name (object-of-class-p ,name 'jupyter-kernel-client))
|
2019-03-07 22:22:51 -06:00
|
|
|
(gethash (jupyter-kernel-language ,name) jupyter--generic-lang-used)))
|
2018-10-01 23:11:30 -05:00
|
|
|
(lambda (tag &rest _)
|
|
|
|
(and (eq (car-safe tag) 'jupyter-lang)
|
|
|
|
(list tag))))
|
|
|
|
|
2018-09-17 19:15:28 -05:00
|
|
|
(cl-generic-define-context-rewriter jupyter-lang (lang)
|
2018-10-01 23:11:30 -05:00
|
|
|
`(jupyter-current-client (jupyter-lang ,lang)))
|
|
|
|
|
|
|
|
(cl-defmethod cl-generic-generalizers ((specializer (head jupyter-lang)))
|
|
|
|
"Support for (jupyter-lang LANG) specializers.
|
|
|
|
Matches if the kernel language of the `jupyter-kernel-client'
|
|
|
|
passed as the argument has a language of LANG."
|
|
|
|
(puthash (cadr specializer) specializer jupyter--generic-lang-used)
|
|
|
|
(list jupyter--generic-lang-generalizer))
|
2018-09-17 19:15:28 -05:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;; Initializing a `jupyter-kernel-client'
|
|
|
|
|
2019-08-08 19:53:27 -05:00
|
|
|
(defun jupyter-client-has-manager-p (&optional client)
|
|
|
|
"Return non-nil if CLIENT's kernel has a kernel manager.
|
|
|
|
CLIENT defaults to `jupyter-current-client'."
|
|
|
|
(or client (setq client jupyter-current-client))
|
|
|
|
(when client
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(and (oref client manager) t)))
|
|
|
|
|
2019-05-09 10:54:40 -05:00
|
|
|
(cl-defmethod initialize-instance ((client jupyter-kernel-client) &optional _slots)
|
2018-01-16 12:05:53 -06:00
|
|
|
(cl-call-next-method)
|
2018-11-12 10:22:00 -06:00
|
|
|
(let ((buffer (generate-new-buffer " *jupyter-kernel-client*")))
|
|
|
|
(oset client -buffer buffer)
|
|
|
|
(jupyter-add-finalizer client
|
|
|
|
(lambda ()
|
|
|
|
(when (buffer-live-p buffer)
|
2018-11-14 01:29:13 -06:00
|
|
|
(kill-buffer buffer))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(jupyter-stop-channels client)))))
|
2018-10-16 13:28:45 -05:00
|
|
|
|
2019-08-08 19:57:06 -05:00
|
|
|
(cl-defmethod jupyter-kernel-alive-p ((client jupyter-kernel-client))
|
|
|
|
"Return non-nil if the kernel CLIENT is connected to is alive."
|
|
|
|
(or (and (jupyter-client-has-manager-p client)
|
|
|
|
(jupyter-kernel-alive-p (oref client manager)))
|
|
|
|
(jupyter-hb-beating-p client)))
|
|
|
|
|
2018-11-07 13:20:43 -06:00
|
|
|
(defun jupyter-clients ()
|
2019-06-25 09:33:08 -05:00
|
|
|
"Return a list of all `jupyter-kernel-client' objects."
|
2018-11-13 18:21:11 -06:00
|
|
|
(jupyter-all-objects 'jupyter--clients))
|
2018-11-07 13:20:43 -06:00
|
|
|
|
2018-05-20 12:09:00 -05:00
|
|
|
(defun jupyter-find-client-for-session (session-id)
|
2018-11-14 18:51:50 -06:00
|
|
|
"Return the kernel client whose session has SESSION-ID."
|
2018-11-12 10:22:00 -06:00
|
|
|
(or (cl-find-if
|
|
|
|
(lambda (x) (string= (jupyter-session-id (oref x session)) session-id))
|
|
|
|
(jupyter-clients))
|
2018-05-20 12:09:00 -05:00
|
|
|
(error "No client found for session (%s)" session-id)))
|
|
|
|
|
2019-03-23 18:31:35 -05:00
|
|
|
(defun jupyter--connection-info (info-or-session)
|
|
|
|
"Return the connection plist according to INFO-OR-SESSION.
|
2020-03-18 12:44:51 -05:00
|
|
|
See `jupyter-comm-initialize'."
|
2019-03-23 18:31:35 -05:00
|
|
|
(cond
|
|
|
|
((jupyter-session-p info-or-session)
|
|
|
|
(jupyter-session-conn-info info-or-session))
|
|
|
|
((json-plist-p info-or-session) info-or-session)
|
|
|
|
((stringp info-or-session)
|
|
|
|
(if (file-remote-p info-or-session)
|
|
|
|
;; TODO: Don't tunnel if a tunnel already exists
|
|
|
|
(jupyter-tunnel-connection info-or-session)
|
|
|
|
(unless (file-exists-p info-or-session)
|
|
|
|
(error "File does not exist (%s)" info-or-session))
|
|
|
|
(jupyter-read-plist info-or-session)))
|
|
|
|
(t (signal 'wrong-type-argument
|
|
|
|
(list info-or-session
|
|
|
|
'(or jupyter-session-p json-plist-p stringp))))))
|
|
|
|
|
2019-05-31 14:55:00 -05:00
|
|
|
;; FIXME: This requires that CLIENT is communicating with a kernel using a
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
;; `jupyter-channel-ioloop-comm' object.
|
2020-03-18 12:44:51 -05:00
|
|
|
(cl-defmethod jupyter-comm-initialize ((client jupyter-kernel-client) info-or-session)
|
2018-05-15 19:25:03 -05:00
|
|
|
"Initialize CLIENT with connection INFO-OR-SESSION.
|
2018-09-09 21:33:05 -05:00
|
|
|
INFO-OR-SESSION can be a file name, a plist, or a
|
|
|
|
`jupyter-session' object that will be used to initialize CLIENT's
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
connection.
|
2019-03-23 18:31:35 -05:00
|
|
|
|
|
|
|
When INFO-OR-SESSION is a file name, read the contents of the
|
|
|
|
file as a JSON plist and create a new `jupyter-session' from it.
|
|
|
|
For remote files, create a new `jupyter-session' based on the
|
|
|
|
plist returned from `jupyter-tunnel-connection'.
|
|
|
|
|
|
|
|
When INFO-OR-SESSION is a plist, use it to create a new
|
|
|
|
`jupyter-session'.
|
|
|
|
|
|
|
|
Finally, when INFO-OR-SESSION is a `jupyter-session' it is used
|
|
|
|
as the session for CLIENT.
|
|
|
|
|
|
|
|
The session object will then be used to initialize the client
|
|
|
|
connection and will be accessible as the session slot of CLIENT.
|
2018-05-06 23:38:09 -05:00
|
|
|
|
|
|
|
The necessary keys and values to initialize a connection can be
|
|
|
|
found at
|
2019-03-23 18:31:35 -05:00
|
|
|
http://jupyter-client.readthedocs.io/en/latest/kernels.html#connection-files."
|
|
|
|
(let ((session (and (jupyter-session-p info-or-session) info-or-session))
|
|
|
|
(conn-info (jupyter--connection-info info-or-session)))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(cl-destructuring-bind (&key key signature_scheme &allow-other-keys)
|
2017-12-22 00:50:56 -06:00
|
|
|
conn-info
|
|
|
|
(when (and (> (length key) 0)
|
2018-05-22 21:57:38 -05:00
|
|
|
(not (functionp
|
|
|
|
(intern (concat "jupyter-" signature_scheme)))))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(error "Unsupported signature scheme: %s" signature_scheme)))
|
|
|
|
(oset client session
|
|
|
|
(or (copy-sequence session)
|
|
|
|
(jupyter-session
|
|
|
|
:key (plist-get conn-info :key)
|
|
|
|
:conn-info conn-info)))
|
2020-03-18 12:44:51 -05:00
|
|
|
(jupyter-comm-initialize
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(oref client kcomm)
|
|
|
|
(oref client session))))
|
2017-12-22 00:50:56 -06:00
|
|
|
|
2018-01-16 12:05:53 -06:00
|
|
|
;;; Client local variables
|
2018-01-13 22:51:27 -06:00
|
|
|
|
2018-10-02 22:09:59 -05:00
|
|
|
(defmacro jupyter-with-client-buffer (client &rest body)
|
2018-01-18 23:10:16 -06:00
|
|
|
"Run a form inside CLIENT's IOloop subprocess buffer.
|
|
|
|
BODY is run with the current buffer set to CLIENT's IOloop
|
|
|
|
subprocess buffer."
|
2018-01-12 17:47:06 -06:00
|
|
|
(declare (indent 1))
|
|
|
|
`(progn
|
2018-01-13 13:34:02 -06:00
|
|
|
(cl-check-type ,client jupyter-kernel-client)
|
2018-01-16 12:05:53 -06:00
|
|
|
(with-current-buffer (oref ,client -buffer)
|
2018-01-12 17:47:06 -06:00
|
|
|
,@body)))
|
|
|
|
|
|
|
|
(defun jupyter-set (client symbol newval)
|
|
|
|
"Set CLIENT's local value for SYMBOL to NEWVAL."
|
2018-10-02 22:09:59 -05:00
|
|
|
(jupyter-with-client-buffer client
|
2018-01-12 17:47:06 -06:00
|
|
|
(set (make-local-variable symbol) newval)))
|
|
|
|
|
|
|
|
(defun jupyter-get (client symbol)
|
2019-07-13 02:47:21 -05:00
|
|
|
"Get CLIENT's local value of SYMBOL.
|
|
|
|
Return nil if SYMBOL is not bound for CLIENT."
|
|
|
|
(condition-case nil
|
|
|
|
(buffer-local-value symbol (oref client -buffer))
|
|
|
|
(void-variable nil)))
|
|
|
|
|
|
|
|
(gv-define-simple-setter jupyter-get jupyter-set)
|
2018-01-12 17:47:06 -06:00
|
|
|
|
2018-01-16 12:05:53 -06:00
|
|
|
;;; Hooks
|
|
|
|
|
2018-01-12 17:54:15 -06:00
|
|
|
(defun jupyter-add-hook (client hook function &optional append)
|
|
|
|
"Add to the CLIENT value of HOOK the function FUNCTION.
|
|
|
|
APPEND has the same meaning as in `add-hook' and FUNCTION is
|
2020-03-11 20:50:52 +09:00
|
|
|
added to HOOK using `add-hook', but local only to CLIENT. Note
|
2018-01-12 17:54:15 -06:00
|
|
|
that the CLIENT should have its channels already started before
|
|
|
|
this is called."
|
2018-05-13 11:40:08 -05:00
|
|
|
(declare (indent 2))
|
2018-10-02 22:09:59 -05:00
|
|
|
(jupyter-with-client-buffer client
|
2018-01-12 17:54:15 -06:00
|
|
|
(add-hook hook function append t)))
|
|
|
|
|
2018-05-25 21:12:54 -05:00
|
|
|
(defun jupyter-run-hook-with-args-until-success (client hook &rest args)
|
2018-11-11 13:42:43 -06:00
|
|
|
"Run CLIENT's value for HOOK with the arguments ARGS.
|
|
|
|
CLIENT is passed as the first argument and then ARGS."
|
2018-10-02 22:09:59 -05:00
|
|
|
(jupyter-with-client-buffer client
|
2018-01-18 23:09:10 -06:00
|
|
|
(when jupyter--debug
|
|
|
|
(message "RUN-HOOK: %s" hook))
|
2018-11-11 13:42:43 -06:00
|
|
|
(with-demoted-errors "Error in Jupyter message hook: %S"
|
|
|
|
(apply #'run-hook-with-args-until-success hook client args))))
|
2018-01-12 17:54:15 -06:00
|
|
|
|
|
|
|
(defun jupyter-remove-hook (client hook function)
|
|
|
|
"Remove from CLIENT's value of HOOK the function FUNCTION."
|
2018-10-02 22:09:59 -05:00
|
|
|
(jupyter-with-client-buffer client
|
2018-01-12 17:54:15 -06:00
|
|
|
(remove-hook hook function t)))
|
2017-12-15 18:21:54 -06:00
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; Sending messages
|
|
|
|
|
2018-08-27 20:46:58 -05:00
|
|
|
(cl-defgeneric jupyter-generate-request ((_client jupyter-kernel-client) _msg)
|
2018-06-03 22:04:21 -05:00
|
|
|
"Generate a `jupyter-request' object for MSG.
|
|
|
|
This method gives an opportunity for subclasses to initialize a
|
2018-08-27 20:46:58 -05:00
|
|
|
`jupyter-request' based on the current context.
|
2018-06-03 22:04:21 -05:00
|
|
|
|
|
|
|
The default implementation returns a new `jupyter-request' with
|
2020-03-11 20:50:52 +09:00
|
|
|
the default value for all slots. Note, the `:id' and
|
2018-10-01 23:13:07 -05:00
|
|
|
`:inhibited-handlers' slots are overwritten by the caller of this
|
|
|
|
method."
|
2018-11-15 18:49:55 -06:00
|
|
|
(jupyter-request))
|
2018-06-03 22:04:21 -05:00
|
|
|
|
2018-11-07 12:23:58 -06:00
|
|
|
(defun jupyter-verify-inhibited-handlers ()
|
|
|
|
"Verify the value of `jupyter-inhibit-handlers'.
|
|
|
|
If it does not contain a valid value, raise an error."
|
|
|
|
(or (eq jupyter-inhibit-handlers t)
|
|
|
|
(cl-loop
|
|
|
|
for msg-type in (if (eq (car jupyter-inhibit-handlers) 'not)
|
|
|
|
(cdr jupyter-inhibit-handlers)
|
|
|
|
jupyter-inhibit-handlers)
|
|
|
|
unless (plist-member jupyter-message-types msg-type)
|
|
|
|
do (error "Not a valid message type (`%s')" msg-type))))
|
|
|
|
|
2017-12-31 15:22:48 -06:00
|
|
|
(cl-defmethod jupyter-send ((client jupyter-kernel-client)
|
|
|
|
channel
|
|
|
|
type
|
2018-05-25 02:07:47 -05:00
|
|
|
message
|
|
|
|
&optional msg-id)
|
2018-01-08 18:11:08 -06:00
|
|
|
"Send a message on CLIENT's CHANNEL.
|
2020-03-11 20:50:52 +09:00
|
|
|
Return a `jupyter-request' representing the sent message. CHANNEL
|
2018-11-08 13:41:39 -06:00
|
|
|
is one of the channel keywords, either (:stdin or :shell).
|
2020-03-11 20:50:52 +09:00
|
|
|
TYPE is one of the `jupyter-message-types'. MESSAGE is the
|
2018-11-08 13:41:39 -06:00
|
|
|
message sent on CHANNEL.
|
2018-05-12 14:52:35 -05:00
|
|
|
|
|
|
|
Note that you can manipulate how to handle messages received in
|
|
|
|
response to the sent message, see `jupyter-add-callback' and
|
2018-02-08 13:38:27 -06:00
|
|
|
`jupyter-request-inhibited-handlers'."
|
2017-12-15 18:21:54 -06:00
|
|
|
(declare (indent 1))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(jupyter-verify-inhibited-handlers)
|
|
|
|
(let ((msg-id (or msg-id (jupyter-new-uuid))))
|
2019-04-11 17:40:08 -05:00
|
|
|
(when jupyter--debug
|
|
|
|
;; The logging of messages is deferred until the next command loop for
|
2020-03-11 20:50:52 +09:00
|
|
|
;; security reasons. When sending :input-reply messages that read
|
2019-04-11 17:40:08 -05:00
|
|
|
;; passwords, clearing the password string using `clear-string' happens
|
|
|
|
;; *after* the call to `jupyter-send'.
|
|
|
|
(run-at-time 0 nil (lambda () (message "SENDING: %s %s %s" type msg-id message))))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(jupyter-send (oref client kcomm) 'send channel type message msg-id)
|
|
|
|
;; Anything sent to stdin is a reply not a request so don't add it as a
|
|
|
|
;; pending request
|
|
|
|
(unless (eq channel :stdin)
|
2019-05-24 14:57:53 -05:00
|
|
|
(let ((req (jupyter-generate-request client message))
|
|
|
|
(requests (oref client requests)))
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(setf (jupyter-request-id req) msg-id)
|
|
|
|
(setf (jupyter-request-inhibited-handlers req) jupyter-inhibit-handlers)
|
2019-05-24 14:57:53 -05:00
|
|
|
(puthash msg-id req requests)
|
|
|
|
(puthash "last-sent" req requests)))))
|
2017-12-15 18:21:54 -06:00
|
|
|
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
;;; Pending requests
|
2017-12-19 18:47:57 -06:00
|
|
|
|
2019-03-17 02:00:00 -05:00
|
|
|
(defun jupyter-requests-pending-p (client)
|
|
|
|
"Return non-nil if CLIENT has open requests that the kernel has not handled.
|
|
|
|
Specifically, this returns non-nil if the last request message
|
|
|
|
sent to the kernel using CLIENT has not received an idle message
|
|
|
|
back."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(jupyter--drop-idle-requests client)
|
2019-05-24 14:57:53 -05:00
|
|
|
(with-slots (requests) client
|
|
|
|
;; If there are two requests, then there is really only one since
|
|
|
|
;; "last-sent" is an alias for the other.
|
|
|
|
(or (> (hash-table-count requests) 2)
|
2019-03-17 02:00:00 -05:00
|
|
|
(when-let* ((last-sent (gethash "last-sent" requests)))
|
|
|
|
(not (jupyter-request-idle-received-p last-sent))))))
|
|
|
|
|
2019-05-24 14:57:53 -05:00
|
|
|
(defsubst jupyter-last-sent-request (client)
|
|
|
|
"Return the most recent `jupyter-request' made by CLIENT."
|
|
|
|
(gethash "last-sent" (oref client requests)))
|
|
|
|
|
2019-07-12 22:01:29 -05:00
|
|
|
(defun jupyter-map-pending-requests (client function)
|
|
|
|
"Call FUNCTION for all pending requests of CLIENT."
|
|
|
|
(declare (indent 1))
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(maphash (lambda (k v)
|
|
|
|
(unless (or (equal k "last-sent")
|
|
|
|
(jupyter-request-idle-received-p v))
|
|
|
|
(funcall function v)))
|
|
|
|
(oref client requests)))
|
|
|
|
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
;;; Event handlers
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
|
2018-11-11 08:28:30 -06:00
|
|
|
;;;; Sending/receiving
|
|
|
|
|
2019-04-11 17:40:08 -05:00
|
|
|
(defun jupyter--show-event (event)
|
|
|
|
(let ((event-name (upcase (symbol-name (car event))))
|
|
|
|
(repr (cl-case (car event)
|
|
|
|
(sent (format "%s" (cdr event)))
|
|
|
|
(message (cl-destructuring-bind (_ channel _idents . msg) event
|
|
|
|
(format "%s" (list
|
|
|
|
channel
|
|
|
|
(jupyter-message-type msg)
|
|
|
|
(jupyter-message-content msg)))))
|
|
|
|
(t nil))))
|
|
|
|
(when repr
|
|
|
|
(message "%s" (concat event-name ": " repr)))))
|
|
|
|
|
2019-05-24 14:57:53 -05:00
|
|
|
;; TODO: Get rid of this method
|
|
|
|
(cl-defmethod jupyter-event-handler ((_client jupyter-kernel-client)
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(event (head sent)))
|
2019-04-11 17:40:08 -05:00
|
|
|
(when jupyter--debug
|
2019-05-24 14:57:53 -05:00
|
|
|
(jupyter--show-event event)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(cl-defmethod jupyter-event-handler ((client jupyter-kernel-client)
|
|
|
|
(event (head message)))
|
2019-04-11 17:40:08 -05:00
|
|
|
(when jupyter--debug
|
|
|
|
(jupyter--show-event event))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(cl-destructuring-bind (_ channel _idents . msg) event
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(jupyter-handle-message client channel msg)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
;;; Starting communication with a kernel
|
2018-11-11 08:28:30 -06:00
|
|
|
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(cl-defmethod jupyter-start-channels ((client jupyter-kernel-client))
|
2020-03-18 12:44:51 -05:00
|
|
|
(jupyter-comm-add-handler (oref client kcomm) client))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2017-12-19 18:13:42 -06:00
|
|
|
(cl-defmethod jupyter-stop-channels ((client jupyter-kernel-client))
|
|
|
|
"Stop any running channels of CLIENT."
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(when (slot-boundp client 'kcomm)
|
2020-03-18 12:44:51 -05:00
|
|
|
(jupyter-comm-remove-handler (oref client kcomm) client)))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2017-12-15 18:14:28 -06:00
|
|
|
(cl-defmethod jupyter-channels-running-p ((client jupyter-kernel-client))
|
2018-01-18 23:10:16 -06:00
|
|
|
"Are any channels of CLIENT running?"
|
Generalize communication with a kernel
The previous mechanism to communicate with a kernel was too low level from the
perspective of a client. The client interfaced directly with the subprocess
abstraction, `jupyter-ioloop`, and had to handle all "events" that occurred in
the `jupyter-ioloop`, e.g. when a channel was started or stopped. But in
reality such events should not be the concern of a client.
A client should only care about events that are directly related to kernel
messages and not events related to the implementation details of *how*
communication occurs.
This commit abstracts out the way in which a client communicates with its
kernel by introducing a new `jupyter-comm-layer` class. The
`jupyter-comm-layer` class takes care of managing the communication channel
between a kernel and its clients as well as sending events to all registered
clients. This way, clients operate solely at the level of events on the
communication layer. All a client does is register itself to receive events on
the communication layer and send events on the layer.
* jupyter-base.el (jupyter-session-endpoints): New function.
* jupyter-client.el (jupyter-kernel-client): Remove ioloop and channels slots.
Add kcomm slot.
(initialize-instance): Unconditionally stop channels.
(jupyter-initialize-connection): Change into a method call.
Call `jupyter-initialize-connection` on the `kcomm` slot.
(jupyter-with-client-buffer): Remove stale comment.
(jupyter-send): Call `jupyter-send` on the `kcomm` slot.
(jupyter-ioloop-handler): Remove all method definitions, replace `sent` and
`message` methods with their `jupyter-event-handler` equivalents.
(jupyter-hb-pause, jupyter-hb-unpause, jupyter-hb-beating):
(jupyter-channel-alive-p, jupyter-start-channel, jupyter-stop-channel):
(jupyter-start-channels, jupyter-stop-channels):
Replace with calls to their equivalents using the `kcomm` slot.
* jupyter-comm-layer.el: New file.
* jupyter-kernel-manager (jupyter-make-client): Set a client's `kcomm` slot to
`jupyter-channel-ioloop-comm`.
* jupyter-messages.el (jupyter-decode-message): Use `list` directly. There
seemed to be issues when using the new `jupyter-sync-channel-comm` due to
using quoted lists.
* test/jupyter-test.el: Add `jupyter-comm-layer` test. Update other tests.
* test/test-helper.el: Add `jupyter-comm-layer` mock objects. Update
`jupyter-echo-client`.
2019-04-08 11:42:00 -05:00
|
|
|
(jupyter-comm-alive-p (oref client kcomm)))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-channel-alive-p ((client jupyter-kernel-client) channel)
|
|
|
|
(jupyter-channel-alive-p (oref client kcomm) channel))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-hb-pause ((client jupyter-kernel-client))
|
|
|
|
(when (cl-typep (oref client kcomm) 'jupyter-hb-comm)
|
|
|
|
(jupyter-hb-pause (oref client kcomm))))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-hb-unpause ((client jupyter-kernel-client))
|
|
|
|
(when (cl-typep (oref client kcomm) 'jupyter-hb-comm)
|
|
|
|
(jupyter-hb-unpause (oref client kcomm))))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-hb-beating-p ((client jupyter-kernel-client))
|
|
|
|
"Is CLIENT still connected to its kernel?"
|
|
|
|
(or (null (cl-typep (oref client kcomm) 'jupyter-hb-comm))
|
|
|
|
(jupyter-hb-beating-p (oref client kcomm))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2017-12-15 22:26:21 -06:00
|
|
|
;;; Message callbacks
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-01-06 15:31:39 -06:00
|
|
|
(defun jupyter--run-callbacks (req msg)
|
|
|
|
"Run REQ's MSG callbacks.
|
|
|
|
See `jupyter-add-callback'."
|
2019-09-22 10:15:12 -05:00
|
|
|
(when-let (callbacks (and req (jupyter-request-callbacks req)))
|
2018-11-11 08:58:11 -06:00
|
|
|
;; Callback for all message types
|
2019-09-22 10:15:12 -05:00
|
|
|
(when-let (f (alist-get t callbacks))
|
|
|
|
(funcall f msg))
|
|
|
|
(when-let (f (alist-get (jupyter-message-type msg) callbacks))
|
|
|
|
(funcall f msg))))
|
2017-12-19 18:02:55 -06:00
|
|
|
|
2018-01-06 15:31:39 -06:00
|
|
|
(defun jupyter--add-callback (req msg-type cb)
|
2018-01-06 16:37:18 -06:00
|
|
|
"Helper function for `jupyter-add-callback'.
|
2018-05-12 14:52:35 -05:00
|
|
|
REQ is a `jupyter-request' object, MSG-TYPE is one of the
|
2018-01-06 16:37:18 -06:00
|
|
|
keywords corresponding to a received message type in
|
2018-05-12 14:52:35 -05:00
|
|
|
`jupyter-message-types', and CB is the callback that will be run
|
|
|
|
when MSG-TYPE is received for REQ."
|
2018-05-16 11:33:05 -05:00
|
|
|
(unless (or (plist-member jupyter-message-types msg-type)
|
|
|
|
;; A msg-type of t means that FUNCTION is run for all messages
|
|
|
|
;; associated with a request.
|
|
|
|
(eq msg-type t))
|
2018-01-06 15:31:39 -06:00
|
|
|
(error "Not a valid message type (`%s')" msg-type))
|
2019-09-22 10:15:12 -05:00
|
|
|
(add-function
|
|
|
|
:after (alist-get msg-type (jupyter-request-callbacks req) #'identity)
|
|
|
|
cb))
|
2018-01-06 15:31:39 -06:00
|
|
|
|
|
|
|
(defun jupyter-add-callback (req msg-type cb &rest callbacks)
|
|
|
|
"Add a callback to run when a message is received for a request.
|
|
|
|
REQ is a `jupyter-request' returned by one of the request methods
|
2020-03-11 20:50:52 +09:00
|
|
|
of a kernel client. MSG-TYPE is one of the keys in
|
|
|
|
`jupyter-message-types'. CB is the callback function to run when
|
2018-02-04 18:05:53 -06:00
|
|
|
a message with MSG-TYPE is received for REQ.
|
|
|
|
|
2018-01-08 18:11:08 -06:00
|
|
|
MSG-TYPE can also be a list, in which case run CB for every
|
2020-03-11 20:50:52 +09:00
|
|
|
MSG-TYPE in the list. If MSG-TYPE is t, run CB for every message
|
2018-02-04 18:05:53 -06:00
|
|
|
received for REQ.
|
2018-01-06 16:37:18 -06:00
|
|
|
|
2020-03-11 20:50:52 +09:00
|
|
|
Multiple callbacks can be added for the same MSG-TYPE. The
|
2019-07-31 21:10:22 -05:00
|
|
|
callbacks will be called in the order they were added.
|
|
|
|
|
2018-01-06 16:37:18 -06:00
|
|
|
Any additional arguments to `jupyter-add-callback' are
|
2020-03-11 20:50:52 +09:00
|
|
|
interpreted as additional CALLBACKS to add to REQ. So to add
|
2018-02-04 18:05:53 -06:00
|
|
|
multiple callbacks you would do
|
2018-01-06 15:31:39 -06:00
|
|
|
|
|
|
|
(jupyter-add-callback
|
2018-05-15 23:40:09 -05:00
|
|
|
(jupyter-send-execute-request client :code \"1 + 2\")
|
2018-01-06 15:31:39 -06:00
|
|
|
:status (lambda (msg) ...)
|
|
|
|
:execute-reply (lambda (msg) ...)
|
|
|
|
:execute-result (lambda (msg) ...))"
|
|
|
|
(declare (indent 1))
|
|
|
|
(if (jupyter-request-idle-received-p req)
|
|
|
|
(error "Request already received idle message")
|
2018-11-11 08:58:11 -06:00
|
|
|
(while (and msg-type cb)
|
|
|
|
(cl-check-type cb function "Callback should be a function")
|
|
|
|
(if (listp msg-type)
|
|
|
|
(cl-loop for mt in msg-type
|
|
|
|
do (jupyter--add-callback req mt cb))
|
|
|
|
(jupyter--add-callback req msg-type cb))
|
|
|
|
(setq msg-type (pop callbacks)
|
|
|
|
cb (pop callbacks)))))
|
2018-01-06 15:31:39 -06:00
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; Waiting for messages
|
|
|
|
|
2019-06-22 21:58:00 -05:00
|
|
|
(defvar jupyter--already-waiting-p nil)
|
|
|
|
|
2018-11-01 19:20:25 -05:00
|
|
|
(defun jupyter-wait-until (req msg-type cb &optional timeout progress-msg)
|
2018-01-06 16:37:18 -06:00
|
|
|
"Wait until conditions for a request are satisfied.
|
|
|
|
REQ, MSG-TYPE, and CB have the same meaning as in
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-add-callback'. If CB returns non-nil within TIMEOUT
|
|
|
|
seconds, return the message that caused CB to return non-nil. If
|
|
|
|
CB never returns a non-nil value within TIMEOUT, return nil. Note
|
2018-11-01 19:20:25 -05:00
|
|
|
that if no TIMEOUT is given, `jupyter-default-timeout' is used.
|
|
|
|
|
|
|
|
If PROGRESS-MSG is non-nil, it should be a message string to
|
|
|
|
display for reporting progress to the user while waiting."
|
2018-01-22 19:24:26 -06:00
|
|
|
(declare (indent 2))
|
2018-11-11 21:13:40 -06:00
|
|
|
(let (msg)
|
2018-01-06 15:31:39 -06:00
|
|
|
(jupyter-add-callback req
|
2018-01-06 16:37:18 -06:00
|
|
|
msg-type (lambda (m) (setq msg (when (funcall cb m) m))))
|
2019-06-22 21:58:00 -05:00
|
|
|
(let* ((timeout-spec (when jupyter--already-waiting-p
|
|
|
|
(with-timeout-suspend)))
|
|
|
|
(jupyter--already-waiting-p t))
|
|
|
|
(unwind-protect
|
|
|
|
(jupyter-with-timeout
|
|
|
|
(progress-msg (or timeout jupyter-default-timeout))
|
|
|
|
msg)
|
|
|
|
(when timeout-spec
|
|
|
|
(with-timeout-unsuspend timeout-spec))))))
|
2018-11-01 19:20:25 -05:00
|
|
|
|
Refactor of `jupyter-kernel-manager.el`
This refactor implements a new class hierarchy to manage the lifetime of a
Jupyter kernel. The first node in this hierarchy is the
`jupyter-kernel-lifetime` class which defines a set of methods to manage the
lifetime of a kernel. An object that inherits from `jupyter-kernel-lifetime` is
stating that it has an association with a kernel and can be used to manage the
lifetime of the associated kernel.
The `jupyter-meta-kernel` class inherits from `jupyter-kernel-lifetime` and
mainly defines a `spec` slot used to hold the `kernelspec` from which a command
can be constructed to start a kernel and a `session` slot used to hold the
`jupyter-session` object that clients can use to establish communication with a
kernel once its live. Concrete classes that actually launch kernels are
intended to inherit from this class and use its slots.
`jupyter-kernel-process` manages the lifetime of a kernel started as a process
using the function `start-file-process`, `jupyter-command-kernel` calls the
`jupyter kernel` shell command to start a kernel, finally `jupyter-spec-kernel`
uses the `spec` slot to construct a shell command to start a kernel.
A `jupyter-kernel-manager` now consists of a `kernel` slot that holds a
`jupyter-meta-kernel` and a `control-channel` slot and inherits from
`jupyter-kernel-lifetime`. The `jupyter-kernel-lifetime` methods of the manager
just defer to those of `kernel` while also taking into account the
`control-channel`.
* jupyter-base.el (jupyter-write-connection-file): New function.
* jupyter-channel-ioloop.el
(jupyter-channel-ioloop-add-start-channel-event): Remove `sleep-for` call.
The startup message is not so important anymore.
* jupyter-client.el (jupyter-wait-until-startup: New function.
* jupyter-kernel-manager.el (jupyter-kernel-lifetime)
(jupyter-kernel, jupyter-kernel-process, jupyter-command-kernel)
(jupyter-spec-kernel): New classes.
(jupyter-kernel-manager): Inherit from jupyter-kernel-lifetime only and
implement its methods.
(jupyter-kernel-manager--cleanup, jupyter-kernel-managers)
(jupyter-delete-all-kernels, jupyter--kernel-sentinel)
(jupyter--start-kernel): Remove and remove related, their functionality has
been generalized in the new classes.
(jupyter-interrupt-kernel, jupyter-shutdown-kernel)
(jupyter-start-channels, jupyter-start-kernel, jupyter-kernel-alive-p)
(jupyter-kill-kernel): Refactor and implement to use the new class hierarchy.
* test/jupyter-test.el: Refactor tests to account for changes.
(jupyter-write-connect-file, jupyter-command-kernel): New tests.
* jupyter-kernelspec.el (jupyter-guess-kernelspec): New function.
2019-05-09 08:31:00 -05:00
|
|
|
(defun jupyter-wait-until-startup (client &optional timeout progress-msg)
|
|
|
|
"Wait for CLIENT to receive a status: startup message.
|
|
|
|
Return non-nil if CLIENT receives the message within TIMEOUT,
|
2020-03-11 20:50:52 +09:00
|
|
|
otherwise nil. TIMEOUT defaults to `jupyter-long-timeout'.
|
Refactor of `jupyter-kernel-manager.el`
This refactor implements a new class hierarchy to manage the lifetime of a
Jupyter kernel. The first node in this hierarchy is the
`jupyter-kernel-lifetime` class which defines a set of methods to manage the
lifetime of a kernel. An object that inherits from `jupyter-kernel-lifetime` is
stating that it has an association with a kernel and can be used to manage the
lifetime of the associated kernel.
The `jupyter-meta-kernel` class inherits from `jupyter-kernel-lifetime` and
mainly defines a `spec` slot used to hold the `kernelspec` from which a command
can be constructed to start a kernel and a `session` slot used to hold the
`jupyter-session` object that clients can use to establish communication with a
kernel once its live. Concrete classes that actually launch kernels are
intended to inherit from this class and use its slots.
`jupyter-kernel-process` manages the lifetime of a kernel started as a process
using the function `start-file-process`, `jupyter-command-kernel` calls the
`jupyter kernel` shell command to start a kernel, finally `jupyter-spec-kernel`
uses the `spec` slot to construct a shell command to start a kernel.
A `jupyter-kernel-manager` now consists of a `kernel` slot that holds a
`jupyter-meta-kernel` and a `control-channel` slot and inherits from
`jupyter-kernel-lifetime`. The `jupyter-kernel-lifetime` methods of the manager
just defer to those of `kernel` while also taking into account the
`control-channel`.
* jupyter-base.el (jupyter-write-connection-file): New function.
* jupyter-channel-ioloop.el
(jupyter-channel-ioloop-add-start-channel-event): Remove `sleep-for` call.
The startup message is not so important anymore.
* jupyter-client.el (jupyter-wait-until-startup: New function.
* jupyter-kernel-manager.el (jupyter-kernel-lifetime)
(jupyter-kernel, jupyter-kernel-process, jupyter-command-kernel)
(jupyter-spec-kernel): New classes.
(jupyter-kernel-manager): Inherit from jupyter-kernel-lifetime only and
implement its methods.
(jupyter-kernel-manager--cleanup, jupyter-kernel-managers)
(jupyter-delete-all-kernels, jupyter--kernel-sentinel)
(jupyter--start-kernel): Remove and remove related, their functionality has
been generalized in the new classes.
(jupyter-interrupt-kernel, jupyter-shutdown-kernel)
(jupyter-start-channels, jupyter-start-kernel, jupyter-kernel-alive-p)
(jupyter-kill-kernel): Refactor and implement to use the new class hierarchy.
* test/jupyter-test.el: Refactor tests to account for changes.
(jupyter-write-connect-file, jupyter-command-kernel): New tests.
* jupyter-kernelspec.el (jupyter-guess-kernelspec): New function.
2019-05-09 08:31:00 -05:00
|
|
|
|
|
|
|
If PROGRESS-MSG is non-nil, it should be a message string to
|
|
|
|
display for reporting progress to the user while waiting."
|
|
|
|
(let* ((msg nil)
|
|
|
|
(check (lambda (_ m)
|
|
|
|
(when (jupyter-message-status-starting-p m)
|
|
|
|
(setq msg m)))))
|
|
|
|
(jupyter-add-hook client 'jupyter-iopub-message-hook check)
|
|
|
|
(unwind-protect
|
|
|
|
(jupyter-with-timeout
|
|
|
|
(progress-msg (or timeout jupyter-long-timeout))
|
|
|
|
msg)
|
|
|
|
(jupyter-remove-hook client 'jupyter-iopub-message-hook check))))
|
|
|
|
|
2018-11-01 19:20:25 -05:00
|
|
|
(defun jupyter-wait-until-idle (req &optional timeout progress-msg)
|
2018-01-06 16:37:18 -06:00
|
|
|
"Wait until a status: idle message is received for a request.
|
2020-03-11 20:50:52 +09:00
|
|
|
REQ has the same meaning as in `jupyter-add-callback'. If an idle
|
2018-01-06 16:37:18 -06:00
|
|
|
message for REQ is received within TIMEOUT seconds, return the
|
2020-03-11 20:50:52 +09:00
|
|
|
message. Otherwise return nil if the message was not received
|
|
|
|
within TIMEOUT. Note that if no TIMEOUT is given, it defaults to
|
2018-11-01 19:20:25 -05:00
|
|
|
`jupyter-default-timeout'.
|
2017-12-15 18:18:41 -06:00
|
|
|
|
2018-11-01 19:20:25 -05:00
|
|
|
If PROGRESS-MSG is non-nil, it is a message string to display for
|
|
|
|
reporting progress to the user while waiting."
|
2020-03-12 21:48:00 -05:00
|
|
|
(or (jupyter-request-idle-received-p req)
|
|
|
|
(jupyter-wait-until req :status
|
|
|
|
#'jupyter-message-status-idle-p timeout progress-msg)))
|
2018-11-01 19:20:25 -05:00
|
|
|
|
|
|
|
(defun jupyter-wait-until-received (msg-type req &optional timeout progress-msg)
|
2018-01-06 16:37:18 -06:00
|
|
|
"Wait until a message of a certain type is received for a request.
|
2018-05-12 14:52:35 -05:00
|
|
|
MSG-TYPE and REQ have the same meaning as their corresponding
|
2020-03-11 20:50:52 +09:00
|
|
|
arguments in `jupyter-add-callback'. If no message that matches
|
2018-01-06 16:37:18 -06:00
|
|
|
MSG-TYPE is received for REQ within TIMEOUT seconds, return nil.
|
2020-03-11 20:50:52 +09:00
|
|
|
Otherwise return the first message that matched MSG-TYPE. Note
|
2018-01-06 16:37:18 -06:00
|
|
|
that if no TIMEOUT is given, it defaults to
|
2018-11-01 19:20:25 -05:00
|
|
|
`jupyter-default-timeout'.
|
|
|
|
|
|
|
|
If PROGRESS-MSG is non-nil, it is a message string to display for
|
|
|
|
reporting progress to the user while waiting."
|
2017-12-31 13:54:43 -06:00
|
|
|
(declare (indent 1))
|
2018-11-01 19:20:25 -05:00
|
|
|
(jupyter-wait-until req msg-type #'identity timeout progress-msg))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; Client handlers
|
2018-01-11 12:14:35 -06:00
|
|
|
|
2018-06-03 22:04:21 -05:00
|
|
|
(cl-defgeneric jupyter-drop-request ((_client jupyter-kernel-client) _req)
|
|
|
|
"Called when CLIENT removes REQ, from its request table."
|
|
|
|
nil)
|
|
|
|
|
2018-11-11 16:52:41 -06:00
|
|
|
(cl-defmethod jupyter-drop-request :before ((_client jupyter-kernel-client) req)
|
|
|
|
(when jupyter--debug
|
|
|
|
(message "DROPPING-REQ: %s" (jupyter-request-id req))))
|
|
|
|
|
2018-01-11 12:06:26 -06:00
|
|
|
(defun jupyter--drop-idle-requests (client)
|
2018-02-04 17:41:48 -06:00
|
|
|
"Drop completed requests from CLIENT's request table.
|
|
|
|
A request is deemed complete when an idle message has been
|
2018-05-27 14:50:20 -05:00
|
|
|
received for it and it is not the most recently sent request."
|
2018-11-11 16:52:41 -06:00
|
|
|
(with-slots (requests) client
|
|
|
|
(cl-loop
|
|
|
|
with last-sent = (gethash "last-sent" requests)
|
|
|
|
for req in (hash-table-values requests)
|
|
|
|
when (and (jupyter-request-idle-received-p req)
|
|
|
|
(not (eq req last-sent)))
|
|
|
|
do (unwind-protect
|
|
|
|
(jupyter-drop-request client req)
|
|
|
|
(remhash (jupyter-request-id req) requests)))))
|
2018-01-11 12:06:26 -06:00
|
|
|
|
2018-11-14 13:14:06 -06:00
|
|
|
(defsubst jupyter--run-handler-p (req msg)
|
|
|
|
"Return non-nil if REQ doesn't inhibit the handler for MSG."
|
2018-11-11 08:40:47 -06:00
|
|
|
(let* ((ihandlers (and req (jupyter-request-inhibited-handlers req)))
|
|
|
|
(type (and (listp ihandlers)
|
|
|
|
(memq (jupyter-message-type msg) ihandlers))))
|
2018-11-14 13:14:06 -06:00
|
|
|
(not (or (eq ihandlers t)
|
|
|
|
(if (eq (car ihandlers) 'not) (not type) type)))))
|
|
|
|
|
|
|
|
(defun jupyter--run-handler-maybe (client channel req msg)
|
|
|
|
"Possibly run CLIENT's CHANNEL handler on REQ's received MSG."
|
|
|
|
(when (jupyter--run-handler-p req msg)
|
|
|
|
(jupyter-handle-message channel client req msg)))
|
2018-02-08 13:38:27 -06:00
|
|
|
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(cl-defmethod jupyter-handle-message ((client jupyter-kernel-client) channel msg)
|
2017-12-13 11:27:13 -06:00
|
|
|
"Process a message on CLIENT's CHANNEL.
|
2018-01-06 19:43:21 -06:00
|
|
|
When a message is received from the kernel, the
|
2020-03-11 20:50:52 +09:00
|
|
|
`jupyter-handle-message' method is called on the client. The
|
2018-01-06 19:43:21 -06:00
|
|
|
client method runs any callbacks for the message and possibly
|
|
|
|
runs the client handler for the channel the message was received
|
2020-03-11 20:50:52 +09:00
|
|
|
on. The channel's `jupyter-handle-message' method will then pass
|
2018-05-15 23:41:19 -05:00
|
|
|
the message to the appropriate message handler based on the
|
|
|
|
message type.
|
2018-01-06 19:43:21 -06:00
|
|
|
|
|
|
|
So when a message is received from the kernel the following steps
|
|
|
|
are taken:
|
|
|
|
|
|
|
|
- `jupyter-handle-message' (client)
|
|
|
|
- Run callbacks for message
|
|
|
|
- Possibly run channel handlers
|
|
|
|
- `jupyter-handle-message' (channel)
|
|
|
|
- Based on message type, dispatch to
|
|
|
|
`jupyter-handle-execute-result',
|
|
|
|
`jupyter-handle-kernel-info-reply', ...
|
2018-01-08 18:11:08 -06:00
|
|
|
- Remove request from client request table when idle message is received"
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(when msg
|
2018-11-10 13:05:33 -06:00
|
|
|
(let* ((jupyter-current-client client)
|
|
|
|
(pmsg-id (jupyter-message-parent-id msg))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(requests (oref client requests))
|
|
|
|
(req (gethash pmsg-id requests)))
|
2019-03-23 23:59:05 -05:00
|
|
|
;; Update the state of the client
|
2019-03-29 12:29:16 -05:00
|
|
|
(pcase (jupyter-message-type msg)
|
2019-03-23 23:59:05 -05:00
|
|
|
(:status
|
|
|
|
(oset client execution-state
|
|
|
|
(jupyter-message-get msg :execution_state)))
|
2019-03-29 12:29:16 -05:00
|
|
|
((or :execute-input (and (guard req) :execute-reply))
|
2019-03-23 23:59:05 -05:00
|
|
|
(oset client execution-count
|
|
|
|
(1+ (jupyter-message-get msg :execution_count)))))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(if (not req)
|
2019-03-14 19:57:00 -05:00
|
|
|
(when (or (jupyter-get client 'jupyter-include-other-output)
|
|
|
|
;; Always handle a startup message
|
|
|
|
(jupyter-message-status-starting-p msg))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter--run-handler-maybe client channel req msg))
|
|
|
|
(setf (jupyter-request-last-message req) msg)
|
|
|
|
(unwind-protect
|
|
|
|
(jupyter--run-callbacks req msg)
|
2017-12-15 22:26:21 -06:00
|
|
|
(unwind-protect
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter--run-handler-maybe client channel req msg)
|
2019-03-17 02:01:00 -05:00
|
|
|
(when (or (jupyter-message-status-idle-p msg)
|
2019-05-12 23:18:19 -05:00
|
|
|
;; Jupyter protocol 5.1, IPython implementation 7.5.0
|
|
|
|
;; doesn't give status: busy or status: idle messages on
|
2020-03-11 20:50:52 +09:00
|
|
|
;; kernel-info-requests. Whereas IPython implementation
|
|
|
|
;; 6.5.0 does. Seen on Appveyor tests.
|
2019-05-12 23:18:19 -05:00
|
|
|
;;
|
|
|
|
;; TODO: May be related jupyter/notebook#3705 as the
|
|
|
|
;; problem does happen after a kernel restart when
|
|
|
|
;; testing.
|
|
|
|
(eq (jupyter-message-type msg) :kernel-info-reply)
|
2019-03-17 02:01:00 -05:00
|
|
|
;; No idle message is received after a shutdown reply so
|
|
|
|
;; consider REQ as having received an idle message in
|
|
|
|
;; this case.
|
|
|
|
(eq (jupyter-message-type msg) :shutdown-reply))
|
2020-03-11 20:50:52 +09:00
|
|
|
;; Order matters here. We want to remove idle requests *before*
|
2019-06-25 02:16:57 -05:00
|
|
|
;; setting another request idle to account for idle messages
|
|
|
|
;; coming in out of order, e.g. before their respective reply
|
|
|
|
;; messages.
|
|
|
|
(jupyter--drop-idle-requests client)
|
|
|
|
(setf (jupyter-request-idle-received-p req) t))))))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-05-12 14:50:21 -05:00
|
|
|
;;; Channel handler macros
|
|
|
|
|
|
|
|
(defmacro jupyter-dispatch-message-cases (client req msg cases)
|
|
|
|
"Dispatch to CLIENT handler's based on REQ and MSG.
|
2018-06-14 21:07:22 -05:00
|
|
|
CASES defines the handlers to dispatch to based on the
|
2018-05-12 14:50:21 -05:00
|
|
|
`jupyter-message-type' of MSG and should be a list of lists, the
|
|
|
|
first element of each inner list being the name of the handler,
|
2020-03-11 20:50:52 +09:00
|
|
|
excluding the `jupyter-handle-' prefix. The rest of the elements
|
2018-06-14 21:07:22 -05:00
|
|
|
in the list are the name of the keys that will be extracted from
|
2018-05-12 14:50:21 -05:00
|
|
|
the `jupyter-message-content' of MSG and passed to the handler in
|
2020-03-11 20:50:52 +09:00
|
|
|
the same order as they appear. For example,
|
2018-05-12 14:50:21 -05:00
|
|
|
|
|
|
|
(jupyter-dispatch-message-cases client req msg
|
|
|
|
((shutdown-reply restart)
|
|
|
|
(stream name text)))
|
|
|
|
|
|
|
|
will be transformed to
|
|
|
|
|
|
|
|
(let ((content (jupyter-message-content msg)))
|
|
|
|
(pcase (jupyter-message-type msg)
|
2018-05-16 11:33:05 -05:00
|
|
|
(:shutdown-reply
|
2018-06-14 21:07:22 -05:00
|
|
|
(cl-destructuring-bind (&key restart &allow-other-keys)
|
2018-05-12 14:50:21 -05:00
|
|
|
content
|
|
|
|
(jupyter-handle-shutdown-reply client req restart)))
|
2018-05-16 11:33:05 -05:00
|
|
|
(:stream
|
2018-06-14 21:07:22 -05:00
|
|
|
(cl-destructuring-bind (&key name text &allow-other-keys)
|
2018-05-12 14:50:21 -05:00
|
|
|
content
|
|
|
|
(jupyter-handle-stream client req name text)))
|
|
|
|
(_ (warn \"Message type not handled (%s)\"
|
|
|
|
(jupyter-message-type msg)))))"
|
|
|
|
(declare (indent 3))
|
|
|
|
(let ((handlers nil)
|
|
|
|
(content (make-symbol "contentvar"))
|
|
|
|
(jclient (make-symbol "clientvar"))
|
|
|
|
(jreq (make-symbol "reqvar"))
|
|
|
|
(jmsg (make-symbol "msgvar")))
|
|
|
|
(dolist (case cases)
|
|
|
|
(cl-destructuring-bind (msg-type . keys) case
|
2018-05-16 11:33:05 -05:00
|
|
|
(let ((handler (intern (format "jupyter-handle-%s" msg-type)))
|
|
|
|
(msg-type (intern (concat ":" (symbol-name msg-type)))))
|
|
|
|
(push `(,msg-type
|
2018-05-12 14:50:21 -05:00
|
|
|
(cl-destructuring-bind (&key ,@keys &allow-other-keys)
|
|
|
|
,content
|
|
|
|
(,handler ,jclient ,jreq ,@keys)))
|
|
|
|
handlers))))
|
|
|
|
`(let* ((,jmsg ,msg)
|
|
|
|
(,jreq ,req)
|
|
|
|
(,jclient ,client)
|
|
|
|
(,content (jupyter-message-content ,jmsg)))
|
|
|
|
(pcase (jupyter-message-type ,jmsg)
|
|
|
|
,@handlers
|
|
|
|
(_ (warn "Message type not handled (%s)"
|
|
|
|
(jupyter-message-type msg)))))))
|
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; STDIN handlers
|
2018-01-06 19:43:21 -06:00
|
|
|
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(cl-defmethod jupyter-handle-message ((_channel (eql :stdin))
|
2018-01-04 15:56:04 -06:00
|
|
|
client
|
|
|
|
req
|
|
|
|
msg)
|
2018-05-25 21:12:54 -05:00
|
|
|
(unless (jupyter-run-hook-with-args-until-success
|
|
|
|
client 'jupyter-stdin-message-hook msg)
|
|
|
|
(jupyter-dispatch-message-cases client req msg
|
2018-10-10 00:12:56 -05:00
|
|
|
((input-reply prompt password)
|
|
|
|
(input-request prompt password)))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-10-10 00:12:56 -05:00
|
|
|
(cl-defgeneric jupyter-handle-input-request ((client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
prompt
|
|
|
|
password)
|
2017-12-15 18:14:28 -06:00
|
|
|
"Handle an input request from CLIENT's kernel.
|
2020-03-11 20:50:52 +09:00
|
|
|
PROMPT is the prompt the kernel would like to show the user. If
|
2019-02-17 12:12:07 -06:00
|
|
|
PASSWORD is t, then `read-passwd' is used to get input from the
|
2020-03-11 20:50:52 +09:00
|
|
|
user. Otherwise `read-from-minibuffer' is used."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2019-02-17 12:12:07 -06:00
|
|
|
(let* ((value (condition-case nil
|
2020-03-11 20:50:52 +09:00
|
|
|
;; Disallow any `with-timeout's from timing out. This
|
2019-05-29 00:26:22 -05:00
|
|
|
;; prevents any calls to `jupyter-wait-until-received' from
|
2020-03-11 20:50:52 +09:00
|
|
|
;; timing out when reading input. See #35.
|
2019-05-29 00:26:22 -05:00
|
|
|
(let ((timeout-spec (with-timeout-suspend)))
|
|
|
|
(unwind-protect
|
|
|
|
(if (eq password t) (read-passwd prompt)
|
|
|
|
(read-from-minibuffer prompt))
|
|
|
|
(with-timeout-unsuspend timeout-spec)))
|
2019-02-17 12:12:07 -06:00
|
|
|
(quit "")))
|
|
|
|
(msg (jupyter-message-input-reply :value value)))
|
2019-05-29 00:26:22 -05:00
|
|
|
(unwind-protect
|
|
|
|
(jupyter-send client :stdin :input-reply msg)
|
|
|
|
(when (eq password t)
|
|
|
|
(clear-string value)))
|
|
|
|
value))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-10-10 00:12:56 -05:00
|
|
|
(defalias 'jupyter-handle-input-reply 'jupyter-handle-input-request)
|
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; SHELL handlers
|
2017-12-13 11:27:13 -06:00
|
|
|
|
|
|
|
;; http://jupyter-client.readthedocs.io/en/latest/messaging.html#messages-on-the-shell-router-dealer-channel
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(cl-defmethod jupyter-handle-message ((_channel (eql :shell))
|
2018-01-04 15:56:04 -06:00
|
|
|
client
|
|
|
|
req
|
|
|
|
msg)
|
2018-05-25 21:12:54 -05:00
|
|
|
(unless (jupyter-run-hook-with-args-until-success
|
|
|
|
client 'jupyter-shell-message-hook msg)
|
2018-05-27 14:52:39 -05:00
|
|
|
(jupyter-dispatch-message-cases client req msg
|
2018-06-01 23:13:50 -05:00
|
|
|
((execute-reply status execution_count user_expressions payload)
|
2018-05-27 14:52:39 -05:00
|
|
|
(shutdown-reply restart)
|
|
|
|
(inspect-reply found data metadata)
|
|
|
|
(complete-reply matches cursor_start cursor_end metadata)
|
|
|
|
(history-reply history)
|
|
|
|
(is-complete-reply status indent)
|
|
|
|
(comm-info-reply comms)
|
|
|
|
(kernel-info-reply protocol_version implementation
|
|
|
|
implementation_version language_info
|
|
|
|
banner help_links)))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Evaluation
|
2018-10-23 20:45:25 -05:00
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
(cl-defgeneric jupyter-load-file-code (_file)
|
|
|
|
"Return a string suitable to send as code to a kernel for loading FILE.
|
|
|
|
Use the jupyter-lang method specializer to add a method for a
|
|
|
|
particular language."
|
|
|
|
(error "Kernel language (%s) not supported yet"
|
|
|
|
(jupyter-kernel-language jupyter-current-client)))
|
|
|
|
|
|
|
|
;;;;; Evaluation routines
|
|
|
|
|
|
|
|
(defvar-local jupyter-eval-expression-history nil
|
|
|
|
"A client local variable to store the evaluation history.
|
|
|
|
The evaluation history is used when reading code to evaluate from
|
|
|
|
the minibuffer.")
|
|
|
|
|
2018-12-19 21:09:32 -06:00
|
|
|
(defun jupyter--teardown-minibuffer ()
|
|
|
|
"Remove Jupyter related variables and hooks from the minibuffer."
|
|
|
|
(setq jupyter-current-client nil)
|
|
|
|
(remove-hook 'completion-at-point-functions 'jupyter-completion-at-point t)
|
|
|
|
(remove-hook 'minibuffer-exit-hook 'jupyter--teardown-minibuffer t))
|
|
|
|
|
2019-02-13 16:47:48 -06:00
|
|
|
;; This is needed since `read-from-minibuffer' expects the history variable to
|
2020-03-11 20:50:52 +09:00
|
|
|
;; be a symbol whose value is `set' when adding a new history element. Since
|
2019-02-13 16:47:48 -06:00
|
|
|
;; `jupyter-eval-expression-history' is a buffer (client) local variable, it would be
|
|
|
|
;; set in the minibuffer which we don't want.
|
|
|
|
(defvar jupyter--read-expression-history nil
|
|
|
|
"A client's `jupyter-eval-expression-history' when reading an expression.
|
|
|
|
This variable is used as the history symbol when reading an
|
2020-03-11 20:50:52 +09:00
|
|
|
expression from the minibuffer. After an expression is read, the
|
2019-02-13 16:47:48 -06:00
|
|
|
`jupyter-eval-expression-history' of the client is updated to the
|
|
|
|
value of this variable.")
|
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
(cl-defgeneric jupyter-read-expression ()
|
|
|
|
"Read an expression using the `jupyter-current-client' for completion.
|
|
|
|
The expression is read from the minibuffer and the expression
|
|
|
|
history is obtained from the `jupyter-eval-expression-history'
|
|
|
|
client local variable.
|
|
|
|
|
|
|
|
Methods that extend this generic function should
|
|
|
|
`cl-call-next-method' as a last step."
|
|
|
|
(cl-check-type jupyter-current-client jupyter-kernel-client
|
|
|
|
"Need a client to read an expression")
|
2019-02-13 16:47:48 -06:00
|
|
|
(let* ((client jupyter-current-client)
|
|
|
|
(jupyter--read-expression-history
|
|
|
|
(jupyter-get client 'jupyter-eval-expression-history)))
|
|
|
|
(minibuffer-with-setup-hook
|
|
|
|
(lambda ()
|
|
|
|
(setq jupyter-current-client client)
|
|
|
|
(add-hook 'completion-at-point-functions
|
|
|
|
'jupyter-completion-at-point nil t)
|
|
|
|
(add-hook 'minibuffer-exit-hook
|
|
|
|
'jupyter--teardown-minibuffer nil t))
|
|
|
|
(prog1 (read-from-minibuffer
|
2019-03-07 22:22:51 -06:00
|
|
|
(format "Eval (%s): " (jupyter-kernel-language client))
|
2019-02-15 22:14:07 -06:00
|
|
|
nil read-expression-map
|
2019-02-13 16:47:48 -06:00
|
|
|
nil 'jupyter--read-expression-history)
|
|
|
|
(jupyter-set client 'jupyter-eval-expression-history
|
|
|
|
jupyter--read-expression-history)))))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
2018-10-23 20:45:25 -05:00
|
|
|
(defun jupyter-eval (code &optional mime)
|
|
|
|
"Send an execute request for CODE, wait for the execute result.
|
|
|
|
The `jupyter-current-client' is used to send the execute request.
|
2020-03-11 20:50:52 +09:00
|
|
|
All client handlers are inhibited for the request. In addition,
|
|
|
|
the history of the request is not stored. Return the MIME
|
|
|
|
representation of the result. If MIME is nil, return the
|
2018-11-17 16:29:59 -06:00
|
|
|
text/plain representation."
|
|
|
|
(interactive (list (jupyter-read-expression) nil))
|
2018-10-23 20:45:25 -05:00
|
|
|
(let ((msg (jupyter-wait-until-received :execute-result
|
2019-09-03 18:09:16 -05:00
|
|
|
(let* ((jupyter-inhibit-handlers t)
|
|
|
|
(req (jupyter-send-execute-request jupyter-current-client
|
|
|
|
:code code :store-history nil)))
|
2018-12-11 21:36:00 -06:00
|
|
|
(prog1 req
|
|
|
|
(jupyter-add-callback req
|
|
|
|
:execute-reply
|
2019-01-21 23:18:50 -06:00
|
|
|
(jupyter-message-lambda (status evalue)
|
|
|
|
(unless (equal status "ok")
|
|
|
|
(error "%s" (ansi-color-apply evalue))))))))))
|
2018-10-23 20:45:25 -05:00
|
|
|
(when msg
|
|
|
|
(jupyter-message-data msg (or mime :text/plain)))))
|
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(defun jupyter-eval-result-callbacks (req beg end)
|
|
|
|
"Return a plist containing callbacks used to display evaluation results.
|
|
|
|
The plist contains default callbacks for the :execute-reply,
|
|
|
|
:execute-result, and :display-data messages that may be used for
|
|
|
|
the messages received in response to REQ.
|
|
|
|
|
|
|
|
BEG and END are positions in the current buffer marking the
|
|
|
|
region of code evaluated.
|
|
|
|
|
|
|
|
The callbacks are designed to either display evaluation results
|
|
|
|
using overlays in the current buffer over the region between BEG
|
2020-03-11 20:50:52 +09:00
|
|
|
and END or in pop-up buffers/frames. See
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
`jupyter-eval-use-overlays'."
|
|
|
|
(let ((buffer (current-buffer))
|
|
|
|
(use-overlays-p (and beg end (jupyter-eval-display-with-overlay-p))))
|
|
|
|
(when use-overlays-p
|
|
|
|
;; NOTE: It would make sense to set these markers to nil, e.g. at the end
|
|
|
|
;; of the execute-result or idle messages, but there is no guarantee on
|
|
|
|
;; message order so it may be the case that those message types are
|
|
|
|
;; received before the callbacks that use these markers have fired.
|
|
|
|
;;
|
|
|
|
;; TODO: Do something with finalizers?
|
|
|
|
(setq beg (set-marker (make-marker) beg))
|
|
|
|
(setq end (set-marker (make-marker) end)))
|
|
|
|
(let ((display-overlay
|
|
|
|
(if use-overlays-p
|
|
|
|
(lambda (val)
|
|
|
|
(when (buffer-live-p buffer)
|
|
|
|
(prog1 t
|
|
|
|
(with-current-buffer buffer
|
|
|
|
(jupyter-eval-display-overlay beg end val)))))
|
|
|
|
#'ignore))
|
|
|
|
had-result)
|
|
|
|
(list
|
|
|
|
:execute-reply
|
|
|
|
(jupyter-message-lambda (status ename evalue)
|
|
|
|
(cond
|
|
|
|
((equal status "ok")
|
|
|
|
(unless had-result
|
|
|
|
(unless (funcall display-overlay "✔")
|
|
|
|
(message "jupyter: eval done"))))
|
|
|
|
(t
|
|
|
|
(setq ename (ansi-color-apply ename))
|
|
|
|
(setq evalue (ansi-color-apply evalue))
|
|
|
|
(unless
|
|
|
|
;; Happens in IJulia
|
|
|
|
(> (+ (length ename) (length evalue)) 250)
|
|
|
|
(if (string-prefix-p ename evalue)
|
|
|
|
;; Also happens in IJulia
|
|
|
|
(message evalue)
|
|
|
|
(message "%s: %s" ename evalue))))))
|
|
|
|
:execute-result
|
|
|
|
(lambda (msg)
|
|
|
|
(setq had-result t)
|
|
|
|
(jupyter-with-message-data msg
|
|
|
|
((res text/plain)
|
2020-03-11 20:50:52 +09:00
|
|
|
;; Prefer to display the markdown representation if available. The
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
;; IJulia kernel will return both plain text and markdown.
|
|
|
|
(md text/markdown))
|
|
|
|
(let ((jupyter-pop-up-frame (jupyter-pop-up-frame-p :execute-result)))
|
|
|
|
(cond
|
|
|
|
((or md (null res))
|
|
|
|
(jupyter-with-display-buffer "result" 'reset
|
|
|
|
(jupyter-with-message-content msg (data metadata)
|
|
|
|
(jupyter-insert data metadata))
|
|
|
|
(goto-char (point-min))
|
|
|
|
(jupyter-display-current-buffer-reuse-window)))
|
|
|
|
(res
|
|
|
|
(setq res (ansi-color-apply res))
|
|
|
|
(cond
|
|
|
|
((funcall display-overlay res))
|
|
|
|
((jupyter-line-count-greater-p
|
|
|
|
res jupyter-eval-short-result-max-lines)
|
|
|
|
(jupyter-with-display-buffer "result" 'reset
|
|
|
|
(insert res)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(jupyter-display-current-buffer-reuse-window)))
|
|
|
|
(t
|
|
|
|
(funcall jupyter-eval-short-result-display-function
|
|
|
|
(format "%s" res)))))))))
|
|
|
|
:display-data
|
|
|
|
(jupyter-message-lambda (data metadata)
|
|
|
|
(setq had-result t)
|
|
|
|
(jupyter-with-display-buffer "display" req
|
|
|
|
(jupyter-insert data metadata)
|
|
|
|
;; Don't pop-up the display when it's empty (e.g. jupyter-R
|
|
|
|
;; will open some HTML results in an external browser)
|
|
|
|
(when (and (/= (point-min) (point-max)))
|
|
|
|
(jupyter-display-current-buffer-guess-where :display-data)))
|
|
|
|
;; TODO: Also inline images?
|
|
|
|
(funcall display-overlay "✔"))))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-add-callbacks (req &optional beg end)
|
2019-05-20 23:45:20 -05:00
|
|
|
"Add evaluation callbacks for REQ.
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
|
2019-05-20 23:45:20 -05:00
|
|
|
The callbacks are designed to handle the various message types
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
that can be generated by an execute-request to, e.g. display the
|
|
|
|
results of evaluation in a popup buffer or indicate that an error
|
|
|
|
occurred during evaluation.
|
|
|
|
|
|
|
|
The message types that will have callbacks added are
|
|
|
|
:execute-reply, :execute-result, :display-data, :error, :stream.
|
|
|
|
|
|
|
|
BEG and END are positions that mark the region of the current
|
|
|
|
buffer corresponding to the evaluated code.
|
|
|
|
|
|
|
|
See `jupyter-eval-short-result-max-lines' and
|
|
|
|
`jupyter-eval-use-overlays'."
|
|
|
|
(let* ((eval-callbacks (jupyter-eval-result-callbacks req beg end)))
|
|
|
|
(apply
|
|
|
|
#'jupyter-add-callback req
|
|
|
|
(nconc
|
|
|
|
eval-callbacks
|
|
|
|
(list
|
|
|
|
:error
|
|
|
|
(jupyter-message-lambda (traceback)
|
|
|
|
;; FIXME: Assumes the error in the
|
|
|
|
;; execute-reply is good enough
|
|
|
|
(when (> (apply #'+ (mapcar #'length traceback)) 250)
|
|
|
|
(jupyter-display-traceback traceback)))
|
|
|
|
:stream
|
|
|
|
(jupyter-message-lambda (name text)
|
|
|
|
(jupyter-with-display-buffer (pcase name
|
|
|
|
("stderr" "error")
|
|
|
|
(_ "output"))
|
|
|
|
req
|
|
|
|
(jupyter-insert-ansi-coded-text text)
|
|
|
|
(jupyter-display-current-buffer-guess-where :stream))))))
|
|
|
|
req))
|
|
|
|
|
|
|
|
(cl-defgeneric jupyter-eval-string (str &optional beg end)
|
2019-05-20 23:45:20 -05:00
|
|
|
"Evaluate STR using the `jupyter-current-client'.
|
|
|
|
Return the `jupyter-request' object for the evaluation.
|
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
If BEG and END are non-nil they correspond to the region of the
|
|
|
|
current buffer that STR was extracted from.")
|
2019-05-20 23:45:20 -05:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(cl-defmethod jupyter-eval-string (str &optional beg end)
|
|
|
|
"Evaluate STR using the `jupyter-current-client'."
|
2019-05-20 23:45:20 -05:00
|
|
|
(cl-check-type jupyter-current-client jupyter-kernel-client
|
|
|
|
"Not a valid client")
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(let ((jupyter-inhibit-handlers '(not :input-request))
|
|
|
|
(req (jupyter-send-execute-request jupyter-current-client
|
|
|
|
:code str :store-history nil)))
|
2019-05-20 23:45:20 -05:00
|
|
|
(prog1 req
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(jupyter-eval-add-callbacks req beg end))))
|
2019-05-20 23:45:20 -05:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(defun jupyter-eval-string-command (str)
|
2019-05-20 23:45:20 -05:00
|
|
|
"Evaluate STR using the `jupyter-current-client'.
|
|
|
|
If the result of evaluation is more than
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
`jupyter-eval-short-result-max-lines' long, a buffer displaying
|
2020-03-11 20:50:52 +09:00
|
|
|
the results is shown. For less lines, the result is displayed
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
with `jupyter-eval-short-result-display-function'.
|
2019-05-20 23:45:20 -05:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
If `jupyter-eval-use-overlays' is non-nil, evaluation results
|
|
|
|
are displayed in the current buffer instead."
|
2019-08-28 15:43:54 -05:00
|
|
|
(interactive (list (jupyter-read-expression)))
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(jupyter-eval-string str))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(defun jupyter-eval-region (beg end)
|
2018-11-17 16:29:59 -06:00
|
|
|
"Evaluate a region with the `jupyter-current-client'.
|
|
|
|
BEG and END are the beginning and end of the region to evaluate.
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
|
|
|
|
If the result of evaluation is more than
|
|
|
|
`jupyter-eval-short-result-max-lines' long, a buffer displaying
|
2020-03-11 20:50:52 +09:00
|
|
|
the results is shown. For less lines, the result is displayed
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
with `jupyter-eval-short-result-display-function'.
|
|
|
|
|
|
|
|
If `jupyter-eval-use-overlays' is non-nil, evaluation results
|
|
|
|
are displayed in the current buffer instead."
|
2018-11-17 16:29:59 -06:00
|
|
|
(interactive "r")
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(jupyter-eval-string (buffer-substring-no-properties beg end) beg end))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
(defun jupyter-eval-line-or-region (insert)
|
|
|
|
"Evaluate the current line or region with the `jupyter-current-client'.
|
2018-12-28 12:49:50 -06:00
|
|
|
If the current region is active send it using
|
2018-11-17 16:29:59 -06:00
|
|
|
`jupyter-eval-region', otherwise send the current line.
|
|
|
|
|
2018-12-28 12:49:50 -06:00
|
|
|
With a prefix argument, evaluate and INSERT the text/plain
|
|
|
|
representation of the results in the current buffer."
|
2018-11-17 16:29:59 -06:00
|
|
|
(interactive "P")
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
(let* ((region (when (use-region-p)
|
|
|
|
(car (region-bounds))))
|
|
|
|
(req (jupyter-eval-region
|
|
|
|
(or (car region) (line-beginning-position))
|
|
|
|
(or (cdr region) (line-end-position)))))
|
|
|
|
(prog1 req
|
|
|
|
(when insert
|
|
|
|
(setf (alist-get :execute-result (jupyter-request-callbacks req))
|
|
|
|
(let ((pos (point-marker)))
|
|
|
|
(jupyter-message-lambda ((res text/plain))
|
|
|
|
(when res
|
|
|
|
(setq res (ansi-color-apply res))
|
|
|
|
(with-current-buffer (marker-buffer pos)
|
|
|
|
(save-excursion
|
|
|
|
(cond
|
|
|
|
(region
|
|
|
|
(goto-char (car region))
|
|
|
|
(delete-region (car region) (cdr region)))
|
|
|
|
(t
|
|
|
|
(goto-char pos)
|
|
|
|
(end-of-line)
|
|
|
|
(insert "\n")))
|
|
|
|
(set-marker pos nil)
|
|
|
|
(insert res)
|
|
|
|
(when region (push-mark))))))))))))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
(defun jupyter-load-file (file)
|
|
|
|
"Send the contents of FILE using `jupyter-current-client'."
|
|
|
|
(interactive
|
|
|
|
(list (read-file-name "File name: " nil nil nil
|
|
|
|
(file-name-nondirectory
|
|
|
|
(or (buffer-file-name) "")))))
|
|
|
|
(message "Evaluating %s..." file)
|
|
|
|
(setq file (expand-file-name file))
|
|
|
|
(if (file-exists-p file)
|
|
|
|
(jupyter-eval-string (jupyter-load-file-code file))
|
|
|
|
(error "Not a file (%s)" file)))
|
|
|
|
|
|
|
|
(defun jupyter-eval-buffer (buffer)
|
|
|
|
"Send the contents of BUFFER using `jupyter-current-client'."
|
|
|
|
(interactive (list (current-buffer)))
|
|
|
|
(jupyter-eval-string (with-current-buffer buffer (buffer-string))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-defun ()
|
|
|
|
"Evaluate the function at `point'."
|
|
|
|
(interactive)
|
2019-05-21 18:29:14 -05:00
|
|
|
(when-let* ((bounds (bounds-of-thing-at-point 'defun)))
|
|
|
|
(cl-destructuring-bind (beg . end) bounds
|
|
|
|
(jupyter-eval-region beg end))))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
;;;;;; Evaluation overlays
|
|
|
|
|
|
|
|
(defvar jupyter-eval-overlay-keymap
|
|
|
|
(let ((map (make-sparse-keymap)))
|
|
|
|
(define-key map (kbd "S-RET") 'jupyter-eval-toggle-overlay)
|
|
|
|
(define-key map (kbd "S-<return>") 'jupyter-eval-toggle-overlay)
|
|
|
|
map))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--delete (ov &rest _)
|
|
|
|
(delete-overlay ov))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--remove-all (beg end)
|
|
|
|
(dolist (ov (overlays-in beg end))
|
|
|
|
(when (overlay-get ov 'jupyter-eval)
|
|
|
|
(jupyter-eval-ov--delete ov))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--propertize (text &optional newline)
|
|
|
|
;; Display properties can't be nested so use the one on TEXT if available
|
|
|
|
(if (get-text-property 0 'display text) text
|
|
|
|
(let ((display (concat
|
|
|
|
;; Add a space before a newline so that `point' stays on
|
|
|
|
;; the same line when moving to the beginning of the
|
|
|
|
;; overlay.
|
|
|
|
(if newline " \n" " ")
|
|
|
|
(propertize
|
2019-10-13 22:39:49 +02:00
|
|
|
(concat jupyter-eval-overlay-prefix text)
|
Evaluation overlays
* README.org: Add section on `jupyter-eval-use-overlays`, minor formatting fix
* jupyter-client.el (jupyter-eval-overlay): New face.
(jupyter-eval-use-overlays, jupyter-eval-overlay-prefix): New custom variables.
(jupyter--display-eval-result): Remove function.
(jupyter-eval): Use `jupyter-eval-string`.
(jupyter-eval-result-callbacks): New function.
(jupyter-eval-add-callbacks): Result callbacks now obtained from
`jupyter-eval-result-callbacks`, only add callbacks for non-result message
types. Allow `beg` and `end` arguments remove `result-cb` argument, update all
callers.
(jupyter-eval-string): Allow `beg` and `end` arguments remove `cb` argument,
update all callers.
(jupyter-eval-string-command): Remove `cb` argument, update all callers.
(jupyter-eval-region): Ditto.
(jupyter-eval-line-or-region): Refactor.
(jupyter-eval-overlay-keymap): New keymap.
(jupyter-eval-ov--delete, jupyter-eval-ov--remove-all)
(jupyter-eval-ov--propertize, jupyter-eval-ov--fold-boundary)
(jupyter-eval-ov--expand-string, jupyter-eval-ov--make)
(jupyter-eval-ov--expand, jupyter-eval-ov--fold)
(jupyter-eval-toggle-overlay, jupyter-eval-remove-overlays)
(jupyter-eval-display-overlay, jupyter-eval-display-with-overlay-p): New
functions.
* jupyter-repl.el (jupyter-eval-string): Ensure callbacks are added in the
original (non-REPL) buffer the command was called from. So that
`jupyter-eval-display-with-overlay-p`, indirectly called by
`jupyter-eval-add-callbacks`, works.
(jupyter-repl-interaction-mode-map): Set `C-c C-o` binding to
`jupyter-eval-remove-overlays`.
2019-06-30 12:19:22 -05:00
|
|
|
'face 'jupyter-eval-overlay))))
|
|
|
|
;; Ensure `point' doesn't move past the beginning or end of the overlay
|
|
|
|
;; on motion commands.
|
|
|
|
(put-text-property 0 1 'cursor t display)
|
|
|
|
(put-text-property (1- (length display)) (length display) 'cursor t display)
|
|
|
|
(propertize " " 'display display))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--fold-boundary (text)
|
|
|
|
(string-match-p "\n" text))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--fold-string (text)
|
|
|
|
(when (eq buffer-invisibility-spec t)
|
|
|
|
(setq buffer-invisibility-spec '(t)))
|
|
|
|
(unless (assoc 'jupyter-eval buffer-invisibility-spec)
|
|
|
|
(push (cons 'jupyter-eval t) buffer-invisibility-spec))
|
|
|
|
(when-let* ((pos (jupyter-eval-ov--fold-boundary text)))
|
|
|
|
(put-text-property pos (length text) 'invisible 'jupyter-eval text)
|
|
|
|
text))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--expand-string (text)
|
|
|
|
(prog1 text
|
|
|
|
(put-text-property 0 (length text) 'invisible nil text)))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--make (beg end text)
|
|
|
|
(setq text (replace-regexp-in-string "\n+$" "" text))
|
|
|
|
(setq text (replace-regexp-in-string "^\n+" "" text))
|
|
|
|
(let ((ov (make-overlay beg end nil t)))
|
|
|
|
(prog1 ov
|
|
|
|
(overlay-put ov 'evaporate t)
|
|
|
|
(overlay-put ov 'modification-hooks '(jupyter-eval-ov--delete))
|
|
|
|
(overlay-put ov 'insert-in-front-hooks '(jupyter-eval-ov--delete))
|
|
|
|
(overlay-put ov 'insert-behind-hooks '(jupyter-eval-ov--delete))
|
|
|
|
(overlay-put ov 'keymap jupyter-eval-overlay-keymap)
|
|
|
|
(let ((folded (jupyter-eval-ov--fold-string text)))
|
|
|
|
(overlay-put ov 'jupyter-eval
|
|
|
|
(list (if folded 'folded 'expanded) text))
|
|
|
|
(overlay-put ov 'after-string (jupyter-eval-ov--propertize text))))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--expand (ov)
|
|
|
|
(when-let* ((eval-props (overlay-get ov 'jupyter-eval)))
|
|
|
|
(cl-destructuring-bind (fold text) eval-props
|
|
|
|
(when (eq fold 'folded)
|
|
|
|
(setf (car (overlay-get ov 'jupyter-eval)) 'expanded)
|
|
|
|
(when (jupyter-eval-ov--fold-boundary text)
|
|
|
|
(setf (overlay-get ov 'after-string)
|
|
|
|
(jupyter-eval-ov--propertize
|
|
|
|
;; Newline added so that background extends across entire line
|
|
|
|
;; of the last line in TEXT.
|
|
|
|
(concat (jupyter-eval-ov--expand-string text) "\n")
|
|
|
|
t)))))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-ov--fold (ov)
|
|
|
|
(when-let* ((eval-props (overlay-get ov 'jupyter-eval)))
|
|
|
|
(cl-destructuring-bind (fold text) eval-props
|
|
|
|
(when (eq fold 'expanded)
|
|
|
|
(setf (car (overlay-get ov 'jupyter-eval)) 'folded)
|
|
|
|
(jupyter-eval-ov--fold-string text)
|
|
|
|
(setf (overlay-get ov 'after-string)
|
|
|
|
(jupyter-eval-ov--propertize text))))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-toggle-overlay ()
|
|
|
|
"Expand or contract the display of evaluation results around `point'."
|
|
|
|
(interactive)
|
|
|
|
(let (nearest)
|
|
|
|
(dolist (ov (overlays-at (point)))
|
|
|
|
(when (and (or (null nearest)
|
|
|
|
(and (> (overlay-start ov) (overlay-start nearest))
|
|
|
|
(< (overlay-end ov) (overlay-end nearest))))
|
|
|
|
(overlay-get ov 'jupyter-eval))
|
|
|
|
(setq nearest ov)))
|
|
|
|
(when-let* ((props (and nearest (overlay-get nearest 'jupyter-eval))))
|
|
|
|
(cl-destructuring-bind (fold _) props
|
|
|
|
(if (eq fold 'folded)
|
|
|
|
(jupyter-eval-ov--expand nearest)
|
|
|
|
(jupyter-eval-ov--fold nearest))))))
|
|
|
|
|
|
|
|
(defun jupyter-eval-remove-overlays ()
|
|
|
|
"Remove all evaluation result overlays in the buffer."
|
|
|
|
(interactive)
|
|
|
|
(jupyter-eval-ov--remove-all (point-min) (point-max)))
|
|
|
|
|
|
|
|
(defun jupyter-eval-display-overlay (beg end str)
|
|
|
|
"Overlay (BEG . END) using STR as an evaluation result.
|
|
|
|
STR is displayed after the region."
|
|
|
|
(save-excursion
|
|
|
|
(goto-char end)
|
|
|
|
(setq end (if (get-text-property 0 'display str)
|
|
|
|
(min (point-max) (1+ (line-end-position)))
|
|
|
|
(skip-syntax-backward "->")
|
|
|
|
(point)))
|
|
|
|
(jupyter-eval-ov--remove-all (1- end) end)
|
|
|
|
(jupyter-eval-ov--make beg end str)))
|
|
|
|
|
|
|
|
(defun jupyter-eval-display-with-overlay-p ()
|
|
|
|
"Return non-nil if evaluation results should be displayed with overlays."
|
|
|
|
(and jupyter-eval-use-overlays
|
|
|
|
jupyter-current-client
|
|
|
|
(derived-mode-p (jupyter-kernel-language-mode jupyter-current-client))))
|
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
;;;;; Handlers
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-execute-request ((client jupyter-kernel-client)
|
|
|
|
&key code
|
|
|
|
(silent nil)
|
|
|
|
(store-history t)
|
|
|
|
(user-expressions nil)
|
|
|
|
(allow-stdin
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-channel-alive-p client :stdin))
|
2018-05-15 23:40:09 -05:00
|
|
|
(stop-on-error nil))
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send an execute request."
|
2017-12-13 11:27:13 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-execute-request
|
2017-12-13 11:27:13 -06:00
|
|
|
:code code
|
|
|
|
:silent silent
|
|
|
|
:store-history store-history
|
|
|
|
:user-expressions user-expressions
|
|
|
|
:allow-stdin allow-stdin
|
|
|
|
:stop-on-error stop-on-error)))
|
2019-01-15 16:08:58 -06:00
|
|
|
(prog1 (jupyter-send client :shell :execute-request msg)
|
|
|
|
(jupyter-server-mode-set-client client))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2019-01-13 13:01:20 -06:00
|
|
|
(cl-defgeneric jupyter-handle-payload ((source symbol) _payload)
|
|
|
|
"Execute the action in a Jupyter PAYLOAD.
|
|
|
|
SOURCE is the type of payload and PAYLOAD will be a property list
|
|
|
|
containing the necessary information to perform the actions of
|
|
|
|
SOURCE."
|
|
|
|
(error "Unhandled payload (%s)" source))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-handle-payload ((payloads vector))
|
|
|
|
"Loop over PAYLOADS, calling `jupyter-handle-payload' for each one."
|
|
|
|
(cl-loop
|
|
|
|
for pl across payloads
|
|
|
|
do (jupyter-handle-payload (intern (plist-get pl :source)) pl)))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-handle-payload ((_source (eql page)) pl)
|
|
|
|
(let ((text (plist-get (plist-get pl :data) :text/plain))
|
|
|
|
(line (or (plist-get pl :start) 0)))
|
|
|
|
(jupyter-with-display-buffer "pager" 'reset
|
|
|
|
(jupyter-insert-ansi-coded-text text)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(forward-line line)
|
2019-02-11 16:01:41 -06:00
|
|
|
(jupyter-display-current-buffer-reuse-window))))
|
2019-01-13 13:01:20 -06:00
|
|
|
|
|
|
|
(cl-defmethod jupyter-handle-payload ((_source (eql edit)) pl)
|
|
|
|
(with-current-buffer (find-file-other-window
|
|
|
|
(plist-get pl :filename))
|
|
|
|
(goto-char (point-min))
|
|
|
|
(forward-line (plist-get pl :line_number))
|
|
|
|
(set-window-start (selected-window) (point))))
|
|
|
|
|
|
|
|
(cl-defmethod jupyter-handle-payload ((_source (eql edit_magic)) pl)
|
|
|
|
(jupyter-handle-payload 'edit pl))
|
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-execute-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
2018-06-01 23:13:50 -05:00
|
|
|
_status
|
2018-01-22 19:12:47 -06:00
|
|
|
_execution-count
|
|
|
|
_user-expressions
|
|
|
|
_payload)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default execute reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Inspection
|
|
|
|
|
2018-11-12 14:46:43 -06:00
|
|
|
;; TODO: How to add hover documentation support
|
|
|
|
(defun jupyter-inspect-at-point (&optional buffer detail)
|
|
|
|
"Inspect the code at point.
|
|
|
|
Call `jupyter-inspect' for the `jupyter-code-context' at point.
|
|
|
|
|
|
|
|
BUFFER and DETAIL have the same meaning as in `jupyter-inspect'."
|
|
|
|
(interactive (list nil 0))
|
|
|
|
(cl-destructuring-bind (code pos)
|
|
|
|
(jupyter-code-context 'inspect)
|
|
|
|
(jupyter-inspect code pos buffer detail)))
|
|
|
|
|
2019-02-09 14:33:00 -06:00
|
|
|
(cl-defgeneric jupyter-inspect (code &optional pos buffer detail)
|
2018-11-12 14:46:43 -06:00
|
|
|
"Inspect CODE.
|
2018-12-06 00:39:39 -06:00
|
|
|
Send an `:inspect-request' with the `jupyter-current-client' and
|
2018-11-12 14:46:43 -06:00
|
|
|
display the results in a BUFFER.
|
|
|
|
|
|
|
|
CODE is the code to inspect and POS is your position in the CODE.
|
|
|
|
If POS is nil, it defaults to the length of CODE.
|
|
|
|
|
|
|
|
If BUFFER is nil, display the results in a help buffer.
|
|
|
|
Otherwise insert the results in BUFFER but do not display it.
|
|
|
|
|
|
|
|
DETAIL is the detail level to use for the request and defaults to
|
|
|
|
0."
|
|
|
|
(setq pos (or pos (length code)))
|
2018-12-19 20:55:42 -06:00
|
|
|
(unless (and jupyter-current-client
|
|
|
|
(object-of-class-p jupyter-current-client 'jupyter-kernel-client))
|
|
|
|
(error "Need a valid `jupyter-current-client'"))
|
2018-11-12 14:46:43 -06:00
|
|
|
(let ((client jupyter-current-client)
|
|
|
|
(msg (jupyter-wait-until-received :inspect-reply
|
2018-11-19 13:58:05 -06:00
|
|
|
(jupyter-send-inspect-request jupyter-current-client
|
2019-01-15 22:53:11 -06:00
|
|
|
:code code :pos pos :detail detail)
|
|
|
|
;; Longer timeout for the Julia kernel
|
|
|
|
jupyter-long-timeout)))
|
2018-11-12 14:46:43 -06:00
|
|
|
(if msg
|
|
|
|
(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
|
2018-11-14 02:21:09 -06:00
|
|
|
;; Insert MSG here so that `jupyter-insert' has access to
|
2020-03-11 20:50:52 +09:00
|
|
|
;; the message type. This is needed since the python
|
2018-11-14 02:21:09 -06:00
|
|
|
;; kernel and others may use this information.
|
|
|
|
(jupyter-insert msg)
|
2018-11-12 14:46:43 -06:00
|
|
|
(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
|
2018-11-20 13:46:50 -06:00
|
|
|
(list
|
2019-08-27 13:48:01 -05:00
|
|
|
;; Don't capture a strong reference to the client
|
|
|
|
;; object since we don't know when this reference will
|
|
|
|
;; be cleaned up.
|
2019-04-08 11:34:00 -05:00
|
|
|
(let ((ref (jupyter-weak-ref client)))
|
2018-11-20 13:46:50 -06:00
|
|
|
(lambda ()
|
|
|
|
(let ((jupyter-current-client
|
2019-04-08 11:34:00 -05:00
|
|
|
(jupyter-weak-ref-resolve ref)))
|
2018-11-20 13:46:50 -06:00
|
|
|
(if jupyter-current-client
|
|
|
|
(jupyter-inspect code pos nil detail)
|
2019-08-27 13:48:01 -05:00
|
|
|
;; TODO: Skip over this xref, need to figure
|
|
|
|
;; out if going forward or backward first.
|
|
|
|
(error "Client has been removed"))))))
|
2018-11-12 14:46:43 -06:00
|
|
|
nil)
|
2018-11-14 02:21:09 -06:00
|
|
|
(jupyter-insert msg)))))
|
2018-11-12 14:46:43 -06:00
|
|
|
(message "Nothing found for %s"
|
|
|
|
(with-temp-buffer
|
|
|
|
(insert code)
|
|
|
|
(goto-char pos)
|
|
|
|
(symbol-at-point)))))
|
|
|
|
(message "Inspect timed out"))))
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-inspect-request ((client jupyter-kernel-client)
|
|
|
|
&key code
|
|
|
|
(pos 0)
|
|
|
|
(detail 0))
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send an inspect request."
|
2017-12-14 13:34:03 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-inspect-request
|
2017-12-14 13:34:03 -06:00
|
|
|
:code code :pos pos :detail detail)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :inspect-request msg)))
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-inspect-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_found
|
|
|
|
_data
|
|
|
|
_metadata)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default inspect reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Completion
|
2018-09-16 20:09:55 -05:00
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
;;;;; Code context
|
|
|
|
|
2018-09-16 20:09:55 -05:00
|
|
|
(cl-defgeneric jupyter-code-context (type)
|
|
|
|
"Return a list, (CODE POS), for the context around `point'.
|
|
|
|
CODE is the required context for TYPE (either `inspect' or
|
|
|
|
`completion') and POS is the relative position of `point' within
|
2020-03-11 20:50:52 +09:00
|
|
|
CODE. Depending on the current context such as the current
|
2018-09-16 20:09:55 -05:00
|
|
|
`major-mode', CODE and POS will be used for `:complete-request's
|
|
|
|
originating from `jupyter-completion-at-point' and
|
2018-10-10 14:09:53 -05:00
|
|
|
`:inspect-request's from `jupyter-inspect-at-point'.
|
|
|
|
|
|
|
|
The default methods return the `jupyter-line-or-region-context'.")
|
2018-09-16 20:09:55 -05:00
|
|
|
|
2018-11-20 13:52:45 -06:00
|
|
|
(defun jupyter-line-context ()
|
|
|
|
"Return the code context for the current line."
|
|
|
|
(jupyter-region-context (line-beginning-position) (line-end-position)))
|
|
|
|
|
|
|
|
(defun jupyter-region-context (beg end)
|
|
|
|
"Return the code context between BEG and END.
|
|
|
|
BEG and END are the bounds of the region of text for which to
|
2020-03-11 20:50:52 +09:00
|
|
|
extract the context. It is an error if `point' is not within
|
|
|
|
these bounds. See `jupyter-code-context' for the form of the
|
2018-11-20 13:52:45 -06:00
|
|
|
returned list."
|
|
|
|
(unless (<= beg (point) end)
|
|
|
|
(error "Point not within bounds (%d %d)" beg end))
|
|
|
|
(let ((code (buffer-substring-no-properties beg end))
|
|
|
|
(pos (1+ (- (point) beg))))
|
2018-09-16 20:09:55 -05:00
|
|
|
(list code (min pos (length code)))))
|
|
|
|
|
2018-11-20 13:52:45 -06:00
|
|
|
(defun jupyter-line-or-region-context ()
|
2018-10-08 18:48:52 -05:00
|
|
|
"Return the code context of the region or line.
|
2020-03-11 20:50:52 +09:00
|
|
|
If the region is active, return it. Otherwise return the line."
|
2018-10-08 18:48:52 -05:00
|
|
|
(if (region-active-p)
|
2018-11-20 13:52:45 -06:00
|
|
|
(jupyter-region-context (region-beginning) (region-end))
|
|
|
|
(jupyter-line-context)))
|
2018-10-08 18:48:52 -05:00
|
|
|
|
2018-09-16 20:09:55 -05:00
|
|
|
(cl-defmethod jupyter-code-context ((_type (eql inspect)))
|
2018-10-08 18:48:52 -05:00
|
|
|
(jupyter-line-or-region-context))
|
2018-09-16 20:09:55 -05:00
|
|
|
|
|
|
|
(cl-defmethod jupyter-code-context ((_type (eql completion)))
|
2019-02-14 23:07:00 -06:00
|
|
|
(let ((ppss (syntax-ppss)))
|
|
|
|
(if (zerop (nth 0 ppss))
|
|
|
|
(jupyter-region-context (line-beginning-position) (point))
|
|
|
|
(jupyter-region-context
|
2019-03-17 20:27:19 -05:00
|
|
|
;; Return a context including the deepest nested parenthesis and the
|
|
|
|
;; closest contiguous non-whitespace sequence of characters at the top
|
|
|
|
;; level.
|
2019-02-14 23:07:00 -06:00
|
|
|
(save-excursion
|
2019-06-13 16:07:46 -05:00
|
|
|
(when (nth 1 ppss)
|
|
|
|
(goto-char (nth 1 ppss)))
|
2019-02-14 23:07:00 -06:00
|
|
|
(skip-syntax-backward "->")
|
|
|
|
(skip-syntax-backward "^->")
|
|
|
|
(point))
|
|
|
|
(point)))))
|
2018-09-16 20:09:55 -05:00
|
|
|
|
2018-11-17 16:29:59 -06:00
|
|
|
;;;;; Helpers for completion interface
|
|
|
|
|
|
|
|
(defun jupyter-completion-symbol-beginning (&optional pos)
|
2018-12-06 00:39:39 -06:00
|
|
|
"Return the beginning position of a completion symbol.
|
|
|
|
The beginning position of the symbol around `point' is returned.
|
|
|
|
If no symbol exists around point, then `point' is returned.
|
|
|
|
|
|
|
|
If POS is non-nil, goto POS first."
|
2018-11-17 16:29:59 -06:00
|
|
|
(save-excursion
|
|
|
|
(and pos (goto-char pos))
|
2018-12-06 00:39:39 -06:00
|
|
|
;; FIXME: This is language specific
|
2018-11-17 16:29:59 -06:00
|
|
|
(if (and (eq (char-syntax (char-before)) ?.)
|
|
|
|
(not (eq (char-before) ?.)))
|
|
|
|
;; Complete operators, but not the field/attribute
|
|
|
|
;; accessor .
|
|
|
|
(skip-syntax-backward ".")
|
|
|
|
(skip-syntax-backward "w_"))
|
|
|
|
(point)))
|
|
|
|
|
|
|
|
;; Adapted from `company-grab-symbol-cons'
|
|
|
|
(defun jupyter-completion-grab-symbol-cons (re &optional max-len)
|
|
|
|
"Return the current completion prefix before point.
|
2020-03-11 20:50:52 +09:00
|
|
|
Return either a STRING or a (STRING . t) pair. If RE matches the
|
2018-11-17 16:29:59 -06:00
|
|
|
beginning of the current symbol before point, return the latter.
|
2020-03-11 20:50:52 +09:00
|
|
|
Otherwise return the symbol before point. If no completion can be
|
2018-11-17 16:29:59 -06:00
|
|
|
done at point, return nil.
|
|
|
|
|
|
|
|
MAX-LEN is the maximum number of characters to search behind the
|
|
|
|
begiining of the symbol at point to look for a match of RE."
|
|
|
|
(let ((symbol (if (or (looking-at "\\>\\|\\_>")
|
|
|
|
;; Complete operators
|
|
|
|
(and (char-before)
|
|
|
|
(eq (char-syntax (char-before)) ?.)))
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(jupyter-completion-symbol-beginning) (point))
|
|
|
|
(unless (and (char-after)
|
|
|
|
(memq (char-syntax (char-after)) '(?w ?_)))
|
|
|
|
""))))
|
|
|
|
(when symbol
|
|
|
|
(save-excursion
|
|
|
|
(forward-char (- (length symbol)))
|
|
|
|
(if (looking-back re (if max-len
|
|
|
|
(- (point) max-len)
|
|
|
|
(line-beginning-position)))
|
|
|
|
(cons symbol t)
|
|
|
|
symbol)))))
|
|
|
|
|
|
|
|
(defun jupyter-completion-number-p ()
|
|
|
|
"Return non-nil if the text before `point' may be a floating point number."
|
|
|
|
(and (char-before)
|
|
|
|
(or (<= ?0 (char-before) ?9)
|
|
|
|
(eq (char-before) ?.))
|
|
|
|
(save-excursion
|
|
|
|
(skip-syntax-backward "w.")
|
|
|
|
(looking-at-p "[0-9]+\\.?[0-9]*"))))
|
|
|
|
|
|
|
|
;;;;; Extracting arguments from argument strings
|
|
|
|
;; This is mainly used for the Julia kernel which will return the type
|
|
|
|
;; information of method arguments and the methods file locations.
|
|
|
|
|
|
|
|
(defconst jupyter-completion-argument-regexp
|
|
|
|
(rx
|
|
|
|
(group "(" (zero-or-more anything) ")")
|
|
|
|
(one-or-more anything) " "
|
|
|
|
(group (one-or-more anything)) ?: (group (one-or-more digit)))
|
|
|
|
"Regular expression to match arguments and file locations.")
|
|
|
|
|
|
|
|
(defun jupyter-completion--arg-extract-1 (pos)
|
|
|
|
"Helper function for `jupyter-completion--arg-extract'.
|
|
|
|
Extract the arguments starting at POS, narrowing to the first
|
|
|
|
SEXP before extraction."
|
|
|
|
(save-restriction
|
|
|
|
(goto-char pos)
|
|
|
|
(narrow-to-region
|
|
|
|
pos (save-excursion (forward-sexp) (point)))
|
|
|
|
(jupyter-completion--arg-extract)))
|
|
|
|
|
|
|
|
(defun jupyter-completion--arg-extract ()
|
|
|
|
"Extract arguments from an argument string.
|
|
|
|
Works for Julia and Python."
|
|
|
|
(let (arg-info
|
|
|
|
inner-args ppss depth inner
|
|
|
|
(start (1+ (point-min)))
|
|
|
|
(get-sexp
|
|
|
|
(lambda ()
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
(point) (progn (forward-sexp) (point)))))
|
|
|
|
(get-string
|
|
|
|
(lambda (start)
|
|
|
|
(string-trim
|
|
|
|
(buffer-substring-no-properties
|
|
|
|
start (1- (point)))))))
|
2018-12-19 20:56:47 -06:00
|
|
|
(while (re-search-forward ",\\|::\\|;" nil t)
|
2018-11-17 16:29:59 -06:00
|
|
|
(setq ppss (syntax-ppss)
|
|
|
|
depth (nth 0 ppss)
|
|
|
|
inner (nth 1 ppss))
|
|
|
|
(cl-case (char-before)
|
|
|
|
(?:
|
|
|
|
(if (eq (char-after) ?{)
|
|
|
|
(push (jupyter-completion--arg-extract-1 (point)) inner-args)
|
|
|
|
(push (list (list (funcall get-sexp))) inner-args)))
|
2018-12-19 20:56:47 -06:00
|
|
|
((or ?, ?\;)
|
2018-11-17 16:29:59 -06:00
|
|
|
(if (/= depth 1)
|
|
|
|
(push (jupyter-completion--arg-extract-1 inner) inner-args)
|
2018-12-19 20:56:47 -06:00
|
|
|
;; ((string . sep) . inner-args)
|
|
|
|
(push (cons (cons (funcall get-string start) (char-before)) (pop inner-args))
|
2018-11-17 16:29:59 -06:00
|
|
|
arg-info)
|
2018-12-06 00:40:21 -06:00
|
|
|
(skip-syntax-forward "-")
|
|
|
|
(setq start (point))))))
|
2018-11-17 16:29:59 -06:00
|
|
|
(goto-char (point-max))
|
2018-12-19 20:56:47 -06:00
|
|
|
(push (cons (cons (funcall get-string start) nil) (pop inner-args)) arg-info)
|
2018-11-17 16:29:59 -06:00
|
|
|
(nreverse arg-info)))
|
|
|
|
|
|
|
|
(defun jupyter-completion--make-arg-snippet (args)
|
|
|
|
"Construct a snippet from ARGS."
|
|
|
|
(cl-loop
|
|
|
|
with i = 1
|
|
|
|
for top-args in args
|
|
|
|
;; TODO: Handle nested arguments
|
2018-12-19 20:56:47 -06:00
|
|
|
for ((arg . sep) . inner-args) = top-args
|
|
|
|
collect (format (concat "${%d:%s}" (when sep "%c")) i arg sep)
|
|
|
|
into constructs
|
2018-11-17 16:29:59 -06:00
|
|
|
and do (setq i (1+ i))
|
|
|
|
finally return
|
2018-12-19 20:56:47 -06:00
|
|
|
(concat "(" (mapconcat #'identity constructs " ") ")")))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
;;;;; Completion prefix
|
|
|
|
|
|
|
|
(cl-defgeneric jupyter-completion-prefix (&optional re max-len)
|
|
|
|
"Return the prefix for the current completion context.
|
|
|
|
The default method calls `jupyter-completion-grab-symbol-cons'
|
2020-03-11 20:50:52 +09:00
|
|
|
with RE and MAX-LEN as arguments, RE defaulting to \"\\\\.\". It
|
2018-11-17 16:29:59 -06:00
|
|
|
also handles argument lists surrounded by parentheses specially
|
|
|
|
by considering an open parentheses and the symbol before it as a
|
|
|
|
completion prefix since some kernels will complete argument lists
|
|
|
|
if given such a prefix.
|
|
|
|
|
|
|
|
Note that the prefix returned is not the content sent to the
|
2020-03-11 20:50:52 +09:00
|
|
|
kernel, but the prefix used by `jupyter-completion-at-point'. See
|
2018-11-17 16:29:59 -06:00
|
|
|
`jupyter-code-context' for what is actually sent to the kernel."
|
|
|
|
(or re (setq re "\\."))
|
|
|
|
(cond
|
|
|
|
;; FIXME: Needed for cases where all completions are retrieved
|
|
|
|
;; from Base.| and the prefix turns empty again after
|
|
|
|
;; Base.REPLCompletions)|
|
|
|
|
;;
|
|
|
|
;; Actually the problem stems from stting the prefix length to 0
|
|
|
|
;; in company in the case Base.| and we have not selected a
|
|
|
|
;; completion and just pass over it.
|
|
|
|
((and (looking-at-p "\\_>")
|
|
|
|
(eq (char-syntax (char-before)) ?\)))
|
|
|
|
nil)
|
|
|
|
(t
|
|
|
|
(unless (jupyter-completion-number-p)
|
|
|
|
(jupyter-completion-grab-symbol-cons re max-len)))))
|
|
|
|
|
|
|
|
(defun jupyter-completion-construct-candidates (matches metadata)
|
|
|
|
"Construct candidates for completion.
|
|
|
|
MATCHES are the completion matches returned by the kernel,
|
|
|
|
METADATA is any extra data associated with MATCHES that was
|
|
|
|
supplied by the kernel."
|
|
|
|
(let* ((matches (append matches nil))
|
|
|
|
(tail matches)
|
|
|
|
(types (append (plist-get metadata :_jupyter_types_experimental) nil))
|
|
|
|
(buf))
|
|
|
|
(save-current-buffer
|
|
|
|
(unwind-protect
|
|
|
|
(while tail
|
|
|
|
(cond
|
|
|
|
((string-match jupyter-completion-argument-regexp (car tail))
|
|
|
|
(let* ((str (car tail))
|
|
|
|
(args-str (match-string 1 str))
|
|
|
|
(end (match-end 1))
|
|
|
|
(path (match-string 2 str))
|
|
|
|
(line (string-to-number (match-string 3 str)))
|
|
|
|
(snippet (progn
|
|
|
|
(unless buf
|
|
|
|
(setq buf (generate-new-buffer " *temp*"))
|
|
|
|
(set-buffer buf))
|
|
|
|
(insert args-str)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(prog1 (jupyter-completion--make-arg-snippet
|
|
|
|
(jupyter-completion--arg-extract))
|
|
|
|
(erase-buffer)))))
|
|
|
|
(setcar tail (substring (car tail) 0 end))
|
|
|
|
(put-text-property 0 1 'snippet snippet (car tail))
|
|
|
|
(put-text-property 0 1 'location (cons path line) (car tail))
|
|
|
|
(put-text-property 0 1 'docsig (car tail) (car tail))))
|
|
|
|
;; TODO: This is specific to the results that
|
|
|
|
;; the python kernel returns, make a support
|
|
|
|
;; function?
|
|
|
|
((string-match-p "\\." (car tail))
|
|
|
|
(setcar tail (car (last (split-string (car tail) "\\."))))))
|
|
|
|
(setq tail (cdr tail)))
|
|
|
|
(when buf (kill-buffer buf))))
|
|
|
|
;; When a type is supplied add it as an annotation
|
|
|
|
(when types
|
|
|
|
(let ((max-len (apply #'max (mapcar #'length matches))))
|
|
|
|
(cl-mapc
|
|
|
|
(lambda (match meta)
|
|
|
|
(let* ((prefix (make-string (1+ (- max-len (length match))) ? ))
|
|
|
|
(annot (concat prefix (plist-get meta :type))))
|
|
|
|
(put-text-property 0 1 'annot annot match)))
|
|
|
|
matches types)))
|
|
|
|
matches))
|
|
|
|
|
|
|
|
;;;;; Completion at point interface
|
|
|
|
|
|
|
|
(defvar jupyter-completion-cache nil
|
|
|
|
"The cache for completion candidates.
|
|
|
|
A list that can take the following forms
|
|
|
|
|
|
|
|
(PREFIX . CANDIDATES)
|
|
|
|
(fetched PREFIX MESSAGE)
|
|
|
|
|
|
|
|
The first form states that the list of CANDIDATES is for the
|
|
|
|
prefix, PREFIX.
|
|
|
|
|
|
|
|
The second form signifies that the CANDIDATES for PREFIX must be
|
|
|
|
extracted from MESSAGE and converted to the first form.")
|
|
|
|
|
|
|
|
(defun jupyter-completion-prefetch-p (prefix)
|
|
|
|
"Return non-nil if a prefetch for PREFIX should be performed.
|
|
|
|
Looks at `jupyter-completion-cache' to determine if its
|
|
|
|
candidates can be used for PREFIX."
|
|
|
|
(not (and jupyter-completion-cache
|
|
|
|
(if (eq (car jupyter-completion-cache) 'fetched)
|
|
|
|
(equal (nth 1 jupyter-completion-cache) prefix)
|
|
|
|
(or (equal (car jupyter-completion-cache) prefix)
|
|
|
|
(and (not (string= (car jupyter-completion-cache) ""))
|
|
|
|
(string-prefix-p (car jupyter-completion-cache) prefix))))
|
|
|
|
;; Invalidate the cache when completing argument lists
|
|
|
|
(or (string= prefix "")
|
|
|
|
(not (eq (aref prefix (1- (length prefix))) ?\())))))
|
|
|
|
|
|
|
|
(defun jupyter-completion-prefetch (fun)
|
|
|
|
"Get completions for the current completion context.
|
|
|
|
Run FUN when the completions are available."
|
|
|
|
(cl-destructuring-bind (code pos)
|
|
|
|
(jupyter-code-context 'completion)
|
|
|
|
(let ((req (let ((jupyter-inhibit-handlers t))
|
|
|
|
(jupyter-send-complete-request
|
|
|
|
jupyter-current-client
|
|
|
|
:code code :pos pos))))
|
|
|
|
(prog1 req
|
|
|
|
(jupyter-add-callback req :complete-reply fun)))))
|
|
|
|
|
|
|
|
(defvar company-minimum-prefix-length)
|
2018-11-19 22:16:04 -06:00
|
|
|
(defvar company-timer)
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
(defun jupyter-completion--company-idle-begin ()
|
|
|
|
"Trigger an idle completion."
|
2018-11-19 22:16:04 -06:00
|
|
|
(when company-timer
|
|
|
|
(cancel-timer company-timer))
|
|
|
|
(setq company-timer
|
2018-11-17 16:29:59 -06:00
|
|
|
;; NOTE: When we reach here `company-idle-delay' is `now' since
|
|
|
|
;; we are already inside a company completion so we can't use
|
|
|
|
;; it, just use a sensible time value instead.
|
2018-11-19 22:16:04 -06:00
|
|
|
(run-with-timer
|
2019-03-17 02:07:00 -05:00
|
|
|
0.1 nil
|
2018-11-19 22:16:04 -06:00
|
|
|
(lambda (buf win tick pos)
|
2018-11-17 16:29:59 -06:00
|
|
|
(let ((company-minimum-prefix-length 0))
|
2018-11-19 22:16:04 -06:00
|
|
|
(company-idle-begin buf win tick pos)))
|
|
|
|
(current-buffer) (selected-window)
|
|
|
|
(buffer-chars-modified-tick) (point))))
|
2018-11-17 16:29:59 -06:00
|
|
|
|
|
|
|
(defun jupyter-completion-at-point ()
|
|
|
|
"Function to add to `completion-at-point-functions'."
|
|
|
|
(let ((prefix (jupyter-completion-prefix)) req)
|
2019-01-12 17:35:31 -06:00
|
|
|
(when (and
|
|
|
|
prefix jupyter-current-client
|
|
|
|
;; Don't try to send completion requests when the kernel is busy
|
|
|
|
;; since it doesn't appear that kernels respond to these requests
|
|
|
|
;; when the kernel is busy, at least the Julia kernel doesn't.
|
|
|
|
;;
|
|
|
|
;; FIXME: Maybe this is kernel dependent
|
2019-01-18 21:41:51 -06:00
|
|
|
(not (jupyter-kernel-busy-p jupyter-current-client)))
|
2018-11-17 16:29:59 -06:00
|
|
|
(when (consp prefix)
|
|
|
|
(setq prefix (car prefix))
|
|
|
|
(when (and (bound-and-true-p company-mode)
|
|
|
|
(< (length prefix) company-minimum-prefix-length))
|
|
|
|
(jupyter-completion--company-idle-begin)))
|
|
|
|
(when (jupyter-completion-prefetch-p prefix)
|
|
|
|
(setq jupyter-completion-cache nil
|
|
|
|
req (jupyter-completion-prefetch
|
|
|
|
(lambda (msg) (setq jupyter-completion-cache
|
|
|
|
(list 'fetched prefix msg))))))
|
|
|
|
(list
|
|
|
|
(- (point) (length prefix)) (point)
|
|
|
|
(completion-table-dynamic
|
|
|
|
(lambda (_)
|
|
|
|
(when (and req (not (jupyter-request-idle-received-p req))
|
|
|
|
(not (eq (jupyter-message-type
|
|
|
|
(jupyter-request-last-message req))
|
|
|
|
:complete-reply)))
|
2019-06-04 13:29:29 -05:00
|
|
|
;; Introduce a delay so that we give a chance for the
|
|
|
|
;; :complete-reply message to get handled.
|
|
|
|
(sit-for 0.1))
|
2018-11-17 16:29:59 -06:00
|
|
|
(when (eq (car jupyter-completion-cache) 'fetched)
|
|
|
|
(jupyter-with-message-content (nth 2 jupyter-completion-cache)
|
|
|
|
(status matches metadata)
|
|
|
|
(setq jupyter-completion-cache
|
|
|
|
(cons (nth 1 jupyter-completion-cache)
|
|
|
|
(when (equal status "ok")
|
|
|
|
(jupyter-completion-construct-candidates
|
|
|
|
matches metadata))))))
|
|
|
|
(cdr jupyter-completion-cache)))
|
|
|
|
:exit-function
|
|
|
|
#'jupyter-completion--post-completion
|
|
|
|
:company-location
|
|
|
|
(lambda (arg) (get-text-property 0 'location arg))
|
|
|
|
:annotation-function
|
|
|
|
(lambda (arg) (get-text-property 0 'annot arg))
|
|
|
|
:company-docsig
|
|
|
|
(lambda (arg) (get-text-property 0 'docsig arg))
|
|
|
|
:company-doc-buffer
|
|
|
|
#'jupyter-completion--company-doc-buffer))))
|
|
|
|
|
|
|
|
(defun jupyter-completion--company-doc-buffer (arg)
|
|
|
|
"Send an inspect request for ARG to the kernel.
|
|
|
|
Use the `company-doc-buffer' to insert the results."
|
|
|
|
(let ((buf (company-doc-buffer)))
|
2019-02-09 14:33:00 -06:00
|
|
|
(jupyter-inspect arg 1 buf)
|
2018-11-17 16:29:59 -06:00
|
|
|
(with-current-buffer buf
|
|
|
|
(when (> (point-max) (point-min))
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
(remove-text-properties
|
|
|
|
(point-min) (point-max) '(read-only))
|
|
|
|
(font-lock-mode 1)
|
|
|
|
(goto-char (point-min))
|
|
|
|
(current-buffer))))))
|
|
|
|
|
|
|
|
(defun jupyter-completion--post-completion (arg status)
|
|
|
|
"If ARG is a completion with a snippet, expand the snippet.
|
|
|
|
Do this only if STATUS is sole or finished."
|
|
|
|
(when (memq status '(sole finished))
|
|
|
|
(jupyter-completion-post-completion arg)))
|
|
|
|
|
|
|
|
(defvar yas-minor-mode)
|
|
|
|
|
|
|
|
(cl-defgeneric jupyter-completion-post-completion (candidate)
|
|
|
|
"Called when CANDIDATE was selected as the completion candidate.
|
|
|
|
The default implementation expands the snippet in CANDIDATE's
|
|
|
|
snippet text property, if any, and if `yasnippet' is available."
|
|
|
|
(when (and (get-text-property 0 'snippet candidate)
|
|
|
|
(require 'yasnippet nil t))
|
|
|
|
(unless yas-minor-mode
|
|
|
|
(yas-minor-mode 1))
|
|
|
|
;; Due to packages like smartparens
|
|
|
|
(when (eq (char-after) ?\))
|
|
|
|
(delete-char 1))
|
|
|
|
(yas-expand-snippet
|
|
|
|
(get-text-property 0 'snippet candidate)
|
|
|
|
(save-excursion
|
|
|
|
(forward-sexp -1)
|
|
|
|
(point))
|
|
|
|
(point))))
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-complete-request ((client jupyter-kernel-client)
|
|
|
|
&key code
|
|
|
|
(pos 0))
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send a complete request."
|
2017-12-14 13:34:03 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-complete-request
|
2017-12-14 13:34:03 -06:00
|
|
|
:code code :pos pos)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :complete-request msg)))
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-complete-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_matches
|
|
|
|
_cursor-start
|
|
|
|
_cursor-end
|
|
|
|
_metadata)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default complete reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; History
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-history-request ((client jupyter-kernel-client)
|
|
|
|
&key
|
|
|
|
output
|
|
|
|
raw
|
|
|
|
(hist-access-type "tail")
|
|
|
|
session
|
|
|
|
start
|
|
|
|
stop
|
|
|
|
(n 10)
|
|
|
|
pattern
|
|
|
|
unique)
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send a history request."
|
2017-12-14 13:34:03 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-history-request
|
2017-12-14 13:34:03 -06:00
|
|
|
:output output
|
|
|
|
:raw raw
|
|
|
|
:hist-access-type hist-access-type
|
|
|
|
:session session
|
|
|
|
:start start
|
|
|
|
:stop stop
|
|
|
|
:n n
|
2017-12-17 02:58:11 -06:00
|
|
|
:pattern pattern
|
2017-12-14 13:34:03 -06:00
|
|
|
:unique unique)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :history-request msg)))
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-history-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_history)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default history reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Is Complete
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-is-complete-request ((client jupyter-kernel-client)
|
|
|
|
&key code)
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send an is-complete request."
|
2017-12-14 13:34:03 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-is-complete-request
|
2017-12-14 13:34:03 -06:00
|
|
|
:code code)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :is-complete-request msg)))
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-is-complete-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_status
|
|
|
|
_indent)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default is complete reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Comms
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-comm-info-request ((client jupyter-kernel-client)
|
|
|
|
&key target-name)
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send a comm-info request."
|
2017-12-14 13:34:03 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-comm-info-request
|
2017-12-14 13:34:03 -06:00
|
|
|
:target-name target-name)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :comm-info-request msg)))
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-05-20 12:09:00 -05:00
|
|
|
(cl-defgeneric jupyter-send-comm-open ((client jupyter-kernel-client)
|
|
|
|
&key id
|
|
|
|
target-name
|
|
|
|
data)
|
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-comm-open
|
2018-05-20 12:09:00 -05:00
|
|
|
:id id
|
|
|
|
:target-name target-name
|
|
|
|
:data data)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :comm-open msg)))
|
2018-05-20 12:09:00 -05:00
|
|
|
|
|
|
|
(cl-defgeneric jupyter-send-comm-msg ((client jupyter-kernel-client)
|
|
|
|
&key id
|
|
|
|
data)
|
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-comm-msg
|
2018-05-20 12:09:00 -05:00
|
|
|
:id id
|
|
|
|
:data data)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :comm-msg msg)))
|
2018-05-20 12:09:00 -05:00
|
|
|
|
|
|
|
(cl-defgeneric jupyter-send-comm-close ((client jupyter-kernel-client)
|
|
|
|
&key id
|
|
|
|
data)
|
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-comm-close
|
2018-05-20 12:09:00 -05:00
|
|
|
:id id
|
|
|
|
:data data)))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(jupyter-send client :shell :comm-close msg)))
|
2018-05-20 12:09:00 -05:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-comm-info-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_comms)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default comm info. reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Kernel info
|
2018-09-16 22:53:18 -05:00
|
|
|
|
2019-01-16 13:52:42 -06:00
|
|
|
(defvar jupyter-kernel-language-mode-properties nil
|
|
|
|
"An association list mapping language names to major mode properties.
|
|
|
|
The lists contain the cached information returned by the
|
2019-02-06 17:46:14 -06:00
|
|
|
function `jupyter-kernel-language-mode-properties'.")
|
2019-01-16 13:52:42 -06:00
|
|
|
|
|
|
|
(defun jupyter-kernel-info (client)
|
2018-09-16 21:17:10 -05:00
|
|
|
"Return the kernel info plist of CLIENT.
|
2020-03-11 20:50:52 +09:00
|
|
|
Return CLIENT's kernel-info slot if non-nil. Otherwise send a
|
2018-09-16 21:17:10 -05:00
|
|
|
`:kernel-info-request' to CLIENT's kernel, set CLIENT's
|
|
|
|
kernel-info slot to the plist retrieved from the kernel, and
|
|
|
|
return it.
|
|
|
|
|
|
|
|
If the kernel CLIENT is connected to does not respond to a
|
2019-03-07 22:22:51 -06:00
|
|
|
`:kernel-info-request', raise an error.
|
|
|
|
|
|
|
|
Note, the value of the :name key in the :language_info property
|
2020-03-12 21:53:00 -05:00
|
|
|
list is a symbol as opposed to a string for the purposes of
|
|
|
|
method dispatching. Also all instances of \" \" in the language
|
|
|
|
name are changed to \"-\" and all uppercase characters lowered."
|
2019-01-16 13:52:42 -06:00
|
|
|
(cl-check-type client jupyter-kernel-client)
|
2018-09-16 21:17:10 -05:00
|
|
|
(or (oref client kernel-info)
|
2018-11-11 08:40:47 -06:00
|
|
|
(let* ((jupyter-inhibit-handlers t)
|
|
|
|
(req (jupyter-send-kernel-info-request client))
|
|
|
|
(msg (jupyter-wait-until-received :kernel-info-reply
|
2019-05-31 14:55:00 -05:00
|
|
|
;; Go to great lengths to ensure we have waited long
|
2020-03-11 20:50:52 +09:00
|
|
|
;; enough. When communicating with slow to start kernels
|
2019-05-31 14:55:00 -05:00
|
|
|
;; behind a kernel server this is necessary.
|
2019-06-30 22:36:19 -05:00
|
|
|
req (* 3 jupyter-long-timeout) "Requesting kernel info...")))
|
2018-11-11 08:40:47 -06:00
|
|
|
(unless msg
|
|
|
|
(error "Kernel did not respond to kernel-info request"))
|
2019-03-07 22:22:51 -06:00
|
|
|
(prog1 (oset client kernel-info (jupyter-message-content msg))
|
2020-03-12 21:53:00 -05:00
|
|
|
;; Canonicalize language name to a language symbol for method dispatching
|
2019-03-07 22:22:51 -06:00
|
|
|
(let* ((info (plist-get (oref client kernel-info) :language_info))
|
|
|
|
(lang (plist-get info :name)))
|
2020-03-12 21:53:00 -05:00
|
|
|
(plist-put info :name (intern (jupyter-canonicalize-language-string lang))))))))
|
2018-09-16 21:17:10 -05:00
|
|
|
|
2019-01-16 13:52:42 -06:00
|
|
|
(defun jupyter-kernel-language-mode-properties (client)
|
|
|
|
"Get the `major-mode' info of CLIENT's kernel language.
|
|
|
|
Return a list
|
|
|
|
|
|
|
|
(MODE SYNTAX-TABLE)
|
|
|
|
|
|
|
|
Where MODE is the `major-mode' to use for syntax highlighting
|
|
|
|
purposes and SYNTAX-TABLE is the syntax table of MODE."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(cl-destructuring-bind (&key name file_extension &allow-other-keys)
|
|
|
|
(plist-get (jupyter-kernel-info client) :language_info)
|
|
|
|
(cdr (or (assoc name jupyter-kernel-language-mode-properties)
|
|
|
|
(with-temp-buffer
|
|
|
|
(let ((buffer-file-name
|
|
|
|
(concat "jupyter-repl-lang" file_extension)))
|
|
|
|
(delay-mode-hooks (set-auto-mode)))
|
|
|
|
(let ((item (cons name (list major-mode (syntax-table)))))
|
|
|
|
(prog1 item
|
|
|
|
(push item jupyter-kernel-language-mode-properties))))))))
|
|
|
|
|
|
|
|
(defun jupyter-kernel-language (client)
|
2019-03-07 22:22:51 -06:00
|
|
|
"Return the language (as a symbol) of the kernel CLIENT is connected to."
|
2019-01-16 13:52:42 -06:00
|
|
|
(cl-check-type client jupyter-kernel-client)
|
2018-09-16 22:53:18 -05:00
|
|
|
(plist-get (plist-get (jupyter-kernel-info client) :language_info) :name))
|
|
|
|
|
2019-01-16 13:52:42 -06:00
|
|
|
(defun jupyter-kernel-language-mode (client)
|
|
|
|
"Return the `major-mode' used for CLIENT's kernel language."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(nth 0 (jupyter-kernel-language-mode-properties client)))
|
|
|
|
|
|
|
|
(defun jupyter-kernel-language-syntax-table (client)
|
|
|
|
"Return the `syntax-table' used for CLIENT's kernel language."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(nth 1 (jupyter-kernel-language-mode-properties client)))
|
|
|
|
|
2018-10-23 21:46:32 -05:00
|
|
|
(defun jupyter-load-language-support (client)
|
|
|
|
"Load language support definitions for CLIENT.
|
2018-11-14 18:51:50 -06:00
|
|
|
CLIENT is a kernel client."
|
2019-01-16 13:52:42 -06:00
|
|
|
(cl-check-type client jupyter-kernel-client)
|
2018-10-23 21:46:32 -05:00
|
|
|
(let* ((lang (jupyter-kernel-language client))
|
2019-03-07 22:22:51 -06:00
|
|
|
(support (intern (format "jupyter-%s" lang))))
|
2018-10-23 21:46:32 -05:00
|
|
|
(require support nil t)))
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-kernel-info-request ((client jupyter-kernel-client))
|
2017-12-15 18:14:28 -06:00
|
|
|
"Send a kernel-info request."
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-kernel-info-request)))
|
|
|
|
(jupyter-send client :shell :kernel-info-request msg)))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-kernel-info-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_protocol-version
|
|
|
|
_implementation
|
|
|
|
_implementation-version
|
|
|
|
_language-info
|
|
|
|
_banner
|
|
|
|
_help-links)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default kernel-info reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-11-08 13:41:39 -06:00
|
|
|
;;;; Shutdown
|
|
|
|
|
2018-05-15 23:40:09 -05:00
|
|
|
(cl-defgeneric jupyter-send-shutdown-request ((client jupyter-kernel-client)
|
|
|
|
&key restart)
|
2018-01-08 22:30:00 -06:00
|
|
|
"Request a shutdown of CLIENT's kernel.
|
|
|
|
If RESTART is non-nil, request a restart instead of a complete shutdown."
|
2018-01-22 19:22:22 -06:00
|
|
|
(declare (indent 1))
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(let ((msg (jupyter-message-shutdown-request :restart restart)))
|
|
|
|
(jupyter-send client :shell :shutdown-request msg)))
|
2018-01-08 22:30:00 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-shutdown-reply ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_restart)
|
2018-01-08 22:30:00 -06:00
|
|
|
"Default shutdown reply handler."
|
2018-02-03 15:22:07 -06:00
|
|
|
(declare (indent 1))
|
2018-01-08 22:30:00 -06:00
|
|
|
nil)
|
|
|
|
|
2018-01-13 22:51:27 -06:00
|
|
|
;;; IOPUB handlers
|
2017-12-13 11:27:13 -06:00
|
|
|
|
Add new `jupyter-ioloop` implementation
A `jupyter-kernel-client' defers most of its message sending, receiving, and
message processing to a subprocess which sends its messages to the kernel
through zmq sockets and polls for any messages to received from the kernel.
This commit generalizes this by introducing a new `jupyter-ioloop` type which
encapsulates the subprocess and the code necessary to build up the function
that does the work of communicating with a kernel in the subprocess
environment.
* jupyter-channels.el: Remove `jupyter-async-channel`
* jupyter-ioloop.el: New file.
(jupyter-ioloop-poller):
(jupyter-ioloop-nsockets):
(jupyter-ioloop-pre-hook):
(jupyter-ioloop-post-hook):
(jupyter-ioloop--argument-types): New variables.
(jupyter-ioloop): New function to create `jupyter-ioloop` objects.
(jupyter-ioloop-add-setup):
(jupyter-ioloop-add-teardown):
(jupyter-ioloop-add-arg-type):
(jupyter-ioloop-add-event): New macros.
(jupyter-ioloop-handler):
(jupyter-ioloop-add-callback):
(jupyter-ioloop-start):
(jupyter-ioloop-stop): New methods.
(jupyter-send): Method addition for `jupyter-ioloop` objects.
(jupyter-ioloop-wait-until): Moved function from `jupyter-client.el`, changed
argument order.
(jupyter-ioloop--replace-args):
(jupyter-ioloop--event-dispatcher):
(jupyter-ioloop--function):
(jupyter-ioloop--filter):
(jupyter-ioloop--sentinel): Helper functions.
* jupyter-client.el: Add `jupyter-ioloop` require.
Remove `jupyter-shell-channel`, `jupyter-iopub-channel`,
`jupyter-stdin-channel` classes.
(jupyter-kernel-client): Change type of `ioloop` slot to `jupyter-ioloop`,
remove `shell-channel`, iopub-channel`, `stdin-channel`, and `hb-channel`
slots. Add `channels` slot.
(jupyter-initialize-connection): Replace channel initialization with
initialization of new `channels` slot.
(jupyter-send): Add better assertion. Call an ioloop's `jupyter-send` method.
Expect a Jupyter channel keyword as the `channel` argument.
(jupyter--ioloop-do-command):
(jupyter--ioloop-with-lock-file):
(jupyter--ioloop-unlock):
(jupyter--ioloop-lock):
(jupyter--ioloop):
(jupyter--ioloop-sentinel):
(jupyter--get-channel):
(jupyter--ioloop-filter):
(jupyter--start-ioloop): Remove functions/macros.
(jupyter-ioloop-wait-until): Move to `jupyter-ioloop.el`
(jupyter-hb-pause):
(jupyter-hb-unpause):
(jupyter-hb-beating-p): Use `channels` slot.
(jupyter-client--ioloop-setup-form): New constant.
(jupyter-ioloop-add-arg-type): New jupyter-channel argument type.
(jupyter-ioloop-add-start-channel-event):
(jupyter-ioloop-add-stop-channel-event):
(jupyter-ioloop-add-send-event): New `jupyter-ioloop` event types for clients.
(jupyter-ioloop-start):
(jupyter-ioloop-handler): Method additions specializing to
`jupyter-kernel-client`s.
(jupyter-start-channel):
(jupyter-stop-channel):
(jupyter-channel-alive-p): Method additions for a client utilizing `channels` slot.
(jupyter-start-channels):
(jupyter-stop-channels):
(jupyter-channels-running-p): Use new `jupyter-ioloop` interface and channel
methods.
(jupyter-handle-message): (`jupyter-kernel-client` method) Add new `msg`
argument. Remove call to `jupyter-get-message`.
(jupyter-handle-message): (All channel methods) Replace
`jupyter-stdin-channel`, `jupyter-iopub-channel`, and `jupyter-shell-channel`
with `(eql :stdin)`, `(eql :iopub)`, and `(eql :shell)`
(jupyter-handle-input-request):
(jupyter-send-execute-request):
(jupyter-send-inspect-request):
(jupyter-send-complete-request):
(jupyter-send-history-request):
(jupyter-send-is-complete-request):
(jupyter-send-comm-info-request):
(jupyter-send-comm-open):
(jupyter-send-comm-msg):
(jupyter-send-comm-close):
(jupyter-sned-kernel-info-request):
(jupyter-send-shutdown-request): Remove uses of `shell-channel` and
`stdin-channel` slot. Pass in expected channel keyword as the `channel`
argument in the call to `jupyter-send`
2018-11-07 12:58:41 -06:00
|
|
|
(cl-defmethod jupyter-handle-message ((_channel (eql :iopub))
|
2018-01-04 15:56:04 -06:00
|
|
|
client
|
|
|
|
req
|
|
|
|
msg)
|
2018-05-25 21:12:54 -05:00
|
|
|
(unless (jupyter-run-hook-with-args-until-success
|
|
|
|
client 'jupyter-iopub-message-hook msg)
|
|
|
|
(jupyter-dispatch-message-cases client req msg
|
|
|
|
((shutdown-reply restart)
|
|
|
|
(stream name text)
|
|
|
|
(comm-open comm_id target_name target_module data)
|
|
|
|
(comm-msg comm_id data)
|
|
|
|
(comm-close comm_id data)
|
|
|
|
(execute-input code execution_count)
|
|
|
|
(execute-result execution_count data metadata)
|
|
|
|
(error ename evalue traceback)
|
|
|
|
(status execution_state)
|
|
|
|
(clear-output wait)
|
|
|
|
(display-data data metadata transient)
|
|
|
|
(update-display-data data metadata transient)))))
|
2017-12-13 11:27:13 -06:00
|
|
|
|
2018-05-26 20:01:29 -05:00
|
|
|
(cl-defgeneric jupyter-handle-comm-open ((client jupyter-kernel-client)
|
|
|
|
req
|
|
|
|
id
|
2018-05-20 12:09:00 -05:00
|
|
|
_target-name
|
|
|
|
_target-module
|
2018-05-26 20:01:29 -05:00
|
|
|
data)
|
2018-05-20 12:09:00 -05:00
|
|
|
(declare (indent 1))
|
2018-05-26 20:01:29 -05:00
|
|
|
(let ((comms (oref client comms)))
|
|
|
|
(puthash id (cons (jupyter-request-id req) data) comms)))
|
2018-05-20 12:09:00 -05:00
|
|
|
|
|
|
|
(cl-defgeneric jupyter-handle-comm-msg ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_id
|
|
|
|
_data)
|
|
|
|
(declare (indent 1))
|
|
|
|
nil)
|
|
|
|
|
2018-05-26 20:01:29 -05:00
|
|
|
(cl-defgeneric jupyter-handle-comm-close ((client jupyter-kernel-client)
|
2018-05-20 12:09:00 -05:00
|
|
|
_req
|
2018-05-26 20:01:29 -05:00
|
|
|
id
|
2018-05-20 12:09:00 -05:00
|
|
|
_data)
|
|
|
|
(declare (indent 1))
|
2018-05-26 20:01:29 -05:00
|
|
|
(let ((comms (oref client comms)))
|
|
|
|
(remhash id comms)))
|
2018-05-20 12:09:00 -05:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-stream ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_name
|
|
|
|
_text)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default stream handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-execute-input ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_code
|
|
|
|
_execution-count)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default execute input handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-execute-result ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_execution-count
|
|
|
|
_data
|
|
|
|
_metadata)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default execute result handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-17 16:31:39 -06:00
|
|
|
(defun jupyter-display-traceback (traceback)
|
|
|
|
"Display TRACEBACK in a dedicated buffer."
|
|
|
|
(when (or (vectorp traceback) (listp traceback))
|
|
|
|
(setq traceback (concat (mapconcat #'identity traceback "\n") "\n")))
|
2018-11-18 14:11:50 -06:00
|
|
|
(jupyter-with-display-buffer "traceback" 'reset
|
2018-11-17 16:31:39 -06:00
|
|
|
(jupyter-insert-ansi-coded-text traceback)
|
|
|
|
(goto-char (point-min))
|
2019-05-20 23:13:00 -05:00
|
|
|
(jupyter-display-current-buffer-guess-where :error)))
|
2018-11-17 16:31:39 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-error ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_ename
|
|
|
|
_evalue
|
|
|
|
_traceback)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default error handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-11-11 13:42:43 -06:00
|
|
|
(defun jupyter-execution-state (client)
|
|
|
|
"Return the execution state of CLIENT's kernel."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(oref client execution-state))
|
|
|
|
|
2019-01-18 21:41:51 -06:00
|
|
|
(defun jupyter-kernel-busy-p (client)
|
|
|
|
"Return non-nil if the kernel CLIENT is connected to is busy."
|
|
|
|
(cl-check-type client jupyter-kernel-client)
|
|
|
|
(equal (jupyter-execution-state client) "busy"))
|
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-status ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_execution-state)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default status handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-14 13:34:03 -06:00
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-clear-output ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_wait)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default clear output handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-display-data ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_data
|
|
|
|
_metadata
|
|
|
|
_transient)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default display data handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-display-data ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_data
|
|
|
|
_metadata
|
|
|
|
_transient)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default display data handler."
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
|
|
|
|
2018-01-22 19:12:47 -06:00
|
|
|
(cl-defgeneric jupyter-handle-update-display-data ((_client jupyter-kernel-client)
|
|
|
|
_req
|
|
|
|
_data
|
|
|
|
_metadata
|
|
|
|
_transient)
|
2018-01-06 22:50:55 -06:00
|
|
|
"Default update display handler"
|
2018-02-03 19:14:24 -06:00
|
|
|
(declare (indent 1))
|
2018-01-06 22:50:55 -06:00
|
|
|
nil)
|
2017-12-13 11:27:13 -06:00
|
|
|
|
|
|
|
(provide 'jupyter-client)
|
2018-01-08 21:38:32 -06:00
|
|
|
|
|
|
|
;;; jupyter-client.el ends here
|