;;; 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 . ;;; Commentary: ;; ;;; Code: (eval-when-compile (require 'cl)) (require 'widget) (require 'ein-utils) (require 'ein-notebook) (require 'ein-subpackages) (defcustom ein:notebooklist-first-open-hook nil "Hooks to run when the notebook list is opened at first time. Example to open a notebook named _scratch_ when the notebook list is opened at first time.:: (add-hook 'ein:notebooklist-first-open-hook (lambda () (ein:notebooklist-open-notebook-by-name \"_scratch_\"))) " :type 'hook :group 'ein) (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'.") (defvar ein:notebooklist-buffer-name-template "*ein:notebooklist %s*") (defvar ein:notebooklist-map (make-hash-table :test 'equal) "Data store for `ein:notebooklist-list'. Mapping from URL-OR-PORT to an instance of `ein:$notebooklist'.") (defun ein:notebooklist-list () "Get a list of opened `ein:$notebooklist'." (ein:hash-vals ein:notebooklist-map)) (defun ein:notebooklist-list-add (nblist) "Register notebook list instance NBLIST for global lookup. This function adds NBLIST to `ein:notebooklist-map'." (puthash (ein:$notebooklist-url-or-port nblist) nblist ein:notebooklist-map)) (defun ein:notebooklist-list-get (url-or-port) "Get an instance of `ein:$notebooklist' by URL-OR-PORT as a key." (gethash url-or-port ein:notebooklist-map)) (defun ein:notebooklist-open-notebook-by-name (name &optional url-or-port) "Open notebook named NAME in the server URL-OR-PORT. If URL-OR-PORT is not given or `nil', and the current buffer is the notebook list buffer, the notebook is searched in the notebook list of the current buffer." ;; FIXME: Support no-popup argument to open notebook in background. (loop with nblist = (if url-or-port (ein:notebooklist-list-get url-or-port) ein:notebooklist) for note in (ein:$notebooklist-data nblist) for notebook-name = (plist-get note :name) for notebook-id = (plist-get note :notebook_id) when (equal notebook-name name) return (ein:notebook-open (ein:$notebooklist-url-or-port nblist) notebook-id))) (defun ein:notebooklist-url (url-or-port) (ein:url url-or-port "notebooks")) (defun ein:notebooklist-new-url (url-or-port) (ein:url url-or-port "new")) (defun ein:notebooklist-get-buffer (url-or-port) (get-buffer-create (format ein:notebooklist-buffer-name-template url-or-port))) (defun ein:notebooklist-ask-url-or-port () (let* ((url-or-port-list (mapcar (lambda (x) (format "%s" x)) ein:url-or-port)) (default (format "%s" (ein:aif (ein:pytools-get-notebook) (ein:$notebook-url-or-port it) (ein:aif ein:notebooklist (ein:$notebooklist-url-or-port it) (ein:default-url-or-port))))) (url-or-port (completing-read (format "URL or port number (default %s): " default) url-or-port-list nil nil nil nil default))) (if (string-match "^[0-9]+$" url-or-port) (string-to-number url-or-port) url-or-port))) ;;;###autoload (defun ein:notebooklist-open (&optional url-or-port no-popup) "Open notebook list buffer." (interactive (list (ein:notebooklist-ask-url-or-port))) (unless url-or-port (setq url-or-port (ein:default-url-or-port))) (ein:subpackages-load) (let ((success (if no-popup #'ein:notebooklist-url-retrieve-callback (lambda (&rest args) (pop-to-buffer (apply #'ein:notebooklist-url-retrieve-callback args)))))) (ein:query-singleton-ajax (list 'notebooklist-open url-or-port) (ein:notebooklist-url url-or-port) :cache nil :parser #'ein:json-read :error (cons #'ein:notebooklist-open-error url-or-port) :success (cons success url-or-port))) (ein:notebooklist-get-buffer url-or-port)) (defun* ein:notebooklist-url-retrieve-callback (url-or-port &key status data &allow-other-keys) "Called via `ein:notebooklist-open'." (ein:aif (plist-get status :error) (error "Failed to connect to server '%s'. Got: %S" (ein:url url-or-port) it)) (with-current-buffer (ein:notebooklist-get-buffer url-or-port) (let ((already-opened-p (ein:notebooklist-list-get url-or-port))) (setq ein:notebooklist (make-ein:$notebooklist :url-or-port url-or-port :data data)) (ein:notebooklist-list-add ein:notebooklist) (ein:notebooklist-render) (goto-char (point-min)) (message "Opened notebook list at %s" url-or-port) (unless already-opened-p (run-hooks 'ein:notebooklist-first-open-hook)) (current-buffer)))) (defun* ein:notebooklist-open-error (url-or-port &key symbol-status &allow-other-keys) (ein:log 'error "Error (%s) while opening notebook list at the server %s." symbol-status url-or-port)) (defun ein:notebooklist-reload () "Reload current Notebook list." (interactive) (ein:notebooklist-open (ein:$notebooklist-url-or-port ein:notebooklist) t)) (defun ein:notebooklist-refresh-related () "Reload notebook list in which current notebook locates. This function is called via `ein:notebook-after-rename-hook'." (ein:notebooklist-open (ein:$notebook-url-or-port ein:notebook) t)) (add-hook 'ein:notebook-after-rename-hook 'ein:notebooklist-refresh-related) (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 "