2012-05-07 14:41:15 +02:00
|
|
|
|
;;; ein-notebook.el --- Notebook module
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2012- Takafumi Arakaki
|
|
|
|
|
|
2012-07-01 20:18:05 +02:00
|
|
|
|
;; Author: Takafumi Arakaki <aka.tkf at gmail.com>
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
|
|
|
|
|
|
;; ein-notebook.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-notebook.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-notebook.el. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2012-05-25 22:58:01 +02:00
|
|
|
|
;; * Coding rule about current buffer.
|
|
|
|
|
;; A lot of notebook and cell functions touches to current buffer and
|
|
|
|
|
;; it is not ideal to wrap all these functions by `with-current-buffer'.
|
|
|
|
|
;; Therefore, when the function takes `notebook' to the first argument
|
|
|
|
|
;; ("method" function), it is always assumed that the current buffer
|
|
|
|
|
;; is the notebook buffer. **However**, functions called as callback
|
|
|
|
|
;; (via `url-retrieve', for example) must protect themselves by
|
|
|
|
|
;; calling from unknown buffer.
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(eval-when-compile (require 'cl))
|
|
|
|
|
(require 'ewoc)
|
2012-08-01 20:04:47 +02:00
|
|
|
|
(eval-when-compile (require 'auto-complete nil t))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(require 'ein-utils)
|
|
|
|
|
(require 'ein-log)
|
|
|
|
|
(require 'ein-node)
|
|
|
|
|
(require 'ein-kernel)
|
|
|
|
|
(require 'ein-cell)
|
2012-08-19 11:58:04 +02:00
|
|
|
|
(require 'ein-worksheet)
|
2012-05-15 21:46:17 +02:00
|
|
|
|
(require 'ein-completer)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(require 'ein-pager)
|
|
|
|
|
(require 'ein-events)
|
2012-05-25 02:02:31 +02:00
|
|
|
|
(require 'ein-notification)
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(require 'ein-kill-ring)
|
2012-05-25 22:12:34 +02:00
|
|
|
|
(require 'ein-query)
|
2012-06-03 17:30:16 +02:00
|
|
|
|
(require 'ein-pytools)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-25 00:23:09 +02:00
|
|
|
|
|
|
|
|
|
;;; Configuration
|
|
|
|
|
|
2012-06-16 21:35:16 +02:00
|
|
|
|
(defcustom ein:notebook-enable-undo 'yes
|
|
|
|
|
"Configure undo in notebook buffers.
|
|
|
|
|
|
|
|
|
|
`no' : symbol
|
|
|
|
|
Do not use undo in notebook buffers. It is the safest option.
|
|
|
|
|
`yes' : symbol
|
|
|
|
|
Enable undo in notebook buffers. You can't undo after
|
|
|
|
|
modification of cell (execution, add, remove, etc.). This
|
|
|
|
|
is default.
|
|
|
|
|
`full' : symbol
|
|
|
|
|
Enable full undo in notebook buffers. It is powerful but
|
|
|
|
|
sometime (typically after the cell specific commands) undo
|
|
|
|
|
mess up notebook buffer. Use it on your own risk. When the
|
|
|
|
|
buffer is messed up, you can just redo and continue editing,
|
|
|
|
|
or save it once and reopen it if you want to be careful.
|
|
|
|
|
|
|
|
|
|
You need to reopen the notebook buffer to reflect the change of
|
|
|
|
|
this value."
|
|
|
|
|
:type '(choice (const :tag "No" no)
|
|
|
|
|
(const :tag "Yes" yes)
|
|
|
|
|
(const :tag "Full" full))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-empty-undo-maybe ()
|
|
|
|
|
"Empty `buffer-undo-list' if `ein:notebook-enable-undo' is `yes'."
|
|
|
|
|
(when (eq ein:notebook-enable-undo 'yes)
|
|
|
|
|
(setq buffer-undo-list nil)))
|
|
|
|
|
|
2012-05-25 00:23:09 +02:00
|
|
|
|
(defcustom ein:notebook-discard-output-on-save 'no
|
|
|
|
|
"Configure if the output part of the cell should be saved or not.
|
|
|
|
|
|
2012-06-11 04:21:30 +02:00
|
|
|
|
`no' : symbol
|
|
|
|
|
Save output. This is the default.
|
|
|
|
|
`yes' : symbol
|
|
|
|
|
Always discard output.
|
|
|
|
|
a function
|
|
|
|
|
This function takes two arguments, notebook and cell. Return
|
|
|
|
|
`t' to discard output and return `nil' to save. For example,
|
|
|
|
|
if you don't want to save image output but other kind of
|
|
|
|
|
output, use `ein:notebook-cell-has-image-output-p'.
|
2012-05-25 00:23:09 +02:00
|
|
|
|
|
2012-06-23 01:06:24 +02:00
|
|
|
|
Note that using function needs EIN lisp API, which is not determined
|
2012-05-25 00:23:09 +02:00
|
|
|
|
yet. So be careful when using EIN functions. They may change."
|
|
|
|
|
:type '(choice (const :tag "No" 'no)
|
|
|
|
|
(const :tag "Yes" 'yes)
|
|
|
|
|
;; FIXME: this must be go to the customize UI after
|
|
|
|
|
;; clarifying the notebook lisp API.
|
|
|
|
|
;; (function :tag "Predicate" (lambda () t))
|
|
|
|
|
)
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-10 04:04:31 +02:00
|
|
|
|
(defun ein:notebook-cell-has-image-output-p (-ignore- cell)
|
|
|
|
|
(ein:cell-has-image-ouput-p cell))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-discard-output-p (notebook cell)
|
2012-05-25 00:23:09 +02:00
|
|
|
|
"Return non-`nil' if the output must be discarded, otherwise save."
|
|
|
|
|
(case ein:notebook-discard-output-on-save
|
|
|
|
|
(no nil)
|
|
|
|
|
(yes t)
|
2012-06-10 04:04:31 +02:00
|
|
|
|
(t (funcall ein:notebook-discard-output-on-save notebook cell))))
|
2012-05-25 00:23:09 +02:00
|
|
|
|
|
2012-06-21 00:01:23 +02:00
|
|
|
|
;; As opening/saving notebook treats possibly huge data, define these
|
|
|
|
|
;; timeouts separately:
|
|
|
|
|
|
|
|
|
|
(defcustom ein:notebook-querty-timeout-open (* 60 1000) ; 1 min
|
2012-06-21 00:38:15 +02:00
|
|
|
|
"Query timeout for opening notebook.
|
|
|
|
|
If you cannot open large notebook because of timeout error, try
|
2012-06-21 03:53:51 +02:00
|
|
|
|
to increase this value. Setting this value to `nil' means to use
|
|
|
|
|
global setting. For global setting and more information, see
|
|
|
|
|
`ein:query-timeout'."
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:type '(choice (integer :tag "Timeout [ms]" 5000)
|
2012-06-21 03:53:51 +02:00
|
|
|
|
(const :tag "Use global setting" nil))
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-21 01:05:42 +02:00
|
|
|
|
(defcustom ein:notebook-querty-timeout-save (* 60 1000) ; 1 min
|
2012-06-21 00:38:15 +02:00
|
|
|
|
"Query timeout for saving notebook.
|
|
|
|
|
Similar to `ein:notebook-querty-timeout-open', but for saving
|
|
|
|
|
notebook. For global setting and more information, see
|
|
|
|
|
`ein:query-timeout'."
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:type '(choice (integer :tag "Timeout [ms]" 5000)
|
2012-06-21 03:53:51 +02:00
|
|
|
|
(const :tag "Use global setting" nil))
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(defvar ein:notebook-after-rename-hook nil
|
|
|
|
|
"Hooks to run after notebook is renamed successfully.
|
|
|
|
|
Current buffer for these functions is set to the notebook buffer.")
|
|
|
|
|
|
2012-05-25 00:23:09 +02:00
|
|
|
|
|
|
|
|
|
;;; Class and variable
|
|
|
|
|
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(defvar ein:base-kernel-url "/")
|
|
|
|
|
;; Currently there is no way to know this setting. Maybe I should ask
|
|
|
|
|
;; IPython developers for an API to get this from notebook server.
|
|
|
|
|
|
2012-05-14 17:07:09 +02:00
|
|
|
|
(defvar ein:notebook-pager-buffer-name-template "*ein:pager %s/%s*")
|
2012-05-13 04:29:27 +02:00
|
|
|
|
(defvar ein:notebook-buffer-name-template "*ein: %s/%s*")
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-17 04:08:18 +02:00
|
|
|
|
(defvar ein:notebook-save-retry-max 1
|
|
|
|
|
"Maximum retries for notebook saving.")
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defstruct ein:$notebook
|
2012-05-13 02:51:47 +02:00
|
|
|
|
"Hold notebook variables.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-url-or-port'
|
|
|
|
|
URL or port of IPython server.
|
|
|
|
|
|
2012-05-13 05:46:24 +02:00
|
|
|
|
`ein:$notebook-notebook-id' : string
|
|
|
|
|
uuid string
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-kernel' : `ein:$kernel'
|
|
|
|
|
`ein:$kernel' instance.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-pager'
|
|
|
|
|
Variable for `ein:pager-*' functions. See ein-pager.el.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-dirty' : boolean
|
|
|
|
|
Set to `t' if notebook has unsaved changes. Otherwise `nil'.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-metadata' : plist
|
|
|
|
|
Notebook meta data (e.g., notebook name).
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-name' : string
|
|
|
|
|
Notebook name.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-nbformat' : integer
|
2012-05-22 13:56:24 +02:00
|
|
|
|
Notebook file format version.
|
|
|
|
|
|
2012-08-12 19:43:39 +02:00
|
|
|
|
`ein:$notebook-nbformat-minor' : integer
|
|
|
|
|
Notebook file format version.
|
|
|
|
|
|
2012-05-22 13:56:24 +02:00
|
|
|
|
`ein:$notebook-events' : `ein:$events'
|
2012-05-25 02:02:31 +02:00
|
|
|
|
Event handler instance.
|
|
|
|
|
|
2012-08-19 11:58:04 +02:00
|
|
|
|
`ein:$notebook-worksheets' : list of `ein:worksheet'
|
|
|
|
|
List of worksheets.
|
2012-08-13 18:47:21 +02:00
|
|
|
|
"
|
2012-05-13 02:51:47 +02:00
|
|
|
|
url-or-port
|
2012-05-13 05:46:24 +02:00
|
|
|
|
notebook-id
|
|
|
|
|
kernel
|
|
|
|
|
pager
|
|
|
|
|
dirty
|
|
|
|
|
metadata
|
|
|
|
|
notebook-name
|
|
|
|
|
nbformat
|
2012-08-12 19:43:39 +02:00
|
|
|
|
nbformat-minor
|
2012-05-22 13:56:24 +02:00
|
|
|
|
events
|
2012-08-19 11:58:04 +02:00
|
|
|
|
worksheets
|
2012-05-07 14:41:15 +02:00
|
|
|
|
)
|
|
|
|
|
|
2012-08-19 11:58:04 +02:00
|
|
|
|
;; FIXME: Remove `ein:%notebook%' when worksheet is fully implemented.
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:deflocal ein:%notebook% nil
|
2012-05-12 22:55:06 +02:00
|
|
|
|
"Buffer local variable to store an instance of `ein:$notebook'.")
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(define-obsolete-variable-alias 'ein:notebook 'ein:%notebook% "0.1.2")
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-13 04:07:49 +02:00
|
|
|
|
(defun ein:notebook-new (url-or-port notebook-id &rest args)
|
2012-05-11 05:24:34 +02:00
|
|
|
|
(let ((notebook (apply #'make-ein:$notebook
|
2012-05-13 02:51:47 +02:00
|
|
|
|
:url-or-port url-or-port
|
2012-05-11 05:24:34 +02:00
|
|
|
|
:notebook-id notebook-id
|
|
|
|
|
args)))
|
|
|
|
|
notebook))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-19 17:58:02 +02:00
|
|
|
|
(defun ein:notebook-del (notebook)
|
|
|
|
|
"Destructor for `ein:$notebook'."
|
2012-05-25 16:11:26 +02:00
|
|
|
|
(ein:log-ignore-errors
|
|
|
|
|
(ein:kernel-del (ein:$notebook-kernel notebook))))
|
2012-05-19 17:58:02 +02:00
|
|
|
|
|
2012-05-17 20:12:40 +02:00
|
|
|
|
(defun ein:notebook-buffer (notebook)
|
|
|
|
|
"Return the buffer that is associated with NOTEBOOK."
|
2012-08-19 11:58:04 +02:00
|
|
|
|
;; FIXME: Find a better way to define notebook buffer! (or remove this func)
|
|
|
|
|
(loop for ws in (ein:$notebook-worksheets notebook)
|
|
|
|
|
if (ein:worksheet-buffer ws) return it))
|
2012-05-17 20:12:40 +02:00
|
|
|
|
|
2012-08-14 20:39:05 +02:00
|
|
|
|
(defalias 'ein:notebook-name 'ein:$notebook-notebook-name)
|
|
|
|
|
|
2012-05-12 23:13:28 +02:00
|
|
|
|
(defun ein:notebook-url (notebook)
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(ein:notebook-url-from-url-and-id (ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-id notebook)))
|
2012-05-12 23:13:28 +02:00
|
|
|
|
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(defun ein:notebook-url-from-url-and-id (url-or-port notebook-id)
|
|
|
|
|
(ein:url url-or-port "notebooks" notebook-id))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-12 02:44:34 +02:00
|
|
|
|
(defun ein:notebook-pop-to-current-buffer (&rest -ignore-)
|
|
|
|
|
"Default callback for `ein:notebook-open'."
|
|
|
|
|
(pop-to-buffer (current-buffer)))
|
|
|
|
|
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(defun ein:notebook-open (url-or-port notebook-id &optional callback cbargs)
|
|
|
|
|
"Open notebook of NOTEBOOK-ID 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.
|
|
|
|
|
|
2012-07-12 02:44:34 +02:00
|
|
|
|
After the notebook is opened, CALLBACK is called as::
|
|
|
|
|
|
2012-06-08 11:42:42 +02:00
|
|
|
|
\(apply CALLBACK notebook CREATED CBARGS)
|
2012-07-12 02:44:34 +02:00
|
|
|
|
|
2012-06-08 11:42:42 +02:00
|
|
|
|
where the second argument CREATED indicates whether the notebook
|
2012-07-12 02:44:34 +02:00
|
|
|
|
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."
|
|
|
|
|
(unless callback (setq callback #'ein:notebook-pop-to-current-buffer))
|
2012-08-19 03:19:46 +02:00
|
|
|
|
(let ((buffer (ein:notebook-get-opened-buffer url-or-port notebook-id)))
|
2012-05-18 03:48:36 +02:00
|
|
|
|
(if (buffer-live-p buffer)
|
|
|
|
|
(with-current-buffer buffer
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(when callback
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(apply callback ein:%notebook% nil cbargs))
|
|
|
|
|
ein:%notebook%)
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(ein:notebook-request-open url-or-port notebook-id callback cbargs))))
|
2012-05-18 03:39:39 +02:00
|
|
|
|
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(defun ein:notebook-request-open (url-or-port notebook-id
|
|
|
|
|
&optional callback cbargs)
|
2012-05-17 20:12:40 +02:00
|
|
|
|
"Request notebook of NOTEBOOK-ID to the server at URL-OR-PORT.
|
|
|
|
|
Return `ein:$notebook' instance. Notebook may not be ready at
|
2012-06-08 11:42:42 +02:00
|
|
|
|
the time of execution.
|
|
|
|
|
|
|
|
|
|
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."
|
2012-05-13 04:07:49 +02:00
|
|
|
|
(let ((url (ein:notebook-url-from-url-and-id url-or-port notebook-id))
|
|
|
|
|
(notebook (ein:notebook-new url-or-port notebook-id)))
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(ein:log 'debug "Opening notebook at %s" url)
|
2012-06-20 21:01:58 +02:00
|
|
|
|
(ein:query-singleton-ajax
|
|
|
|
|
(list 'notebook-open url-or-port notebook-id)
|
2012-05-26 20:41:21 +02:00
|
|
|
|
url
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:timeout ein:notebook-querty-timeout-open
|
2012-05-26 20:41:21 +02:00
|
|
|
|
:parser #'ein:json-read
|
2012-06-08 11:42:42 +02:00
|
|
|
|
:success (cons #'ein:notebook-request-open-callback-with-callback
|
|
|
|
|
(list notebook callback cbargs)))
|
2012-05-17 20:12:40 +02:00
|
|
|
|
notebook))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(defun ein:notebook-request-open-callback-with-callback (packed &rest args)
|
|
|
|
|
(let ((notebook (nth 0 packed))
|
|
|
|
|
(callback (nth 1 packed))
|
|
|
|
|
(cbargs (nth 2 packed)))
|
|
|
|
|
(apply #'ein:notebook-request-open-callback notebook args)
|
|
|
|
|
(when callback
|
2012-08-19 11:58:04 +02:00
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
2012-07-12 02:44:34 +02:00
|
|
|
|
(apply callback notebook t cbargs)))))
|
2012-06-08 11:42:42 +02:00
|
|
|
|
|
2012-05-26 20:41:21 +02:00
|
|
|
|
(defun* ein:notebook-request-open-callback (notebook &key status data
|
|
|
|
|
&allow-other-keys)
|
2012-05-08 07:05:11 +02:00
|
|
|
|
(ein:log 'debug "URL-RETRIEVE nodtebook-id = %S, status = %S"
|
2012-05-13 04:07:49 +02:00
|
|
|
|
(ein:$notebook-notebook-id notebook)
|
|
|
|
|
status)
|
2012-05-26 20:41:21 +02:00
|
|
|
|
(let ((notebook-id (ein:$notebook-notebook-id notebook)))
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(ein:notebook-bind-events notebook (ein:events-new))
|
|
|
|
|
(ein:notebook-start-kernel notebook)
|
2012-08-19 11:58:04 +02:00
|
|
|
|
(ein:notebook-from-json notebook data)
|
|
|
|
|
(ein:notebook-put-opened-notebook notebook)
|
|
|
|
|
(ein:notebook--check-nbformat data)
|
|
|
|
|
(ein:log 'info "Notebook %s is ready"
|
|
|
|
|
(ein:$notebook-notebook-name notebook))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-pp (ewoc-data)
|
|
|
|
|
(let ((path (ein:$node-path ewoc-data))
|
|
|
|
|
(data (ein:$node-data ewoc-data)))
|
|
|
|
|
(case (car path)
|
|
|
|
|
(cell (ein:cell-pp (cdr path) data)))))
|
|
|
|
|
|
2012-08-12 19:33:39 +02:00
|
|
|
|
(defun ein:notebook--different-number (n1 n2)
|
|
|
|
|
(and (numberp n1) (numberp n2) (not (= n1 n2))))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook--check-nbformat (data)
|
|
|
|
|
"Warn user when nbformat is changed on server side.
|
|
|
|
|
See https://github.com/ipython/ipython/pull/1934 for the purpose
|
|
|
|
|
of minor mode."
|
|
|
|
|
;; See `Notebook.prototype.load_notebook_success'
|
|
|
|
|
;; at IPython/frontend/html/notebook/static/js/notebook.js
|
|
|
|
|
(destructuring-bind (&key nbformat orig_nbformat
|
|
|
|
|
nbformat_minor orig_nbformat_minor
|
|
|
|
|
&allow-other-keys)
|
|
|
|
|
data
|
|
|
|
|
(cond
|
|
|
|
|
((ein:notebook--different-number nbformat orig_nbformat)
|
|
|
|
|
(ein:display-warning
|
|
|
|
|
(format "Notebook major version updated (v%d -> v%d).
|
|
|
|
|
To not update version, do not save this notebook."
|
|
|
|
|
orig_nbformat nbformat)))
|
|
|
|
|
((ein:notebook--different-number nbformat_minor orig_nbformat_minor)
|
|
|
|
|
(ein:display-warning
|
|
|
|
|
(format "This notebook is version v%s.%s, but IPython
|
|
|
|
|
server you are using only fully support up to v%s.%s.
|
|
|
|
|
Some features may not be available."
|
|
|
|
|
orig_nbformat orig_nbformat_minor
|
|
|
|
|
nbformat nbformat_minor))))))
|
|
|
|
|
|
2012-05-22 20:50:47 +02:00
|
|
|
|
|
|
|
|
|
;;; Initialization.
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-bind-events (notebook events)
|
|
|
|
|
"Bind events related to PAGER to the event handler EVENTS."
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(setf (ein:$notebook-events notebook) events)
|
2012-08-20 02:05:56 +02:00
|
|
|
|
;; As IPython support only supports whole-notebook saving, there is
|
|
|
|
|
;; no need for finer-level `set_dirty.Notebook'. Keep this until
|
|
|
|
|
;; IPython supports finer-level saving.
|
2012-06-04 16:33:19 +02:00
|
|
|
|
(ein:events-on events
|
2012-06-06 21:03:54 +02:00
|
|
|
|
'set_dirty.Notebook
|
2012-06-04 16:33:19 +02:00
|
|
|
|
(lambda (notebook data)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook)
|
|
|
|
|
(plist-get data :value)))
|
|
|
|
|
notebook)
|
2012-08-20 02:22:27 +02:00
|
|
|
|
;; As calling multiple callbacks for this event does not make sense,
|
|
|
|
|
;; I amadding this in notebook instead of worksheet.
|
2012-06-16 23:33:58 +02:00
|
|
|
|
(ein:events-on events
|
|
|
|
|
'maybe_reset_undo.Notebook
|
2012-08-20 02:22:27 +02:00
|
|
|
|
(lambda (-ignore- cell)
|
|
|
|
|
(ein:with-live-buffer (ein:cell-buffer cell)
|
|
|
|
|
(ein:notebook-empty-undo-maybe))))
|
2012-05-22 20:50:47 +02:00
|
|
|
|
;; Bind events for sub components:
|
|
|
|
|
(setf (ein:$notebook-pager notebook)
|
|
|
|
|
(ein:pager-new
|
|
|
|
|
(format ein:notebook-pager-buffer-name-template
|
|
|
|
|
(ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-name notebook))
|
|
|
|
|
(ein:$notebook-events notebook))))
|
|
|
|
|
|
2012-08-15 21:41:05 +02:00
|
|
|
|
(define-obsolete-function-alias
|
|
|
|
|
'ein:notebook-show-in-shared-output
|
|
|
|
|
'ein:shared-output-show-code-cell-at-point "0.1.2")
|
2012-06-07 16:08:00 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;;; Kernel related things
|
|
|
|
|
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(defun ein:notebook-start-kernel (notebook)
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(let* ((base-url (concat ein:base-kernel-url "kernels"))
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(kernel (ein:kernel-new (ein:$notebook-url-or-port notebook)
|
2012-05-22 22:34:00 +02:00
|
|
|
|
base-url
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(ein:$notebook-events notebook))))
|
|
|
|
|
(setf (ein:$notebook-kernel notebook) kernel)
|
2012-05-31 18:12:44 +02:00
|
|
|
|
(ein:kernelinfo-init (ein:$kernel-kernelinfo kernel) (current-buffer))
|
2012-06-03 00:22:16 +02:00
|
|
|
|
(ein:kernelinfo-setup-hooks kernel)
|
2012-06-03 17:30:16 +02:00
|
|
|
|
(ein:pytools-setup-hooks kernel)
|
2012-05-13 02:51:47 +02:00
|
|
|
|
(ein:kernel-start kernel
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(ein:$notebook-notebook-id notebook))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-17 05:35:38 +02:00
|
|
|
|
(defun ein:notebook-restart-kernel (notebook)
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(ein:kernel-restart (ein:$notebook-kernel notebook)))
|
2012-05-17 05:35:38 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-restart-kernel-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Send request to the server to restart kernel."
|
2012-05-17 05:35:38 +02:00
|
|
|
|
(interactive)
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(if ein:%notebook%
|
2012-05-17 05:35:38 +02:00
|
|
|
|
(when (y-or-n-p "Really restart kernel? ")
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:notebook-restart-kernel ein:%notebook%))
|
2012-05-17 05:35:38 +02:00
|
|
|
|
(ein:log 'error "Not in notebook buffer!")))
|
|
|
|
|
|
2012-08-19 21:36:35 +02:00
|
|
|
|
(define-obsolete-function-alias
|
|
|
|
|
'ein:notebook-request-tool-tip-or-help-command
|
|
|
|
|
'ein:pytools-request-tooltip-or-help "0.1.2")
|
2012-05-18 04:31:57 +02:00
|
|
|
|
|
2012-07-29 18:08:30 +02:00
|
|
|
|
(defun ein:notebook-complete-dot ()
|
|
|
|
|
"Insert dot and request completion."
|
|
|
|
|
(interactive)
|
2012-08-20 02:58:08 +02:00
|
|
|
|
(if (and ein:%notebook% (ein:codecell-p (ein:get-cell-at-point)))
|
|
|
|
|
(ein:completer-dot-complete)
|
|
|
|
|
(insert ".")))
|
2012-07-29 18:08:30 +02:00
|
|
|
|
|
2012-05-13 07:32:43 +02:00
|
|
|
|
(defun ein:notebook-kernel-interrupt-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Interrupt the kernel.
|
|
|
|
|
This is equivalent to do ``C-c`` in the console program."
|
2012-05-13 07:32:43 +02:00
|
|
|
|
(interactive)
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:kernel-interrupt (ein:$notebook-kernel ein:%notebook%)))
|
2012-05-13 07:32:43 +02:00
|
|
|
|
|
2012-05-13 07:37:19 +02:00
|
|
|
|
(defun ein:notebook-kernel-kill-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(when (y-or-n-p "Really kill kernel?")
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:kernel-kill (ein:$notebook-kernel ein:%notebook%))))
|
2012-05-13 07:37:19 +02:00
|
|
|
|
|
2012-07-29 14:43:10 +02:00
|
|
|
|
;; autoexec
|
|
|
|
|
|
2012-07-29 14:58:56 +02:00
|
|
|
|
(defun ein:notebook-execute-autoexec-cells (notebook)
|
2012-07-29 16:52:54 +02:00
|
|
|
|
"Execute cells of which auto-execution flag is on."
|
2012-08-20 04:23:53 +02:00
|
|
|
|
(interactive (list (or ein:%notebook% (error "Not in notebook buffer!"))))
|
2012-08-20 02:44:46 +02:00
|
|
|
|
(mapc #'ein:worksheet-execute-autoexec-cells
|
|
|
|
|
(ein:$notebook-worksheets notebook)))
|
2012-07-29 14:58:56 +02:00
|
|
|
|
|
2012-08-15 23:08:35 +02:00
|
|
|
|
(define-obsolete-function-alias
|
|
|
|
|
'ein:notebook-eval-string
|
|
|
|
|
'ein:shared-output-eval-string "0.1.2")
|
2012-06-02 20:40:22 +02:00
|
|
|
|
|
2012-05-27 05:19:17 +02:00
|
|
|
|
;; Followings are kernel related, but EIN specific
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-sync-directory (notebook)
|
|
|
|
|
(ein:kernel-sync-directory (ein:$notebook-kernel notebook)
|
|
|
|
|
(ein:notebook-buffer notebook)))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-sync-directory-command ()
|
|
|
|
|
(interactive)
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(when ein:%notebook% (ein:notebook-sync-directory ein:%notebook%)))
|
2012-05-27 05:19:17 +02:00
|
|
|
|
|
2012-05-08 06:15:23 +02:00
|
|
|
|
|
|
|
|
|
;;; Persistance and loading
|
|
|
|
|
|
2012-05-13 05:06:49 +02:00
|
|
|
|
(defun ein:notebook-set-notebook-name (notebook name)
|
|
|
|
|
"Check NAME and change the name of NOTEBOOK to it."
|
|
|
|
|
(if (ein:notebook-test-notebook-name name)
|
|
|
|
|
(setf (ein:$notebook-notebook-name notebook) name)
|
|
|
|
|
(ein:log 'error "%S is not a good notebook name." name)
|
|
|
|
|
(error "%S is not a good notebook name." name)))
|
|
|
|
|
|
2012-05-13 04:47:41 +02:00
|
|
|
|
(defun ein:notebook-test-notebook-name (name)
|
|
|
|
|
(and (stringp name)
|
|
|
|
|
(> (length name) 0)
|
|
|
|
|
(not (string-match "[\\/\\\\]" name))))
|
|
|
|
|
|
2012-05-08 06:41:17 +02:00
|
|
|
|
(defun ein:notebook-from-json (notebook data)
|
2012-08-19 11:58:04 +02:00
|
|
|
|
(destructuring-bind (&key metadata nbformat nbformat_minor
|
|
|
|
|
&allow-other-keys)
|
|
|
|
|
data
|
|
|
|
|
(setf (ein:$notebook-metadata notebook) metadata)
|
|
|
|
|
(setf (ein:$notebook-nbformat notebook) nbformat)
|
|
|
|
|
(setf (ein:$notebook-nbformat-minor notebook) nbformat_minor)
|
|
|
|
|
(setf (ein:$notebook-notebook-name notebook) (plist-get metadata :name)))
|
|
|
|
|
(setf (ein:$notebook-worksheets notebook)
|
|
|
|
|
(mapcar (lambda (ws-data)
|
2012-08-19 17:13:09 +02:00
|
|
|
|
(ein:worksheet-from-json (ein:worksheet-new
|
|
|
|
|
notebook
|
|
|
|
|
(ein:$notebook-kernel notebook)
|
|
|
|
|
(ein:$notebook-events notebook))
|
2012-08-19 11:58:04 +02:00
|
|
|
|
ws-data))
|
|
|
|
|
(or (plist-get data :worksheets)
|
2012-08-20 13:33:27 +02:00
|
|
|
|
(list nil))))
|
2012-08-20 09:50:07 +02:00
|
|
|
|
(ein:worksheet-render (nth 0 (ein:$notebook-worksheets notebook)))
|
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
|
|
|
|
(setq ein:%notebook% notebook)))
|
2012-05-08 06:41:17 +02:00
|
|
|
|
|
2012-05-08 06:15:23 +02:00
|
|
|
|
(defun ein:notebook-to-json (notebook)
|
2012-05-08 08:26:56 +02:00
|
|
|
|
"Return json-ready alist."
|
2012-08-19 17:40:41 +02:00
|
|
|
|
(let ((worksheets (mapcar #'ein:worksheet-to-json
|
|
|
|
|
(ein:$notebook-worksheets notebook))))
|
|
|
|
|
`((worksheets . ,(apply #'vector worksheets))
|
2012-05-25 22:58:01 +02:00
|
|
|
|
(metadata . ,(ein:$notebook-metadata notebook)))))
|
2012-05-08 06:15:23 +02:00
|
|
|
|
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(defun ein:notebook-save-notebook (notebook retry &optional callback cbarg)
|
2012-05-08 08:24:20 +02:00
|
|
|
|
(let ((data (ein:notebook-to-json notebook)))
|
2012-05-08 08:50:09 +02:00
|
|
|
|
(plist-put (cdr (assq 'metadata data))
|
|
|
|
|
:name (ein:$notebook-notebook-name notebook))
|
2012-05-08 08:26:56 +02:00
|
|
|
|
(push `(nbformat . ,(ein:$notebook-nbformat notebook)) data)
|
2012-08-12 19:43:39 +02:00
|
|
|
|
(ein:aif (ein:$notebook-nbformat-minor notebook)
|
|
|
|
|
;; Do not set nbformat when it is not given from server.
|
|
|
|
|
(push `(nbformat_minor . ,it) data))
|
2012-05-22 13:56:24 +02:00
|
|
|
|
(ein:events-trigger (ein:$notebook-events notebook)
|
2012-06-06 21:03:54 +02:00
|
|
|
|
'notebook_saving.Notebook)
|
2012-06-20 21:01:58 +02:00
|
|
|
|
(ein:query-singleton-ajax
|
|
|
|
|
(list 'notebook-save
|
|
|
|
|
(ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-id notebook))
|
2012-05-25 22:12:34 +02:00
|
|
|
|
(ein:notebook-url notebook)
|
2012-06-21 00:01:23 +02:00
|
|
|
|
:timeout ein:notebook-querty-timeout-save
|
2012-05-25 22:12:34 +02:00
|
|
|
|
:type "PUT"
|
|
|
|
|
:headers '(("Content-Type" . "application/json"))
|
|
|
|
|
:cache nil
|
|
|
|
|
:data (json-encode data)
|
|
|
|
|
:error (cons #'ein:notebook-save-notebook-error notebook)
|
|
|
|
|
:success (cons #'ein:notebook-save-notebook-workaround
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(list notebook retry callback cbarg))
|
2012-05-25 22:12:34 +02:00
|
|
|
|
:status-code
|
2012-06-26 17:03:36 +02:00
|
|
|
|
`((204 . ,(cons (lambda (arg &rest rest)
|
|
|
|
|
(destructuring-bind (notebook callback cbarg)
|
|
|
|
|
arg
|
|
|
|
|
(apply #'ein:notebook-save-notebook-success
|
|
|
|
|
notebook rest)
|
|
|
|
|
(when callback
|
|
|
|
|
(apply callback cbarg rest))))
|
|
|
|
|
(list notebook callback cbarg)))))))
|
2012-05-08 08:24:20 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-save-notebook-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Save the notebook."
|
2012-05-08 08:24:20 +02:00
|
|
|
|
(interactive)
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:notebook-save-notebook ein:%notebook% 0))
|
2012-05-08 08:24:20 +02:00
|
|
|
|
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(defun* ein:notebook-save-notebook-workaround (packed &rest args
|
|
|
|
|
&key
|
|
|
|
|
status
|
|
|
|
|
response-status
|
|
|
|
|
&allow-other-keys)
|
2012-05-25 22:12:34 +02:00
|
|
|
|
;; IPython server returns 204 only when the notebook URL is
|
|
|
|
|
;; accessed via PUT or DELETE. As it seems Emacs failed to
|
|
|
|
|
;; choose PUT method every two times, let's check the response
|
|
|
|
|
;; here and fail when 204 is not returned.
|
2012-05-26 20:00:17 +02:00
|
|
|
|
(unless (eq response-status 204)
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(destructuring-bind (notebook retry callback cbarg)
|
|
|
|
|
packed
|
2012-05-25 22:58:01 +02:00
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
|
|
|
|
(if (< retry ein:notebook-save-retry-max)
|
|
|
|
|
(progn
|
|
|
|
|
(ein:log 'info "Retry saving... Next count: %s" (1+ retry))
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(ein:notebook-save-notebook notebook (1+ retry)
|
|
|
|
|
callback cbarg))
|
2012-05-25 22:58:01 +02:00
|
|
|
|
(ein:notebook-save-notebook-error notebook :status status)
|
|
|
|
|
(ein:log 'info
|
|
|
|
|
"Status code (=%s) is not 204 and retry exceeds limit (=%s)."
|
2012-05-26 20:00:17 +02:00
|
|
|
|
response-status ein:notebook-save-retry-max))))))
|
2012-05-25 22:12:34 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-save-notebook-success (notebook &rest ignore)
|
2012-05-23 19:08:07 +02:00
|
|
|
|
(ein:log 'info "Notebook is saved.")
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) nil)
|
2012-08-20 11:39:07 +02:00
|
|
|
|
(mapc (lambda (ws) (ein:worksheet-set-modified-p ws nil))
|
|
|
|
|
(ein:$notebook-worksheets notebook))
|
2012-05-22 13:56:24 +02:00
|
|
|
|
(ein:events-trigger (ein:$notebook-events notebook)
|
2012-06-06 21:03:54 +02:00
|
|
|
|
'notebook_saved.Notebook))
|
2012-05-08 08:24:20 +02:00
|
|
|
|
|
2012-06-20 21:13:28 +02:00
|
|
|
|
(defun* ein:notebook-save-notebook-error (notebook &key symbol-status
|
|
|
|
|
&allow-other-keys)
|
|
|
|
|
(if (eq symbol-status 'user-cancel)
|
|
|
|
|
(ein:log 'info "Cancel saving notebook.")
|
|
|
|
|
(ein:log 'info "Failed to save notebook!")
|
|
|
|
|
(ein:events-trigger (ein:$notebook-events notebook)
|
|
|
|
|
'notebook_save_failed.Notebook)))
|
2012-05-08 08:24:20 +02:00
|
|
|
|
|
2012-05-13 05:06:49 +02:00
|
|
|
|
(defun ein:notebook-rename-command (name)
|
|
|
|
|
"Rename current notebook and save it immediately.
|
|
|
|
|
|
|
|
|
|
NAME is any non-empty string that does not contain '/' or '\\'."
|
|
|
|
|
(interactive
|
2012-05-15 04:15:44 +02:00
|
|
|
|
(list (read-string "Rename notebook: "
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(let ((name (ein:$notebook-notebook-name ein:%notebook%)))
|
2012-05-23 21:50:25 +02:00
|
|
|
|
(unless (string-match "Untitled[0-9]+" name)
|
|
|
|
|
name)))))
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:notebook-set-notebook-name ein:%notebook% name)
|
2012-08-20 03:27:36 +02:00
|
|
|
|
(mapc #'ein:worksheet-set-buffer-name
|
|
|
|
|
(ein:$notebook-worksheets ein:%notebook%))
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(ein:notebook-save-notebook
|
2012-08-18 22:33:42 +02:00
|
|
|
|
ein:%notebook% 0
|
2012-06-26 17:03:36 +02:00
|
|
|
|
(lambda (notebook &rest ignore)
|
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
|
|
|
|
(run-hooks 'ein:notebook-after-rename-hook)))
|
2012-08-18 22:33:42 +02:00
|
|
|
|
ein:%notebook%))
|
2012-05-13 05:06:49 +02:00
|
|
|
|
|
2012-07-14 16:36:51 +02:00
|
|
|
|
(defun ein:notebook-rename-to-scratch-command (name)
|
|
|
|
|
"Rename notebook based on `ein:scratch-notebook-name-template'
|
|
|
|
|
and save it immediately."
|
|
|
|
|
(interactive
|
|
|
|
|
(list (read-string "Rename notebook: "
|
|
|
|
|
(ein:scratch-notebook-name))))
|
|
|
|
|
(ein:notebook-rename-command name))
|
|
|
|
|
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(defun ein:notebook-close (notebook)
|
|
|
|
|
"Close NOTEBOOK and kill its buffer."
|
|
|
|
|
(let ((ein:notebook-kill-buffer-ask nil))
|
|
|
|
|
;; Let `ein:notebook-kill-buffer-callback' do its job.
|
|
|
|
|
(kill-buffer (ein:notebook-buffer notebook))))
|
|
|
|
|
|
2012-06-14 12:24:40 +02:00
|
|
|
|
(defun ein:notebook-kill-kernel-then-close-command ()
|
|
|
|
|
"Kill kernel and then kill notebook buffer.
|
2012-07-19 00:35:21 +02:00
|
|
|
|
To close notebook without killing kernel, just close the buffer
|
|
|
|
|
as usual."
|
2012-06-14 12:24:40 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(when (ein:notebook-ask-before-kill-buffer)
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(let ((kernel (ein:$notebook-kernel ein:%notebook%)))
|
2012-07-19 00:35:21 +02:00
|
|
|
|
;; If kernel is live, kill it before closing.
|
|
|
|
|
(if (ein:kernel-live-p kernel)
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(ein:kernel-kill kernel #'ein:notebook-close (list ein:%notebook%))
|
|
|
|
|
(ein:notebook-close ein:%notebook%)))))
|
2012-06-14 12:24:40 +02:00
|
|
|
|
|
2012-08-19 03:19:46 +02:00
|
|
|
|
|
|
|
|
|
;;; Opened notebooks
|
|
|
|
|
|
|
|
|
|
(defvar ein:notebook--opened-map (make-hash-table :test 'equal)
|
|
|
|
|
"A map: (URL-OR-PORT NOTEBOOK-ID) => notebook instance.")
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-get-opened-notebook (url-or-port notebook-id)
|
|
|
|
|
(gethash (list url-or-port notebook-id) ein:notebook--opened-map))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-get-opened-buffer (url-or-port notebook-id)
|
2012-08-19 03:43:54 +02:00
|
|
|
|
(ein:aand (ein:notebook-get-opened-notebook url-or-port notebook-id)
|
|
|
|
|
(ein:notebook-buffer it)))
|
2012-08-19 03:19:46 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-put-opened-notebook (notebook)
|
|
|
|
|
(puthash (list (ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-id notebook))
|
|
|
|
|
notebook
|
|
|
|
|
ein:notebook--opened-map))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-opened-notebooks ()
|
|
|
|
|
"Return list of opened notebook instances."
|
|
|
|
|
(let (notebooks)
|
|
|
|
|
(maphash (lambda (k n) (if (ein:notebook-live-p n)
|
|
|
|
|
(push n notebooks)
|
|
|
|
|
(remhash k ein:notebook--opened-map)))
|
|
|
|
|
ein:notebook--opened-map)
|
|
|
|
|
notebooks))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-opened-buffers ()
|
|
|
|
|
"Return list of opened notebook buffers."
|
|
|
|
|
(mapcar #'ein:notebook-buffer (ein:notebook-opened-notebooks)))
|
|
|
|
|
|
2012-08-19 04:18:02 +02:00
|
|
|
|
(defun ein:notebook-opened-buffer-names ()
|
|
|
|
|
"Return list of opened notebook buffer names."
|
|
|
|
|
(mapcar #'buffer-name (ein:notebook-opened-buffers)))
|
|
|
|
|
|
2012-08-13 18:55:32 +02:00
|
|
|
|
|
|
|
|
|
;;; Generic getter
|
|
|
|
|
|
|
|
|
|
(defun ein:get-url-or-port--notebook ()
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(when ein:%notebook% (ein:$notebook-url-or-port ein:%notebook%)))
|
2012-08-13 18:55:32 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:get-notebook--notebook ()
|
2012-08-18 22:33:42 +02:00
|
|
|
|
ein:%notebook%)
|
2012-08-13 18:55:32 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:get-kernel--notebook ()
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(when (ein:$notebook-p ein:%notebook%)
|
|
|
|
|
(ein:$notebook-kernel ein:%notebook%)))
|
2012-08-13 18:55:32 +02:00
|
|
|
|
|
2012-08-19 02:32:11 +02:00
|
|
|
|
|
2012-08-20 02:05:56 +02:00
|
|
|
|
;;; Predicate
|
2012-08-19 02:32:11 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-buffer-p ()
|
|
|
|
|
"Return non-`nil' if current buffer is notebook buffer."
|
|
|
|
|
ein:%notebook%)
|
|
|
|
|
|
2012-08-19 03:19:46 +02:00
|
|
|
|
(defun ein:notebook-live-p (notebook)
|
|
|
|
|
"Return non-`nil' if NOTEBOOK has live buffer."
|
|
|
|
|
(buffer-live-p (ein:notebook-buffer notebook)))
|
|
|
|
|
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(defun ein:notebook-modified-p (&optional notebook)
|
|
|
|
|
(unless notebook (setq notebook ein:%notebook%))
|
|
|
|
|
(and (ein:$notebook-p notebook)
|
|
|
|
|
(ein:notebook-live-p notebook)
|
|
|
|
|
(or (ein:$notebook-dirty notebook)
|
2012-08-20 02:05:56 +02:00
|
|
|
|
(loop for ws in (ein:$notebook-worksheets notebook)
|
|
|
|
|
when (ein:worksheet-modified-p ws)
|
|
|
|
|
return t))))
|
2012-08-19 04:17:34 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;;; Notebook mode
|
|
|
|
|
|
2012-05-21 17:55:23 +02:00
|
|
|
|
(defcustom ein:notebook-modes
|
2012-05-21 18:05:57 +02:00
|
|
|
|
'(ein:notebook-mumamo-mode ein:notebook-python-mode ein:notebook-plain-mode)
|
|
|
|
|
"Notebook modes to use \(in order of preference).
|
|
|
|
|
|
2012-05-21 19:47:38 +02:00
|
|
|
|
When the notebook is opened, mode in this value is checked one by one
|
|
|
|
|
and the first usable mode is used. By default, MuMaMo is used when
|
|
|
|
|
it is installed. If not, a simple mode derived from `python-mode' is
|
|
|
|
|
used.
|
|
|
|
|
|
|
|
|
|
Examples:
|
2012-06-11 04:21:30 +02:00
|
|
|
|
|
2012-06-11 04:46:11 +02:00
|
|
|
|
Avoid using MuMaMo even when it is installed::
|
|
|
|
|
|
2012-05-21 18:05:57 +02:00
|
|
|
|
(setq ein:notebook-modes (delq 'ein:notebook-mumamo-mode ein:notebook-modes))
|
2012-06-11 04:46:11 +02:00
|
|
|
|
|
|
|
|
|
Do not use `python-mode'. Use plain mode when MuMaMo is not installed::
|
|
|
|
|
|
2012-05-21 19:47:38 +02:00
|
|
|
|
(setq ein:notebook-modes '(ein:notebook-mumamo-mode ein:notebook-plain-mode))
|
2012-05-21 18:05:57 +02:00
|
|
|
|
"
|
2012-05-21 17:55:23 +02:00
|
|
|
|
:type '(repeat (choice (const :tag "MuMaMo" ein:notebook-mumamo-mode)
|
2012-05-21 18:05:57 +02:00
|
|
|
|
(const :tag "Only Python" ein:notebook-python-mode)
|
2012-05-21 17:55:23 +02:00
|
|
|
|
(const :tag "Plain" ein:notebook-plain-mode)))
|
|
|
|
|
:group 'ein)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-choose-mode ()
|
2012-05-14 18:47:08 +02:00
|
|
|
|
"Return usable (defined) notebook mode."
|
|
|
|
|
;; So try to load extra modules here.
|
|
|
|
|
(when (require 'mumamo nil t)
|
|
|
|
|
(require 'ein-mumamo))
|
|
|
|
|
;; Return first matched mode
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(loop for mode in ein:notebook-modes
|
|
|
|
|
if (functionp mode)
|
|
|
|
|
return mode))
|
|
|
|
|
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(defvar ein:notebook-mode-map (make-sparse-keymap))
|
|
|
|
|
|
|
|
|
|
(let ((map ein:notebook-mode-map))
|
2012-08-20 03:42:39 +02:00
|
|
|
|
(define-key map "\C-c\C-c" 'ein:worksheet-execute-cell)
|
|
|
|
|
(define-key map (kbd "M-RET") 'ein:worksheet-execute-cell-and-goto-next)
|
|
|
|
|
(define-key map (kbd "C-c C-'") 'ein:worksheet-turn-on-autoexec)
|
|
|
|
|
(define-key map "\C-c\C-e" 'ein:worksheet-toggle-output)
|
|
|
|
|
(define-key map "\C-c\C-v" 'ein:worksheet-set-collapsed-all)
|
|
|
|
|
(define-key map "\C-c\C-l" 'ein:worksheet-clear-output)
|
|
|
|
|
(define-key map (kbd "C-c C-S-l") 'ein:worksheet-clear-all-output)
|
2012-08-15 21:41:05 +02:00
|
|
|
|
(define-key map (kbd "C-c C-;") 'ein:shared-output-show-code-cell-at-point)
|
2012-08-20 03:42:39 +02:00
|
|
|
|
(define-key map "\C-c\C-k" 'ein:worksheet-kill-cell)
|
|
|
|
|
(define-key map "\C-c\M-w" 'ein:worksheet-copy-cell)
|
|
|
|
|
(define-key map "\C-c\C-w" 'ein:worksheet-copy-cell)
|
|
|
|
|
(define-key map "\C-c\C-y" 'ein:worksheet-yank-cell)
|
|
|
|
|
(define-key map "\C-c\C-a" 'ein:worksheet-insert-cell-above)
|
|
|
|
|
(define-key map "\C-c\C-b" 'ein:worksheet-insert-cell-below)
|
|
|
|
|
(define-key map "\C-c\C-t" 'ein:worksheet-toggle-cell-type)
|
|
|
|
|
(define-key map "\C-c\C-u" 'ein:worksheet-change-cell-type)
|
|
|
|
|
(define-key map "\C-c\C-s" 'ein:worksheet-split-cell-at-point)
|
|
|
|
|
(define-key map "\C-c\C-m" 'ein:worksheet-merge-cell)
|
|
|
|
|
(define-key map "\C-c\C-n" 'ein:worksheet-goto-next-input)
|
|
|
|
|
(define-key map "\C-c\C-p" 'ein:worksheet-goto-prev-input)
|
|
|
|
|
(define-key map (kbd "C-<up>") 'ein:worksheet-goto-prev-input)
|
|
|
|
|
(define-key map (kbd "C-<down>") 'ein:worksheet-goto-next-input)
|
|
|
|
|
(define-key map (kbd "C-c <up>") 'ein:worksheet-move-cell-up)
|
|
|
|
|
(define-key map (kbd "C-c <down>") 'ein:worksheet-move-cell-down)
|
|
|
|
|
(define-key map (kbd "M-<up>") 'ein:worksheet-move-cell-up)
|
|
|
|
|
(define-key map (kbd "M-<down>") 'ein:worksheet-move-cell-down)
|
2012-08-19 21:36:35 +02:00
|
|
|
|
(define-key map "\C-c\C-f" 'ein:pytools-request-tooltip-or-help)
|
2012-08-19 22:23:51 +02:00
|
|
|
|
(define-key map "\C-c\C-i" 'ein:completer-complete)
|
2012-08-14 20:46:29 +02:00
|
|
|
|
(define-key map "\C-c\C-x" 'ein:tb-show)
|
2012-08-20 13:53:14 +02:00
|
|
|
|
(define-key map "\C-c\C-r" 'ein:notebook-restart-kernel-command)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(define-key map "\C-c\C-z" 'ein:notebook-kernel-interrupt-command)
|
|
|
|
|
(define-key map "\C-c\C-q" 'ein:notebook-kill-kernel-then-close-command)
|
2012-08-15 23:08:35 +02:00
|
|
|
|
(define-key map (kbd "C-:") 'ein:shared-output-eval-string)
|
2012-08-16 15:48:11 +02:00
|
|
|
|
(define-key map "\C-c\C-o" 'ein:console-open)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(define-key map "\C-x\C-s" 'ein:notebook-save-notebook-command)
|
|
|
|
|
(define-key map "\C-x\C-w" 'ein:notebook-rename-command)
|
2012-06-17 02:36:00 +02:00
|
|
|
|
(define-key map "\M-." 'ein:pytools-jump-to-source-command)
|
|
|
|
|
(define-key map (kbd "C-c C-.") 'ein:pytools-jump-to-source-command)
|
|
|
|
|
(define-key map "\M-," 'ein:pytools-jump-back-command)
|
|
|
|
|
(define-key map (kbd "C-c C-,") 'ein:pytools-jump-back-command)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
map)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-29 18:08:30 +02:00
|
|
|
|
(defun ein:notebook-mode ()
|
|
|
|
|
(funcall (ein:notebook-choose-mode))
|
|
|
|
|
(ein:complete-on-dot-install
|
|
|
|
|
ein:notebook-mode-map 'ein:notebook-complete-dot))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(define-derived-mode ein:notebook-plain-mode fundamental-mode "ein:notebook"
|
2012-05-21 18:01:03 +02:00
|
|
|
|
"IPython notebook mode without fancy coloring."
|
2012-05-13 08:36:21 +02:00
|
|
|
|
(font-lock-mode))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-21 18:05:57 +02:00
|
|
|
|
(define-derived-mode ein:notebook-python-mode python-mode "ein:python"
|
|
|
|
|
"Use `python-mode' for whole notebook buffer.")
|
|
|
|
|
|
2012-08-20 09:52:10 +02:00
|
|
|
|
(add-hook 'ein:notebook-plain-mode-hook 'ein:worksheet-imenu-setup)
|
|
|
|
|
(add-hook 'ein:notebook-python-mode-hook 'ein:worksheet-imenu-setup)
|
2012-07-20 17:16:03 +02:00
|
|
|
|
|
2012-07-29 18:09:16 +02:00
|
|
|
|
(set-keymap-parent ein:notebook-plain-mode-map ein:notebook-mode-map)
|
|
|
|
|
(set-keymap-parent ein:notebook-python-mode-map ein:notebook-mode-map)
|
2012-05-21 18:05:57 +02:00
|
|
|
|
|
2012-06-17 14:49:54 +02:00
|
|
|
|
(defun ein:notebook-open-in-browser (&optional print)
|
|
|
|
|
"Open current notebook in web browser.
|
|
|
|
|
When the prefix argument (``C-u``) is given, print page is opened.
|
|
|
|
|
Note that print page is not supported in IPython 0.12.1."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(let ((url (apply #'ein:url
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(ein:$notebook-url-or-port ein:%notebook%)
|
|
|
|
|
(ein:$notebook-notebook-id ein:%notebook%)
|
2012-06-17 14:49:54 +02:00
|
|
|
|
(if print (list "print")))))
|
2012-05-19 17:16:30 +02:00
|
|
|
|
(message "Opening %s in browser" url)
|
|
|
|
|
(browse-url url)))
|
|
|
|
|
|
2012-08-19 04:41:26 +02:00
|
|
|
|
|
|
|
|
|
;;; Buffer and kill hooks
|
|
|
|
|
|
2012-06-06 22:36:47 +02:00
|
|
|
|
(defcustom ein:notebook-kill-buffer-ask t
|
|
|
|
|
"Whether EIN should ask before killing unsaved notebook buffer."
|
|
|
|
|
:type '(choice (const :tag "Yes" t)
|
|
|
|
|
(const :tag "No" nil))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-08-19 04:41:26 +02:00
|
|
|
|
;; -- `kill-buffer-query-functions'
|
2012-05-19 18:16:35 +02:00
|
|
|
|
(defun ein:notebook-ask-before-kill-buffer ()
|
2012-05-13 18:29:50 +02:00
|
|
|
|
"Return `nil' to prevent killing the notebook buffer.
|
|
|
|
|
Called via `kill-buffer-query-functions'."
|
2012-06-06 22:36:47 +02:00
|
|
|
|
(not (and ein:notebook-kill-buffer-ask
|
|
|
|
|
(ein:notebook-modified-p)
|
2012-05-13 18:29:50 +02:00
|
|
|
|
(not (y-or-n-p "You have unsaved changes. Discard changes?")))))
|
|
|
|
|
|
2012-05-19 18:16:35 +02:00
|
|
|
|
(add-hook 'kill-buffer-query-functions 'ein:notebook-ask-before-kill-buffer)
|
|
|
|
|
|
2012-08-19 04:41:26 +02:00
|
|
|
|
;; -- `kill-emacs-query-functions'
|
2012-05-19 18:16:35 +02:00
|
|
|
|
(defun ein:notebook-ask-before-kill-emacs ()
|
|
|
|
|
"Return `nil' to prevent killing Emacs when unsaved notebook exists.
|
|
|
|
|
Called via `kill-emacs-query-functions'."
|
2012-05-23 10:48:43 +02:00
|
|
|
|
(let ((unsaved (ein:filter #'ein:notebook-modified-p
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(ein:notebook-opened-notebooks))))
|
2012-05-19 18:16:35 +02:00
|
|
|
|
(if (null unsaved)
|
|
|
|
|
t
|
2012-06-06 22:36:47 +02:00
|
|
|
|
(let ((answer
|
|
|
|
|
(y-or-n-p
|
|
|
|
|
(format "You have %s unsaved notebook(s). Discard changes?"
|
|
|
|
|
(length unsaved)))))
|
|
|
|
|
;; kill all unsaved buffers forcefully
|
|
|
|
|
(when answer
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(mapc #'ein:notebook-close unsaved))
|
2012-06-06 22:36:47 +02:00
|
|
|
|
answer))))
|
2012-05-19 18:16:35 +02:00
|
|
|
|
|
|
|
|
|
(add-hook 'kill-emacs-query-functions 'ein:notebook-ask-before-kill-emacs)
|
2012-05-13 18:29:50 +02:00
|
|
|
|
|
2012-08-19 04:41:26 +02:00
|
|
|
|
;; -- `kill-buffer-hook'
|
2012-05-19 17:58:02 +02:00
|
|
|
|
(defun ein:notebook-kill-buffer-callback ()
|
|
|
|
|
"Call notebook destructor. This function is called via `kill-buffer-hook'."
|
2012-08-18 22:33:42 +02:00
|
|
|
|
(when (ein:$notebook-p ein:%notebook%)
|
|
|
|
|
(ein:notebook-del ein:%notebook%)))
|
2012-05-19 17:58:02 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-setup-kill-buffer-hook ()
|
|
|
|
|
"Add \"notebook destructor\" to `kill-buffer-hook'."
|
|
|
|
|
(add-hook 'kill-buffer-hook 'ein:notebook-kill-buffer-callback))
|
|
|
|
|
|
|
|
|
|
(add-hook 'ein:notebook-plain-mode-hook 'ein:notebook-setup-kill-buffer-hook)
|
|
|
|
|
|
2012-08-19 04:41:26 +02:00
|
|
|
|
;; Useful command to close notebooks.
|
2012-05-25 15:44:00 +02:00
|
|
|
|
(defun ein:notebook-kill-all-buffers ()
|
2012-07-19 14:21:15 +02:00
|
|
|
|
"Close all opened notebooks."
|
2012-05-25 15:44:00 +02:00
|
|
|
|
(interactive)
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(let* ((notebooks (ein:notebook-opened-notebooks))
|
|
|
|
|
(unsaved (ein:filter #'ein:notebook-modified-p notebooks)))
|
|
|
|
|
(if notebooks
|
2012-05-25 15:44:00 +02:00
|
|
|
|
(if (y-or-n-p
|
2012-07-19 14:21:15 +02:00
|
|
|
|
(format (concat "You have %s opened notebook(s). "
|
|
|
|
|
(when unsaved
|
|
|
|
|
(format "%s are UNSAVED. " (length unsaved)))
|
2012-05-25 15:44:00 +02:00
|
|
|
|
"Really kill all of them?")
|
2012-08-19 04:17:34 +02:00
|
|
|
|
(length notebooks)))
|
2012-05-25 15:44:00 +02:00
|
|
|
|
(progn (ein:log 'info "Killing all notebook buffers...")
|
2012-08-19 05:02:18 +02:00
|
|
|
|
(mapc #'ein:notebook-close notebooks)
|
2012-05-25 15:44:00 +02:00
|
|
|
|
(ein:log 'info "Killing all notebook buffers... Done!"))
|
|
|
|
|
(ein:log 'info "Canceled to kill all notebooks."))
|
|
|
|
|
(ein:log 'info "No opened notebooks."))))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(provide 'ein-notebook)
|
|
|
|
|
|
|
|
|
|
;;; ein-notebook.el ends here
|