2012-05-07 14:41:15 +02:00
|
|
|
|
;;; ein-notebooklist.el --- Notebook list buffer
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2012- Takafumi Arakaki
|
|
|
|
|
|
|
|
|
|
;; Author: Takafumi Arakaki
|
|
|
|
|
|
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
|
|
|
|
|
|
;; ein-notebooklist.el is free software: you can redistribute it and/or modify
|
|
|
|
|
;; it under the terms of the GNU General Public License as published by
|
|
|
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
;; (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
;; ein-notebooklist.el 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 ein-notebooklist.el. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(eval-when-compile (require 'cl))
|
|
|
|
|
(require 'widget)
|
|
|
|
|
|
|
|
|
|
(require 'ein-utils)
|
|
|
|
|
(require 'ein-notebook)
|
2012-05-19 15:47:09 +02:00
|
|
|
|
(require 'ein-subpackages)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defstruct ein:$notebooklist
|
|
|
|
|
"Hold notebooklist variables.
|
|
|
|
|
|
|
|
|
|
`ein:$notebooklist-url-or-port'
|
|
|
|
|
URL or port of IPython server.
|
|
|
|
|
|
|
|
|
|
`ein:$notebooklist-data'
|
|
|
|
|
JSON data sent from the server."
|
|
|
|
|
url-or-port
|
|
|
|
|
data)
|
|
|
|
|
|
|
|
|
|
(ein:deflocal ein:notebooklist nil
|
|
|
|
|
"Buffer local variable to store an instance of `ein:$notebooklist'.")
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defvar ein:notebooklist-buffer-name-template "*ein:notebooklist %s*")
|
|
|
|
|
|
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebooklist-url (url-or-port)
|
|
|
|
|
(ein:url url-or-port "notebooks"))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebooklist-new-url (url-or-port)
|
|
|
|
|
(ein:url url-or-port "new"))
|
2012-05-12 00:34:00 +02:00
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebooklist-get-buffer (url-or-port)
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(get-buffer-create
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(format ein:notebooklist-buffer-name-template url-or-port)))
|
2012-05-12 00:34:00 +02:00
|
|
|
|
|
2012-05-14 18:47:08 +02:00
|
|
|
|
;;;###autoload
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebooklist-open (&optional url-or-port no-popup)
|
2012-05-12 00:59:15 +02:00
|
|
|
|
"Open notebook list buffer."
|
2012-05-13 05:33:20 +02:00
|
|
|
|
(interactive
|
2012-05-16 19:56:11 +02:00
|
|
|
|
(list (completing-read "URL or port number (hit TAB to complete): "
|
2012-05-16 19:44:01 +02:00
|
|
|
|
(mapcar (lambda (x) (format "%s" x))
|
2012-05-16 19:56:11 +02:00
|
|
|
|
ein:url-or-port))))
|
2012-05-16 19:44:01 +02:00
|
|
|
|
(unless url-or-port (setq url-or-port (or (car ein:url-or-port) 8888)))
|
2012-05-19 15:47:09 +02:00
|
|
|
|
(ein:subpackages-load)
|
2012-05-13 06:26:51 +02:00
|
|
|
|
(when (and (stringp url-or-port)
|
|
|
|
|
(string-match "^[0-9]+$" url-or-port))
|
|
|
|
|
(setq url-or-port (string-to-number url-or-port)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(url-retrieve
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(ein:notebooklist-url url-or-port)
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(if no-popup
|
2012-05-13 02:51:47 +02:00
|
|
|
|
#'ein:notebooklist-url-retrieve-callback
|
|
|
|
|
(lambda (&rest args)
|
|
|
|
|
(pop-to-buffer (apply #'ein:notebooklist-url-retrieve-callback args))))
|
2012-05-17 20:12:40 +02:00
|
|
|
|
(list url-or-port))
|
|
|
|
|
(ein:notebooklist-get-buffer url-or-port))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebooklist-url-retrieve-callback (status url-or-port)
|
2012-05-12 00:59:15 +02:00
|
|
|
|
"Called via `ein:notebooklist-open'."
|
2012-05-13 06:24:46 +02:00
|
|
|
|
(ein:aif (plist-get status :error)
|
|
|
|
|
(error "Failed to connect to server '%s'. Got: %S"
|
|
|
|
|
(ein:url url-or-port) it))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(let ((data (ein:json-read)))
|
|
|
|
|
(kill-buffer (current-buffer))
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
|
|
|
|
(setq ein:notebooklist
|
|
|
|
|
(make-ein:$notebooklist :url-or-port url-or-port
|
|
|
|
|
:data data))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:notebooklist-render)
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(current-buffer))))
|
|
|
|
|
|
2012-05-13 05:18:38 +02:00
|
|
|
|
(defun ein:notebooklist-reload ()
|
|
|
|
|
"Reload current Notebook list."
|
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebooklist-open (ein:$notebooklist-url-or-port ein:notebooklist) t))
|
|
|
|
|
|
2012-05-18 02:23:30 +02:00
|
|
|
|
(defun ein:notebooklist-get-data-in-body-tag (key)
|
|
|
|
|
"Very ad-hoc parser to get data in body tag."
|
|
|
|
|
(ignore-errors
|
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char (point-min))
|
|
|
|
|
(search-forward "<body")
|
|
|
|
|
(search-forward-regexp (format "%s=\\([^[:space:]\n]+\\)" key))
|
|
|
|
|
(match-string 1))))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebooklist-open-notebook (nbist notebook-id &optional name)
|
|
|
|
|
(message "Open notebook %s." (or name notebook-id))
|
|
|
|
|
(ein:notebook-open (ein:$notebooklist-url-or-port nbist) notebook-id))
|
|
|
|
|
|
2012-05-17 20:47:23 +02:00
|
|
|
|
(defun ein:notebooklist-new-notebook (&optional url-or-port)
|
2012-05-12 00:59:15 +02:00
|
|
|
|
"Ask server to create a new notebook and update the notebook list buffer."
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(message "Creating a new notebook...")
|
2012-05-17 20:47:23 +02:00
|
|
|
|
(unless (setq url-or-port (ein:$notebooklist-url-or-port ein:notebooklist)))
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(url-retrieve
|
2012-05-17 20:47:23 +02:00
|
|
|
|
(ein:notebooklist-new-url url-or-port)
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(lambda (s buffer)
|
2012-05-18 02:23:30 +02:00
|
|
|
|
(let ((notebook-id
|
|
|
|
|
(ein:notebooklist-get-data-in-body-tag "data-notebook-id")))
|
|
|
|
|
(kill-buffer (current-buffer))
|
|
|
|
|
(message "Creating a new notebook... Done.")
|
|
|
|
|
(with-current-buffer buffer
|
|
|
|
|
(if notebook-id
|
|
|
|
|
(ein:notebooklist-open-notebook ein:notebooklist notebook-id)
|
|
|
|
|
(message (concat "Oops. EIN failed to open new notebook. "
|
|
|
|
|
"Please find it in the notebook list."))
|
|
|
|
|
(ein:notebooklist-reload)))))
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(list (current-buffer))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-13 06:51:26 +02:00
|
|
|
|
(defun ein:notebooklist-delete-notebook-ask (notebook-id name)
|
|
|
|
|
(when (y-or-n-p (format "Delete notebook %s?" name))
|
|
|
|
|
(ein:notebooklist-delete-notebook notebook-id name)))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebooklist-delete-notebook (notebook-id name)
|
|
|
|
|
(message "Deleting notebook %s..." name)
|
|
|
|
|
(let ((url (ein:url-no-cache
|
|
|
|
|
(ein:notebook-url-from-url-and-id
|
|
|
|
|
(ein:$notebooklist-url-or-port ein:notebooklist)
|
|
|
|
|
notebook-id)))
|
|
|
|
|
(url-request-method "DELETE"))
|
|
|
|
|
(url-retrieve
|
|
|
|
|
url
|
|
|
|
|
(lambda (s buffer name)
|
|
|
|
|
(kill-buffer (current-buffer))
|
|
|
|
|
(message "Deleting notebook %s... Done." name)
|
|
|
|
|
(with-current-buffer buffer
|
|
|
|
|
(ein:notebooklist-reload)))
|
|
|
|
|
(list (current-buffer) name))))
|
2012-05-12 00:59:15 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:notebooklist-render ()
|
2012-05-12 00:59:15 +02:00
|
|
|
|
"Render notebook list widget.
|
|
|
|
|
Notebook list data is passed via the buffer local variable
|
|
|
|
|
`ein:notebooklist-data'."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(kill-all-local-variables)
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer))
|
|
|
|
|
(remove-overlays)
|
|
|
|
|
;; Create notebook list
|
2012-05-12 00:48:39 +02:00
|
|
|
|
(widget-insert "IPython Notebook list\n\n")
|
2012-05-12 00:34:00 +02:00
|
|
|
|
(widget-create
|
|
|
|
|
'link
|
|
|
|
|
:notify (lambda (&rest ignore) (ein:notebooklist-new-notebook))
|
|
|
|
|
"New Notebook")
|
2012-05-13 05:18:38 +02:00
|
|
|
|
(widget-insert " ")
|
|
|
|
|
(widget-create
|
|
|
|
|
'link
|
|
|
|
|
:notify (lambda (&rest ignore) (ein:notebooklist-reload))
|
|
|
|
|
"Reload List")
|
2012-05-19 17:09:22 +02:00
|
|
|
|
(widget-insert " ")
|
|
|
|
|
(widget-create
|
|
|
|
|
'link
|
|
|
|
|
:notify (lambda (&rest ignore)
|
|
|
|
|
(browse-url
|
|
|
|
|
(ein:url (ein:$notebooklist-url-or-port ein:notebooklist))))
|
|
|
|
|
"Open In Browser")
|
2012-05-12 00:48:39 +02:00
|
|
|
|
(widget-insert "\n")
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(loop for note in (ein:$notebooklist-data ein:notebooklist)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
for name = (plist-get note :name)
|
|
|
|
|
for notebook-id = (plist-get note :notebook_id)
|
2012-05-12 00:48:39 +02:00
|
|
|
|
do (progn (widget-create
|
2012-05-07 14:41:15 +02:00
|
|
|
|
'link
|
|
|
|
|
:notify (lexical-let ((name name)
|
|
|
|
|
(notebook-id notebook-id))
|
|
|
|
|
(lambda (&rest ignore)
|
2012-05-18 02:23:30 +02:00
|
|
|
|
(ein:notebooklist-open-notebook
|
|
|
|
|
ein:notebooklist notebook-id name)))
|
2012-05-12 00:48:39 +02:00
|
|
|
|
"Open")
|
2012-05-13 06:51:26 +02:00
|
|
|
|
(widget-insert " ")
|
|
|
|
|
(widget-create
|
|
|
|
|
'link
|
|
|
|
|
:notify (lexical-let ((name name)
|
|
|
|
|
(notebook-id notebook-id))
|
|
|
|
|
(lambda (&rest ignore)
|
|
|
|
|
(ein:notebooklist-delete-notebook-ask
|
|
|
|
|
notebook-id
|
|
|
|
|
name)))
|
|
|
|
|
"Delete")
|
|
|
|
|
(widget-insert " : " name)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(widget-insert "\n")))
|
2012-05-15 03:41:08 +02:00
|
|
|
|
(ein:notebooklist-mode)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(widget-setup))
|
|
|
|
|
|
2012-05-15 03:41:08 +02:00
|
|
|
|
|
|
|
|
|
;;; Notebook list mode
|
|
|
|
|
|
|
|
|
|
(define-derived-mode ein:notebooklist-mode fundamental-mode "ein:notebooklist"
|
|
|
|
|
"IPython notebook list mode.")
|
|
|
|
|
|
2012-05-15 04:16:06 +02:00
|
|
|
|
(defun ein:notebooklist-prev-item () (interactive) (move-beginning-of-line 0))
|
|
|
|
|
(defun ein:notebooklist-next-item () (interactive) (move-beginning-of-line 2))
|
|
|
|
|
|
2012-05-15 03:44:53 +02:00
|
|
|
|
(setq
|
|
|
|
|
ein:notebooklist-mode-map
|
|
|
|
|
(let ((map (copy-keymap widget-keymap)))
|
|
|
|
|
(define-key map "g" 'ein:notebooklist-reload)
|
2012-05-15 04:16:06 +02:00
|
|
|
|
(define-key map "p" 'ein:notebooklist-prev-item)
|
|
|
|
|
(define-key map "n" 'ein:notebooklist-next-item)
|
2012-05-17 03:30:33 +02:00
|
|
|
|
(define-key map "q" 'bury-buffer)
|
2012-05-15 03:44:53 +02:00
|
|
|
|
map))
|
2012-05-15 03:41:08 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(provide 'ein-notebooklist)
|
|
|
|
|
|
|
|
|
|
;;; ein-notebooklist.el ends here
|