There is no need to do so since
`jupyter-repl-font-lock-fontify-region` already takes care of
narrowing to cell bounds and `font-lock-syntactic-face-function` is
called during the fontification process of the narrowed cell.
The boundaries of cell text are already considered by
`jupyter-repl-map-cells` (called during fontification) so there is no
need to, in addition, have the `font-lock-multiline` property (see the
documentation of `font-lock-extend-region-functions` for what that
property is meant to do).
With regards to the comment, since the buffer is narrowed to the cell
text during fontification, syntactic fontification is contained within
the cell.
`jupyter-handle-*` methods now only take an argument list like
(client req msg)
instead of each method being passed an expanded list of arguments
unpacked from a message contents. Not sure why the unpacking was done
in the first place. The strategy now is to use
`jupyter-with-message-contents` when accessing the contents of a
message.
* jupyter-client.el
(define-jupyter-client-handler)
(define--jupyter-client-sender): New macros.
(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-send-kernel-info-request)
(jupyter-send-shutdown-request): Use `define--jupyter-client-sender`.
(jupyter-handle-input-request)
(jupyter-handle-execute-reply)
(jupyter-handle-inspect-reply)
(jupyter-handle-complete-reply)
(jupyter-handle-history-reply)
(jupyter-handle-is-complete-reply)
(jupyter-handle-comm-info-reply)
(jupyter-handle-kernel-info-reply)
(jupyter-handle-shutdown-reply)
(jupyter-handle-comm-open)
(jupyter-handle-comm-close)
(jupyter-handle-stream)
(jupyter-handle-execute-input)
(jupyter-handle-execute-result)
(jupyter-handle-error)
(jupyter-handle-status)
(jupyter-handle-clear-output)
(jupyter-handle-display-data)
(jupyter-handle-update-display-data): Use
`define-jupyter-client-handler`.
* jupyter-org-client.el
(jupyter-handle-stream)
(jupyter-handle-error)
(jupyter-handle-execute-result)
(jupyter-handle-display-data)
(jupyter-handle-execute-reply): Update to take into account changes in
the argument lists of `jupyter-handle-*` methods.
* jupyter-python.el
(jupyter-handle-error): Ditto.
* jupyter-repl.el
(jupyter-handle-execute-reply)
(jupyter-handle-execute-result)
(jupyter-handle-clear-output)
(jupyter-handle-display-data)
(jupyter-handle-update-display-data)
(jupyter-handle-status)
(jupyter-handle-stream)
(jupyter-handle-error):
(jupyter-handle-history-reply)
(jupyter-handle-shutdown-reply): Ditto.
* jupyter-widget-client.el
(jupyter-handle-comm-open)
(jupyter-handle-comm-close)
(jupyter-handle-comm-msg): Ditto.
It's main purpose was to not forget to add the `read-only` property to text
that needed it. The code base is stable enough to where this is not an issue
anymore.
* jupyter-repl.el (jupyter-repl-insert): Remove. Update all callers.
* jupyter-python.el (jupyter-handle-error): Ditto.
* jupyter-repl.el
(jupyter-repl-inhibit-continuation-prompts): New variable.
(jupyter-repl-without-continuation-prompts)
(jupyter-repl-insert-continuation-prompts): Use it.
The following changes are made:
`jupyter-initialize-connection` -> `jupyter-comm-initialize`
`jupyter-connect-client` -> `jupyter-comm-add-handler`
`jupyter-disconnect-client` -> `jupyter-comm-remove-handler`
`jupyter-comm-client-loop` -> `jupyter-comm-handler-loop`
* README.org: Do it.
* jupyter-channel-ioloop-comm: Do it.
* jupyter-client.el: Do it.
* jupyter-comm-layer.el: Do it.
(jupyter-comm-layer): Rename `clients` slot to `handlers`. Update all uses.
* jupyter-kernel-process-manager.el: Do it.
* jupyter-repl.el: Do it.
* jupyter-server.el: Do it.
* jupyter-zmq-channel-comm.el: Do it.
* test/jupyter-server-test.el: Do it.
* test/jupyter-test.el: Do it.
* jupyter-repl.el (jupyter-repl--deactivate-interaction-buffers): New function.
(jupyter-repl-kill-buffer-query-function): Extract code that deactivates
`jupyter-repl-interaction-mode` in connected buffers to the new function.
(jupyter-repl-mode): Add the new function to `kill-buffer-hook`.
The described behavior for when `jupyter-repl-echo-eval-p` is `t` and the REPL buffer is not visible was not working, i.e., no pop-up buffer was being show.
* 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`.
* jupyter-repl.el (jupyter-repl-restart-kernel):
Call the `jupyter-shutdown-kernel` method of the client's kernel manager if
available.
Remove code that started a kernel when restarting if a manager was available,
this is already handled by `jupyter-shutdown-kernel`.
So as to further generalize and separate out the abstract kernel manager class
from its various implementations.
* jupyter-kernel-manager.el (jupyter-meta-kernel): Fix documentation.
(jupyter-kernel-process, jupyter-command-kernel, jupyter-spec-kernel):
Move related functions and methods to `jupyter-kernel-process-manager.el`
(jupyter-kernel-manager-base): Remove class.
(jupyter-kernel-manager): Re-purpose class as the base class of all kernel
managers. The class corresponding to the old functionality is now named
`jupyter-kernel-process-manager`. Move all related functions and methods for
`jupyter-kernel-process-manager` to `jupyter-kernel-process-manager.el`.
* jupyter-kernel-process-manager.el: New file.
* jupyter-repl.el: Require `jupyter-kernel-process-manager` instead of
`jupyter-kernel-manager`.
* jupyter-server.el (jupyter-server-kernel-manager): Inherit from
`jupyter-kernel-manager` instead of `jupyter-kernel-manager-base`.
* test/jupyter-test.el (jupyter-kernel-lifetime)
(jupyter-command-kernel): Use `jupyter-kernel-process-manager` instead of
`jupyter-kernel-manager`.
* test/test-helper.el: Require `jupyter-kernel-process-manager` instead of
`jupyter-kernel-manager`.
* jupyter-org-extensions.el (jupyter-org-interrupt-kernel): Do it.
(jupyter-org-hydra/body): Add i binding.
* jupyter-repl.el (jupyter-repl-interrupt-kernel): Clarify error message.
This change localizes all `zmq` related functionality to `jupyter-ioloop` and
`jupyter-zmq-*` files.
* jupyter-channel-ioloop-comm.el: Add better commentary.
(jupyter-base): Require.
(jupyter-channel-ioloop-comm): Add `ioloop-class` slot
(initialize-instance [jupyter-channel-ioloop-comm]): Use it.
* jupyter-channel-ioloop.el (jupyter-base, jupyter-zmq-channel): Un-require.
(jupyter-ioloop-session, jupyter-ioloop-channels):
Rename to `jupyter-channel-ioloop-session` `jupyter-channel-ioloop-channels` and
update all callers.
(jupyter-channel-ioloop): Make into an abstract class.
(initialize-instance [jupyter-channel-ioloop]): Re-add
`jupyter-channel-ioloop-add-send-event`. Don't add to
`jupyter-ioloop-post-hook`.
(jupyter-channel-ioloop-recv-messages): Remove.
(jupyter-channel-ioloop--set-session, jupyter-ioloop-start)
(jupyter-channel-ioloop-add-send-event): Doc changes.
(jupyter-channel-ioloop-add-start-channel-event)
(jupyter-channel-ioloop-add-stop-channel-event):
Don't add/remove from the `jupyter-ioloop-poller`.
Now expected to be handled in the `jupyter-channel` subclass.
Update documentation. In addition, for the start-channel event,
do not attempt to add a channel if one doesn't already exist.
* jupyter-ioloop.el
(jupyter-ioloop-add-teardown):
Remove mention of `jupyter-channel-ioloop` behavior.
(jupyter-ioloop-add-arg-type): Update example variable.
(jupyter-ioloop-environment-p): New function.
* jupyter-kernel-manager.el (jupyter-channel): Require.
(jupyter-make-client): Require and use `jupyter-zmq-channel-ioloop`.
(jupyter-start-channels): Use `make-instance`.
(jupyter-interrupt-kernel): Remove `condition-case`. Not needed since
preventing socket blocking is now handled by `jupyter-recv`.
* jupyter-repl.el
(jupyter-connect-repl): Require and use `jupyter-zmq-channel-ioloop`.
* jupyter-zmq-channel-ioloop.el: New file.
* jupyter-zmq-channel.el (jupyter-ioloop-poller-remove)
(jupyter-ioloop-poller-add): New declares.
(jupyter-start-channel):
Add to `jupyter-ioloop-poller` when in `jupyter-ioloop-environment-p`.
(jupyter-stop-channel):
Only disconnect the socket from its endpoint instead of closing it, leave that
up to garbage collection.
Remove from `jupyter-ioloop-poller` when in `jupyter-ioloop-environment-p`.
(jupyter-recv): Handle non-blocking.
* test/jupyter-test.el
(jupyter-zmq-channel): Use non-blocking `zmq-send` since socket is no longer
closed when calling `jupyter-stop-channel`.
(jupyter-ioloop-test-eval-ioloop): Rename to `jupyter-test-ioloop-eval-event`,
update all callers, and move to `test/test-helper.el`.
(jupyter-channel-ioloop-send-event, jupyter-channel-ioloop-stop-channel-event)
(jupyter-channel-ioloop-start-channel-event): Fix tests for variable name
changes. Use `jupyter-test-channel-ioloop`. Update `jupyter-ioloop-poller`,
addition/removal from poller is now done in the `jupyter-channel` subclass by
checking `jupyter-ioloop-environment-p`.
* test/test-helper.el (jupyter-zmq-channel-ioloop): Require.
(initialize-instance [jupyter-echo-client]): Use it.
(jupyter-test-channel-ioloop): New macro.
(jupyter-test-ioloop-eval-event): New function.
Having the `jupyter-comm-layer` abstraction means we do not need to do so.
* jupyter-base.el (zmq): Un-require.
(jupyter-socket-types): Move to `jupyter-channels.el`.
(jupyter-session): Don't mention zmq in doc string.
(jupyter-available-local-ports, jupyter-make-ssh-tunnel): New functions.
(jupyter-tunnel-connection): Use them.
* jupyter-channel-ioloop-comm.el: New file.
* jupyter-channels.el (jupyter-messages): Un-require.
(jupyter-comm-layer, zmq): New requires.
(jupyter-socket-types): Moved from `jupyter-base.el`.
(jupyter-send, jupyter-recv):
Implementations for `jupyter-session` moved from `jupyter-messages.el`.
(jupyter-sync-channel-comm): `jupyter-comm-layer` implementation for
`jupyter-sync-channel` objects moved from `jupyter-comm-layer.el`.
* jupyter-comm-layer.el (jupyter-channel-ioloop): Un-require.
(jupyter-sync-channel-comm): Move implementation to `jupyter-channels.el`.
(jupyter-ioloop-comm): Move implementation to new file `jupyter-ioloop-comm.el`.
(jupyter-channel-ioloop-comm):
Move implementation to new file `jupyter-channel-ioloop-comm.el`.
* jupyter-ioloop-comm.el: New file.
* jupyter-ioloop.el (zmq): Require.
* jupyter-kernel-manager.el
(jupyter-make-client): Ensure `jupyter-channel-ioloop-comm` is required.
* jupyter-messages.el (jupyter-send)
(jupyter-recv): Moved to `jupyter-channels.el`
* jupyter-repl.el
(jupyter-connect-repl): Ensure `jupyter-channel-ioloop-comm` is required.
* test/jupyter-test.el (jupyter-available-local-ports): New test.
* test/test-helper.el (jupyter-channel-ioloop-comm): New require.
Fixes#137
* jupyter-base.el (jupyter-kernelspec): Un-require.
(jupyter-command, jupyter-locate-python)
(jupyter-runtime-directory): Move to new file `jupyter-env.el`
(jupyter-include-other-output, jupyter-iopub-message-hook)
(jupyter-shell-message-hook)
(jupyter-stdin-message-hook): Move to `jupyter-client.el`
(jupyter-sha256, jupyter-hmac-sha256):
(jupytern-new-uuid): Move to `jupyter-messages.el`. Add declaration of
`jupyter-new-uuid` to account for its removal.
(jupyter-create-connection-info)
(jupyter-write-connection-file): Move to `jupyter-kernel-manager.el`
(jupyter-connect-endpoint, jupyter-connect-channel): Move to `jupyter-channels.el`
* jupyter-channels.el: Accept moved functions.
* jupyter-client.el: Accept moved variables.
* jupyter-kernel-manager.el: Accept moved functions.
(jupyter-env, jupyter-kernelspec): New requires.
* jupyter-kernelspec (jupyter-env): New require.
(jupyter-command): Remove declaration.
(jupyter-read-plist-from-string): New declaration.
* jupyter-messages.el: Accept moved functions.
(hmac-def, json): New requires.
* jupyter-org-extensions.el (jupyter-kernelspec): New require.
* jupyter-repl.el (jupyter-kernelspec): New require.
* jupyter-env.el: New file.
* ob-jupyter.el (jupyter-env, jupyter-kernelspec): New requires.
* test/jupyter-test.el (jupyter-env): New require.
Related to let binding `buffer-undo-list` improperly and making text read-only
when it shouldn't be.
Fixes#139
* jupyter-repl.el (jupyter-repl-with-single-undo)
(jupyter-repl-inhibit-undo-when): New macros.
(jupyter-repl-insert): Inhibit undo only when insertions are `read-only`
(jupyter-repl-insert-prompt): Don't make continuation prompts `read-only`
(jupyter-repl-replace-cell-code): Allow the argument to be a `buffer`. Use
`replace-buffer-contents` in this case. Avoids unnecessary undo information.
(jupyter-handle-is-complete-reply): Don't insert a `read-only` newline on
incomplete cell code.
(jupyter-repl-indent-line): Pass buffer to `jupyter-repl-replace-cell-code`
(jupyter-repl-insert-continuation-prompts): Don't inhibit undo
* test/jupyter-test.el (jupyter-repl-undo): Add more tests.
This accounts for idle messages being dropped before a request's reply message.
In such a case, the request is dropped from the client's request table before
the handlers/callbacks of the request get a chance to handle the reply message.
So that client subclasses can provide specialized behavior if needed.
Also adds the function `jupyter-eval-add-callbacks` so that client methods can
more easily obtain the default behavior of `jupyter-eval-string'.
If method arguments are not named it gives rise to errors like
`Args out of range: "", 0`
that originate in `help-function-arglist` when calling `describe-function` on
those methods.
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.