mirror of
https://github.com/vale981/emacs-ipython-notebook
synced 2025-03-06 01:21:38 -05:00
Including kernelspecs into the notebooklist view.
EIN now shows kernels available for the Jupyter server being view in the notebooklist buffer. We don't do much with the info, yet, though.
This commit is contained in:
parent
25d1437de6
commit
a89aa6aebd
3 changed files with 159 additions and 119 deletions
|
@ -47,7 +47,6 @@
|
|||
url-or-port
|
||||
events
|
||||
api-version
|
||||
kernelspec ; Multiple kernels in Jupyter
|
||||
session-id
|
||||
kernel-id
|
||||
shell-channel
|
||||
|
@ -78,10 +77,9 @@
|
|||
|
||||
;;; Initialization and connection.
|
||||
|
||||
(defun ein:kernel-new (url-or-port base-url events &optional api-version kernelspec)
|
||||
(defun ein:kernel-new (url-or-port base-url events &optional api-version)
|
||||
(make-ein:$kernel
|
||||
:url-or-port url-or-port
|
||||
:kernelspec (or kernelspec "")
|
||||
:events events
|
||||
:api-version (or api-version 2)
|
||||
:session-id (ein:utils-uuid)
|
||||
|
@ -116,26 +114,28 @@
|
|||
(defun ein:kernel-start (kernel notebook)
|
||||
"Start kernel of the notebook whose id is NOTEBOOK-ID."
|
||||
(unless (ein:$kernel-running kernel)
|
||||
(if (= (ein:$kernel-api-version kernel) 2)
|
||||
(let ((path (substring (ein:$notebook-notebook-path notebook)
|
||||
0
|
||||
(or (position ?/ (ein:$notebook-notebook-path notebook)
|
||||
:from-end t)
|
||||
0))))
|
||||
(ein:kernel-start--legacy kernel
|
||||
(ein:$notebook-notebook-name notebook)
|
||||
path))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'kernel-start (ein:$kernel-kernel-id kernel))
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
"api/sessions")
|
||||
:type "POST"
|
||||
:data (json-encode `(("notebook" .
|
||||
(("path" . ,(ein:$notebook-notebook-path notebook))))
|
||||
(("kernel" .
|
||||
(("name" . "default"))))))
|
||||
:parser #'ein:json-read
|
||||
:success (apply-partially #'ein:kernel--kernel-started kernel)))))
|
||||
(let ((kernelspec (ein:$notebook-kernelspec notebook)))
|
||||
(if (= (ein:$kernel-api-version kernel) 2)
|
||||
(let ((path (substring (ein:$notebook-notebook-path notebook)
|
||||
0
|
||||
(or (position ?/ (ein:$notebook-notebook-path notebook)
|
||||
:from-end t)
|
||||
0))))
|
||||
(ein:kernel-start--legacy kernel
|
||||
(ein:$notebook-notebook-name notebook)
|
||||
path))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'kernel-start (ein:$kernel-kernel-id kernel))
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
"api/sessions")
|
||||
:type "POST"
|
||||
:data (json-encode `(("notebook" .
|
||||
(("path" . ,(ein:$notebook-notebook-path notebook))))
|
||||
,@(if kernelspec
|
||||
`("kernel"
|
||||
(("name" . ,(ein:$kernelspec-name kernelspec)))))))
|
||||
:parser #'ein:json-read
|
||||
:success (apply-partially #'ein:kernel--kernel-started kernel))))))
|
||||
|
||||
(defun ein:kernel-start--legacy (kernel notebook-id path)
|
||||
(unless (ein:$kernel-running kernel)
|
||||
|
|
|
@ -171,6 +171,9 @@ Current buffer for these functions is set to the notebook buffer.")
|
|||
`ein:$notebook-kernel' : `ein:$kernel'
|
||||
`ein:$kernel' instance.
|
||||
|
||||
`ein:$notebook-kernelspec' : `ein:$kernelspec'
|
||||
Jupyter kernel specification for the notebook.
|
||||
|
||||
`ein:$notebook-kernelinfo' : `ein:kernelinfo'
|
||||
`ein:kernelinfo' instance.
|
||||
|
||||
|
@ -209,6 +212,7 @@ Current buffer for these functions is set to the notebook buffer.")
|
|||
notebook-path
|
||||
kernel
|
||||
kernelinfo
|
||||
kernelspec
|
||||
pager
|
||||
dirty
|
||||
metadata
|
||||
|
@ -229,9 +233,12 @@ Current buffer for these functions is set to the notebook buffer.")
|
|||
|
||||
;;; Constructor
|
||||
|
||||
(defun ein:notebook-new (url-or-port notebook-path &rest args)
|
||||
(defun ein:notebook-new (url-or-port notebook-path kernelspec &rest args)
|
||||
(if (or (stringp kernelspec) (symbolp kernelspec))
|
||||
(setq kernelspec (ein:get-kernelspec url-or-port kernelspec)))
|
||||
(let ((notebook (apply #'make-ein:$notebook
|
||||
:url-or-port url-or-port
|
||||
:kernelspec kernelspec
|
||||
:notebook-path notebook-path
|
||||
args)))
|
||||
notebook))
|
||||
|
@ -310,7 +317,7 @@ will be updated with kernel's cwd."
|
|||
|
||||
;;; TODO - I think notebook-path is unnecessary (JMM).
|
||||
|
||||
(defun ein:notebook-open (url-or-port path &optional callback cbargs)
|
||||
(defun ein:notebook-open (url-or-port path &optional kernelspec callback cbargs)
|
||||
"Open notebook at PATH in the server URL-OR-PORT.
|
||||
Opened notebook instance is returned. Note that notebook might not be
|
||||
ready at the time when this function is executed.
|
||||
|
@ -324,7 +331,6 @@ is newly created or not. When CALLBACK is specified, buffer is
|
|||
**not** brought up by `pop-to-buffer'. It is caller's
|
||||
responsibility to do so. The current buffer is set to the
|
||||
notebook buffer when CALLBACK is called."
|
||||
;(interactive)
|
||||
(unless callback (setq callback #'ein:notebook-pop-to-current-buffer))
|
||||
(let ((buffer (ein:notebook-get-opened-buffer url-or-port path)))
|
||||
(if (buffer-live-p buffer)
|
||||
|
@ -335,9 +341,9 @@ notebook buffer when CALLBACK is called."
|
|||
(apply callback ein:%notebook% nil cbargs))
|
||||
ein:%notebook%)
|
||||
(ein:log 'info "Opening notebook %s..." path)
|
||||
(ein:notebook-request-open url-or-port path callback cbargs))))
|
||||
(ein:notebook-request-open url-or-port path kernelspec callback cbargs))))
|
||||
|
||||
(defun ein:notebook-request-open (url-or-port path &optional callback cbargs)
|
||||
(defun ein:notebook-request-open (url-or-port path &optional kernelspec callback cbargs)
|
||||
"Request notebook at PATH from the server at URL-OR-PORT.
|
||||
Return an `ein:$notebook' instance. Notebook kernel may not be ready to
|
||||
receive messages after this call is executed.
|
||||
|
@ -345,7 +351,7 @@ receive messages after this call is executed.
|
|||
CALLBACK is called as \(apply CALLBACK notebook t CBARGS). The second
|
||||
argument `t' indicates that the notebook is newly opened.
|
||||
See `ein:notebook-open' for more information."
|
||||
(let ((notebook (ein:notebook-new url-or-port path)))
|
||||
(let ((notebook (ein:notebook-new url-or-port path kernelspec)))
|
||||
(ein:log 'debug "Opening notebook at %s" path)
|
||||
(ein:content-query-contents path url-or-port nil
|
||||
(apply-partially #'ein:notebook-request-open-callback-with-callback
|
||||
|
@ -435,20 +441,35 @@ of minor mode."
|
|||
;;; Kernel related things
|
||||
|
||||
(defstruct ein:$kernelspec
|
||||
"Kernel specification as return by the Jupyter notebook server."
|
||||
"Kernel specification as return by the Jupyter notebook server.
|
||||
|
||||
`ein:$kernelspec-name' : string
|
||||
Name used to identify the kernel (like python2, or python3).
|
||||
|
||||
`ein:$kernelspec-resources' : plist
|
||||
Resources, if any, used by the kernel.
|
||||
|
||||
`ein:$kernelspec-spec' : plist
|
||||
How to start the kernel from the command line. Not used by ein (yet).
|
||||
"
|
||||
name
|
||||
resources
|
||||
spec)
|
||||
|
||||
(defvar ein:available-kernelspecs (make-hash-table))
|
||||
|
||||
(defun ein:get-kernelspec (url-or-port name)
|
||||
(let ((kernelspecs (gethash url-or-port ein:available-kernelspecs))
|
||||
(name (if (stringp name)
|
||||
(intern (format ":%s" name))
|
||||
name)))
|
||||
(plist-get kernelspecs name)))
|
||||
|
||||
(defun ein:list-available-kernels (url-or-port)
|
||||
(let ((kernelspecs (gethash url-or-port ein:available-kernelspecs)))
|
||||
(if kernelspecs
|
||||
(cons "default"
|
||||
(loop for (key spec) on (ein:plist-exclude kernelspecs '(:default)) by 'cddr
|
||||
collecting (ein:$kernelspec-name spec)))
|
||||
"default")))
|
||||
(loop for (key spec) on (ein:plist-exclude kernelspecs '(:default)) by 'cddr
|
||||
collecting (ein:$kernelspec-name spec)))))
|
||||
|
||||
(defun ein:query-kernelspecs (url-or-port)
|
||||
"Query jupyter server for the list of available
|
||||
|
|
|
@ -109,7 +109,7 @@ To suppress popup, you can pass a function `ein:do-nothing' as CALLBACK."
|
|||
for notebook-path = (plist-get note :path)
|
||||
when (equal notebook-name name)
|
||||
return (ein:notebook-open (ein:$notebooklist-url-or-port nblist)
|
||||
notebook-path callback cbargs)))
|
||||
notebook-path nil callback cbargs)))
|
||||
|
||||
(defun ein:notebooklist-url (url-or-port version &optional path)
|
||||
(let ((base-path (cond ((= version 2) "api/notebooks")
|
||||
|
@ -217,13 +217,17 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
(defun ein:notebooklist-open-notebook (nblist path &optional callback cbargs)
|
||||
(ein:notebook-open (ein:$notebooklist-url-or-port nblist)
|
||||
path
|
||||
nil
|
||||
callback
|
||||
cbargs))
|
||||
|
||||
;;;###autoload
|
||||
(defun ein:notebooklist-new-notebook (&optional url-or-port path callback cbargs)
|
||||
(defun ein:notebooklist-new-notebook (&optional url-or-port kernelspec path callback cbargs)
|
||||
"Ask server to create a new notebook and open it in a new buffer."
|
||||
(interactive (list (ein:notebooklist-ask-url-or-port)))
|
||||
(interactive (list (ein:notebooklist-ask-url-or-port)
|
||||
(completing-read
|
||||
"Select kernel [default]: "
|
||||
(ein:list-available-kernels url-or-port) nil t nil nil "default" nil)))
|
||||
(let ((path (or path (ein:$notebooklist-path (or ein:%notebooklist%
|
||||
(ein:notebooklist-list-get url-or-port)))))
|
||||
(version (ein:$notebooklist-api-version (or ein:%notebooklist%
|
||||
|
@ -248,9 +252,10 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
:error (apply-partially #'ein:notebooklist-new-notebook-error
|
||||
url-or-port path callback cbargs)
|
||||
:success (apply-partially #'ein:notebooklist-new-notebook-callback
|
||||
url-or-port path callback cbargs)))))
|
||||
url-or-port kernelspec path callback cbargs)))))
|
||||
|
||||
(defun* ein:notebooklist-new-notebook-callback (url-or-port
|
||||
kernelspec
|
||||
path
|
||||
callback
|
||||
cbargs
|
||||
|
@ -267,7 +272,7 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
(if (string= path "")
|
||||
(setq path name)
|
||||
(setq path (format "%s/%s" path name))))
|
||||
(ein:notebook-open url-or-port path callback cbargs))
|
||||
(ein:notebook-open url-or-port path kernelspec callback cbargs))
|
||||
(ein:log 'info (concat "Oops. EIN failed to open new notebook. "
|
||||
"Please find it in the notebook list."))
|
||||
(setq no-popup nil))
|
||||
|
@ -295,18 +300,19 @@ You may find the new one in the notebook list." error)
|
|||
"Open new notebook and rename the notebook."
|
||||
(interactive (let* ((url-or-port (or (ein:get-url-or-port)
|
||||
(ein:default-url-or-port)))
|
||||
(name (read-from-minibuffer
|
||||
(format "Notebook name (at %s): " url-or-port)))
|
||||
(kernelspec (completing-read
|
||||
"Select kernel [default]: "
|
||||
(ein:list-available-kernels url-or-port) nil t nil nil "default" nil)))
|
||||
(list name url-or-port)))
|
||||
(ein:list-available-kernels url-or-port) nil t nil nil "default" nil))
|
||||
(name (read-from-minibuffer
|
||||
(format "Notebook name (at %s): " url-or-port))))
|
||||
(list name kernelspec url-or-port)))
|
||||
(let ((path (or path (ein:$notebooklist-path
|
||||
(or ein:%notebooklist%
|
||||
(ein:get-notebook)
|
||||
(gethash url-or-port ein:notebooklist-map))))))
|
||||
(ein:notebooklist-new-notebook
|
||||
url-or-port
|
||||
kernelspec
|
||||
path
|
||||
(lambda (notebook created name)
|
||||
(assert created)
|
||||
|
@ -375,83 +381,96 @@ Notebook list data is passed via the buffer local variable
|
|||
path))
|
||||
name)))
|
||||
(widget-insert " |\n\n"))
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore) (ein:notebooklist-new-notebook))
|
||||
"New Notebook")
|
||||
(widget-insert " ")
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore) (ein:notebooklist-reload))
|
||||
"Reload List")
|
||||
(widget-insert " ")
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore)
|
||||
(browse-url
|
||||
(ein:url (ein:$notebooklist-url-or-port ein:%notebooklist%))))
|
||||
"Open In Browser")
|
||||
(widget-insert "\n\n")
|
||||
(let* ((kernels (ein:list-available-kernels (ein:$notebooklist-url-or-port ein:%notebooklist%)))
|
||||
(default-kernel (ein:get-kernelspec (ein:$notebooklist-url-or-port ein:%notebooklist%) (first kernels))))
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore) (call-interactively (ein:notebooklist-new-notebook (ein:$notebooklist-url-or-port ein:%notebooklist%)
|
||||
default-kernel)))
|
||||
"New Notebook")
|
||||
(widget-insert " ")
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore) (ein:notebooklist-reload))
|
||||
"Reload List")
|
||||
(widget-insert " ")
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lambda (&rest ignore)
|
||||
(browse-url
|
||||
(ein:url (ein:$notebooklist-url-or-port ein:%notebooklist%))))
|
||||
"Open In Browser")
|
||||
(widget-insert "\n\nAvailable Kernels:\n")
|
||||
(let* ((radio-widget (widget-create 'radio-button-choice
|
||||
:value (first kernels)
|
||||
:notify (lambda (widget &rest ignore)
|
||||
(setq default-kernel
|
||||
(ein:get-kernelspec (ein:$notebooklist-url-or-port ein:%notebooklist%) (widget-value widget)))
|
||||
(message "New notebooks will be started using the %s kernel."
|
||||
(widget-value widget))))))
|
||||
(dolist (k kernels)
|
||||
(widget-radio-add-item radio-widget (list 'item :value k)))))
|
||||
(widget-insert "\n")
|
||||
(let ((api-version (ein:$notebooklist-api-version ein:%notebooklist%))
|
||||
(sessions (make-hash-table :test 'equal)))
|
||||
(sessions (make-hash-table :test 'equal)))
|
||||
(ein:content-query-sessions sessions (ein:$notebooklist-url-or-port ein:%notebooklist%) t)
|
||||
(loop for note in (ein:$notebooklist-data ein:%notebooklist%)
|
||||
for urlport = (ein:$notebooklist-url-or-port ein:%notebooklist%)
|
||||
for name = (plist-get note :name)
|
||||
for path = (plist-get note :path)
|
||||
;; (cond ((= 2 api-version)
|
||||
;; (plist-get note :path))
|
||||
;; ((= 3 api-version)
|
||||
;; (ein:get-actual-path (plist-get note :path))))
|
||||
for type = (plist-get note :type)
|
||||
for opened-notebook-maybe = (ein:notebook-get-opened-notebook urlport path)
|
||||
do (widget-insert " ")
|
||||
if (string= type "directory")
|
||||
do (progn (widget-create
|
||||
'link
|
||||
:notify (lexical-let ((urlport urlport)
|
||||
(path name))
|
||||
(lambda (&rest ignore)
|
||||
(ein:notebooklist-open urlport
|
||||
(ein:url (ein:$notebooklist-path ein:%notebooklist%)
|
||||
path))))
|
||||
"Dir")
|
||||
(widget-insert " : " name)
|
||||
(widget-insert "\n"))
|
||||
if (string= type "notebook")
|
||||
do (progn (widget-create
|
||||
'link
|
||||
:notify (lexical-let ((name name)
|
||||
(path path))
|
||||
(lambda (&rest ignore)
|
||||
(run-at-time 3 nil
|
||||
#'ein:notebooklist-reload ein:%notebooklist%) ;; TODO using deferred better?
|
||||
(ein:notebooklist-open-notebook
|
||||
ein:%notebooklist% path)))
|
||||
"Open")
|
||||
(widget-insert " ")
|
||||
(when (gethash path sessions)
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lexical-let ((session (car (gethash path sessions)))
|
||||
(nblist ein:%notebooklist%))
|
||||
(lambda (&rest ignore)
|
||||
(run-at-time 1 nil
|
||||
#'ein:notebooklist-reload
|
||||
ein:%notebooklist%)
|
||||
(ein:kernel-kill (make-ein:$kernel :url-or-port (ein:$notebooklist-url-or-port nblist)
|
||||
:session-id session))))
|
||||
"Stop")
|
||||
(widget-insert " "))
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lexical-let ((path path))
|
||||
(lambda (&rest ignore)
|
||||
(ein:notebooklist-delete-notebook-ask
|
||||
path)))
|
||||
"Delete")
|
||||
(widget-insert " : " name)
|
||||
(widget-insert "\n"))))
|
||||
for urlport = (ein:$notebooklist-url-or-port ein:%notebooklist%)
|
||||
for name = (plist-get note :name)
|
||||
for path = (plist-get note :path)
|
||||
;; (cond ((= 2 api-version)
|
||||
;; (plist-get note :path))
|
||||
;; ((= 3 api-version)
|
||||
;; (ein:get-actual-path (plist-get note :path))))
|
||||
for type = (plist-get note :type)
|
||||
for opened-notebook-maybe = (ein:notebook-get-opened-notebook urlport path)
|
||||
do (widget-insert " ")
|
||||
if (string= type "directory")
|
||||
do (progn (widget-create
|
||||
'link
|
||||
:notify (lexical-let ((urlport urlport)
|
||||
(path name))
|
||||
(lambda (&rest ignore)
|
||||
(ein:notebooklist-open urlport
|
||||
(ein:url (ein:$notebooklist-path ein:%notebooklist%)
|
||||
path))))
|
||||
"Dir")
|
||||
(widget-insert " : " name)
|
||||
(widget-insert "\n"))
|
||||
if (string= type "notebook")
|
||||
do (progn (widget-create
|
||||
'link
|
||||
:notify (lexical-let ((name name)
|
||||
(path path))
|
||||
(lambda (&rest ignore)
|
||||
(run-at-time 3 nil
|
||||
#'ein:notebooklist-reload ein:%notebooklist%) ;; TODO using deferred better?
|
||||
(ein:notebooklist-open-notebook
|
||||
ein:%notebooklist% path)))
|
||||
"Open")
|
||||
(widget-insert " ")
|
||||
(when (gethash path sessions)
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lexical-let ((session (car (gethash path sessions)))
|
||||
(nblist ein:%notebooklist%))
|
||||
(lambda (&rest ignore)
|
||||
(run-at-time 1 nil
|
||||
#'ein:notebooklist-reload
|
||||
ein:%notebooklist%)
|
||||
(ein:kernel-kill (make-ein:$kernel :url-or-port (ein:$notebooklist-url-or-port nblist)
|
||||
:session-id session))))
|
||||
"Stop")
|
||||
(widget-insert " "))
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lexical-let ((path path))
|
||||
(lambda (&rest ignore)
|
||||
(ein:notebooklist-delete-notebook-ask
|
||||
path)))
|
||||
"Delete")
|
||||
(widget-insert " : " name)
|
||||
(widget-insert "\n"))))
|
||||
(ein:notebooklist-mode)
|
||||
(widget-setup))
|
||||
|
||||
|
@ -497,7 +516,7 @@ When used in lisp, CALLBACK and CBARGS are passed to `ein:notebook-open'."
|
|||
(when (and (stringp url-or-port)
|
||||
(string-match "^[0-9]+$" url-or-port))
|
||||
(setq url-or-port (string-to-number url-or-port)))
|
||||
(ein:notebook-open url-or-port path callback cbargs)
|
||||
(ein:notebook-open url-or-port path nil callback cbargs)
|
||||
(ein:log 'info "Notebook '%s' not found" nbpath)))
|
||||
|
||||
;;;###autoload
|
||||
|
@ -565,7 +584,7 @@ upload the current file to the server.
|
|||
(unless noerror
|
||||
(assert found nil "No server has notebook named: %s" name))
|
||||
(destructuring-bind (url-or-port path) found
|
||||
(ein:notebook-open url-or-port path callback cbargs))))
|
||||
(ein:notebook-open url-or-port path nil callback cbargs))))
|
||||
|
||||
(defvar ein:notebooklist-find-file-buffer-callback #'ignore)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue