2012-05-07 14:41:15 +02:00
|
|
|
|
;;; ein-notebook.el --- Notebook module
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2012- Takafumi Arakaki
|
|
|
|
|
|
|
|
|
|
;; Author: Takafumi Arakaki
|
|
|
|
|
|
|
|
|
|
;; 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)
|
|
|
|
|
|
|
|
|
|
(require 'ein-utils)
|
|
|
|
|
(require 'ein-log)
|
|
|
|
|
(require 'ein-node)
|
|
|
|
|
(require 'ein-kernel)
|
|
|
|
|
(require 'ein-cell)
|
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-02 20:40:22 +02:00
|
|
|
|
(require 'ein-shared-output)
|
2012-06-03 17:30:16 +02:00
|
|
|
|
(require 'ein-pytools)
|
2012-06-07 15:56:38 +02:00
|
|
|
|
(require 'ein-traceback)
|
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
|
|
|
|
|
|
|
|
|
Note that using function needs EIN lisp API, which is not defined
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; 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-06-07 15:56:38 +02:00
|
|
|
|
(defvar ein:notebook-tb-buffer-name-template "*ein:tb %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-18 03:39:39 +02:00
|
|
|
|
(defvar ein:notebook-opened-map (make-hash-table :test 'equal)
|
|
|
|
|
"A map: (URL-OR-PORT NOTEBOOK-ID) => notebook buffer.")
|
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-data' - FIXME: remove this!
|
|
|
|
|
Original notebook JSON data sent from server. This slot exists
|
|
|
|
|
first for debugging reason and should be deleted later.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-ewoc' : `ewoc'
|
|
|
|
|
An instance of `ewoc'. Notebook is rendered using `ewoc'.
|
|
|
|
|
Also `ewoc' nodes are used for saving cell data.
|
|
|
|
|
|
|
|
|
|
`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.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-events' : `ein:$events'
|
2012-05-25 02:02:31 +02:00
|
|
|
|
Event handler instance.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-notification' : `ein:notification'
|
2012-06-07 15:56:38 +02:00
|
|
|
|
Notification widget.
|
|
|
|
|
|
|
|
|
|
`ein:$notebook-traceback' : `ein:traceback'
|
|
|
|
|
Traceback viewer."
|
2012-05-13 02:51:47 +02:00
|
|
|
|
url-or-port
|
2012-05-13 05:46:24 +02:00
|
|
|
|
notebook-id
|
|
|
|
|
data
|
|
|
|
|
ewoc
|
|
|
|
|
kernel
|
|
|
|
|
pager
|
|
|
|
|
dirty
|
|
|
|
|
metadata
|
|
|
|
|
notebook-name
|
|
|
|
|
nbformat
|
2012-05-22 13:56:24 +02:00
|
|
|
|
events
|
2012-05-25 02:02:31 +02:00
|
|
|
|
notification
|
2012-06-07 15:56:38 +02:00
|
|
|
|
traceback
|
2012-05-07 14:41:15 +02:00
|
|
|
|
)
|
|
|
|
|
|
2012-05-12 22:55:06 +02:00
|
|
|
|
(ein:deflocal ein:notebook nil
|
|
|
|
|
"Buffer local variable to store an instance of `ein:$notebook'.")
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-11 14:39:41 +02:00
|
|
|
|
(defmacro ein:notebook-with-cell (cell-p &rest body)
|
|
|
|
|
"Execute BODY if in cell with a dynamically bound variable `cell'.
|
|
|
|
|
When CELL-P is non-`nil', it is called with the current cell object
|
|
|
|
|
and BODY will be executed only when it returns non-`nil'. If CELL-P
|
|
|
|
|
is `nil', BODY is executed with any cell types."
|
|
|
|
|
(declare (indent 1))
|
|
|
|
|
`(let ((cell (ein:notebook-get-current-cell)))
|
|
|
|
|
(if ,(if cell-p `(and cell (funcall ,cell-p cell)) 'cell)
|
|
|
|
|
(progn ,@body)
|
|
|
|
|
(ein:log 'warn "Not in cell"))))
|
|
|
|
|
|
2012-06-13 00:18:12 +02:00
|
|
|
|
(defmacro ein:notebook-with-cells-in-region (&rest body)
|
|
|
|
|
"Similar to `ein:notebook-with-cell' but sets a list of cells to `cells'."
|
|
|
|
|
(declare (indent 0))
|
|
|
|
|
`(let* ((cells (ein:notebook-get-cells-in-region-or-at-point)))
|
|
|
|
|
(if cells
|
|
|
|
|
(progn ,@body)
|
|
|
|
|
(ein:log 'warn "Not in cell"))))
|
|
|
|
|
|
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-13 04:07:49 +02:00
|
|
|
|
(defun ein:notebook-init (notebook data)
|
2012-05-13 04:19:22 +02:00
|
|
|
|
"Initialize NOTEBOOK with DATA from the server."
|
2012-05-13 04:07:49 +02:00
|
|
|
|
(setf (ein:$notebook-data notebook) data)
|
2012-05-13 04:24:30 +02:00
|
|
|
|
(let* ((metadata (plist-get data :metadata))
|
|
|
|
|
(notebook-name (plist-get metadata :name)))
|
|
|
|
|
(setf (ein:$notebook-metadata notebook) metadata)
|
2012-05-18 21:10:17 +02:00
|
|
|
|
(setf (ein:$notebook-nbformat notebook) (plist-get data :nbformat))
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(setf (ein:$notebook-notebook-name notebook) notebook-name)))
|
2012-05-13 04:07:49 +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
|
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
|
|
|
|
(ein:log-del))
|
|
|
|
|
(ein:kernel-del (ein:$notebook-kernel notebook))))
|
2012-05-19 17:58:02 +02:00
|
|
|
|
|
2012-05-13 05:06:49 +02:00
|
|
|
|
(defun ein:notebook-get-buffer-name (notebook)
|
|
|
|
|
(format ein:notebook-buffer-name-template
|
|
|
|
|
(ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-name notebook)))
|
|
|
|
|
|
2012-05-13 04:13:29 +02:00
|
|
|
|
(defun ein:notebook-get-buffer (notebook)
|
2012-05-13 05:06:49 +02:00
|
|
|
|
(get-buffer-create (ein:notebook-get-buffer-name notebook)))
|
2012-05-13 04:13:29 +02:00
|
|
|
|
|
2012-05-17 20:12:40 +02:00
|
|
|
|
(defun ein:notebook-buffer (notebook)
|
|
|
|
|
"Return the buffer that is associated with NOTEBOOK."
|
|
|
|
|
(ewoc-buffer (ein:$notebook-ewoc notebook)))
|
|
|
|
|
|
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-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.
|
|
|
|
|
|
|
|
|
|
After the notebook is opened, CALLBACK is called as
|
|
|
|
|
\(apply CALLBACK notebook CREATED CBARGS)
|
|
|
|
|
where the second argument CREATED indicates whether the notebook
|
|
|
|
|
is newly created or not."
|
2012-05-18 03:48:36 +02:00
|
|
|
|
(let* ((key (list url-or-port notebook-id))
|
|
|
|
|
(buffer (gethash key ein:notebook-opened-map)))
|
|
|
|
|
(if (buffer-live-p buffer)
|
|
|
|
|
(with-current-buffer buffer
|
|
|
|
|
(pop-to-buffer (current-buffer))
|
2012-06-08 11:42:42 +02:00
|
|
|
|
(when callback
|
|
|
|
|
(apply callback ein:notebook nil cbargs))
|
2012-05-18 03:48:36 +02:00
|
|
|
|
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-05-26 20:41:21 +02:00
|
|
|
|
(ein:query-ajax
|
|
|
|
|
url
|
|
|
|
|
: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-06-08 13:15:55 +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-05-13 04:19:22 +02:00
|
|
|
|
(ein:notebook-init notebook data)
|
2012-05-13 04:13:29 +02:00
|
|
|
|
(with-current-buffer (ein:notebook-get-buffer notebook)
|
2012-05-13 04:19:22 +02:00
|
|
|
|
(ein:log-setup (ein:$notebook-notebook-id notebook))
|
|
|
|
|
(setq ein:notebook notebook)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:notebook-render)
|
2012-05-14 15:23:01 +02:00
|
|
|
|
(set-buffer-modified-p nil)
|
2012-05-18 03:39:39 +02:00
|
|
|
|
(puthash (list (ein:$notebook-url-or-port ein:notebook) notebook-id)
|
|
|
|
|
(current-buffer)
|
|
|
|
|
ein:notebook-opened-map)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(pop-to-buffer (current-buffer)))))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-render ()
|
|
|
|
|
"(Re-)Render the notebook."
|
|
|
|
|
(interactive)
|
2012-05-08 06:41:17 +02:00
|
|
|
|
(assert ein:notebook) ; make sure in a notebook buffer
|
2012-05-19 16:03:27 +02:00
|
|
|
|
(ein:notebook-from-json ein:notebook (ein:$notebook-data ein:notebook))
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(setq buffer-undo-list nil) ; clear undo history
|
2012-06-16 21:35:16 +02:00
|
|
|
|
(when (eq ein:notebook-enable-undo 'no)
|
|
|
|
|
(setq buffer-undo-list t))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:notebook-mode)
|
2012-05-25 02:02:31 +02:00
|
|
|
|
(setf (ein:$notebook-notification ein:notebook)
|
|
|
|
|
(ein:notification-setup (current-buffer)))
|
|
|
|
|
(ein:notebook-bind-events ein:notebook (ein:events-new (current-buffer)))
|
2012-06-07 15:56:38 +02:00
|
|
|
|
(ein:notebook-setup-traceback ein:notebook)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:notebook-start-kernel)
|
2012-05-19 16:07:18 +02:00
|
|
|
|
(ein:log 'info "Notebook %s is ready"
|
|
|
|
|
(ein:$notebook-notebook-name ein: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-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."
|
|
|
|
|
(setf (ein:$notebook-events ein:notebook) events)
|
|
|
|
|
(ein:events-on events
|
2012-06-06 21:03:54 +02:00
|
|
|
|
'set_next_input.Notebook
|
2012-05-22 20:50:47 +02:00
|
|
|
|
#'ein:notebook--set-next-input
|
|
|
|
|
notebook)
|
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-06-16 23:33:58 +02:00
|
|
|
|
(ein:events-on events
|
|
|
|
|
'maybe_reset_undo.Notebook
|
|
|
|
|
(lambda (&rest -ignore-)
|
|
|
|
|
(ein:notebook-empty-undo-maybe)))
|
2012-05-22 20:50:47 +02:00
|
|
|
|
;; Bind events for sub components:
|
2012-06-04 19:46:19 +02:00
|
|
|
|
(mapc (lambda (cell) (oset cell :events (ein:$notebook-events notebook)))
|
|
|
|
|
(ein:notebook-get-cells notebook))
|
2012-05-25 02:02:31 +02:00
|
|
|
|
(ein:notification-bind-events (ein:$notebook-notification ein:notebook)
|
|
|
|
|
events)
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(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))))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook--set-next-input (notebook data)
|
|
|
|
|
(let* ((cell (plist-get data :cell))
|
|
|
|
|
(text (plist-get data :text))
|
|
|
|
|
(new-cell (ein:notebook-insert-cell-below notebook 'code cell)))
|
|
|
|
|
(ein:cell-set-text new-cell text)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) t)))
|
|
|
|
|
|
2012-06-07 15:56:38 +02:00
|
|
|
|
(defun ein:notebook-setup-traceback (notebook)
|
|
|
|
|
(setf (ein:$notebook-traceback notebook)
|
|
|
|
|
(ein:tb-new
|
|
|
|
|
(format ein:notebook-tb-buffer-name-template
|
|
|
|
|
(ein:$notebook-url-or-port notebook)
|
|
|
|
|
(ein:$notebook-notebook-name notebook)))))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;;; Cell indexing, retrieval, etc.
|
|
|
|
|
|
2012-05-10 05:20:52 +02:00
|
|
|
|
(defun ein:notebook-cell-from-json (notebook data &rest args)
|
|
|
|
|
(apply #'ein:cell-from-json
|
|
|
|
|
data :ewoc (ein:$notebook-ewoc notebook) args))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-cell-from-type (notebook type &rest args)
|
2012-05-23 18:46:09 +02:00
|
|
|
|
;; Note: TYPE can be a string.
|
2012-05-23 15:46:51 +02:00
|
|
|
|
;; FIXME: unify type of TYPE to symbol or string.
|
2012-05-10 05:20:52 +02:00
|
|
|
|
(apply #'ein:cell-from-type
|
2012-06-04 16:18:17 +02:00
|
|
|
|
(format "%s" type)
|
|
|
|
|
:ewoc (ein:$notebook-ewoc notebook)
|
|
|
|
|
:events (ein:$notebook-events notebook)
|
|
|
|
|
args))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-get-cells (notebook)
|
|
|
|
|
(let* ((ewoc (ein:$notebook-ewoc notebook))
|
|
|
|
|
(nodes (ewoc-collect ewoc (lambda (n) (ein:cell-node-p n 'prompt)))))
|
|
|
|
|
(mapcar #'ein:$node-data nodes)))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-ncells (notebook)
|
|
|
|
|
(length (ein:notebook-get-cells notebook)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Insertion and deletion of cells
|
|
|
|
|
|
2012-05-11 00:48:22 +02:00
|
|
|
|
(defun ein:notebook-delete-cell (notebook cell)
|
2012-05-25 17:57:52 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
2012-05-11 00:48:22 +02:00
|
|
|
|
(apply #'ewoc-delete
|
|
|
|
|
(ein:$notebook-ewoc notebook)
|
|
|
|
|
(ein:cell-all-element cell)))
|
2012-06-16 21:35:16 +02:00
|
|
|
|
(setf (ein:$notebook-dirty notebook) t)
|
|
|
|
|
(ein:notebook-empty-undo-maybe))
|
2012-05-11 00:48:22 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-delete-cell-command ()
|
2012-05-25 18:06:45 +02:00
|
|
|
|
"Delete a cell. \(WARNING: no undo!)
|
|
|
|
|
This command has no key binding because there is no way to undo
|
|
|
|
|
deletion. Use kill to play on the safe side.
|
|
|
|
|
|
2012-06-11 14:13:57 +02:00
|
|
|
|
If you really want use this command, you can do something like this
|
|
|
|
|
\(but be careful when using it!)::
|
|
|
|
|
|
2012-05-25 18:06:45 +02:00
|
|
|
|
\(define-key ein:notebook-mode-map \"\\C-c\\C-d\"
|
2012-06-11 14:13:57 +02:00
|
|
|
|
'ein:notebook-delete-cell-command)"
|
2012-05-11 00:48:22 +02:00
|
|
|
|
(interactive)
|
2012-05-11 14:39:41 +02:00
|
|
|
|
(ein:notebook-with-cell nil
|
2012-05-15 05:03:30 +02:00
|
|
|
|
(ein:notebook-delete-cell ein:notebook cell)
|
|
|
|
|
(ein:aif (ein:notebook-get-current-cell) (ein:cell-goto it))))
|
2012-05-11 00:48:22 +02:00
|
|
|
|
|
2012-06-13 00:18:12 +02:00
|
|
|
|
(defun ein:notebook-kill-cells (notebook cells)
|
|
|
|
|
(when cells
|
|
|
|
|
(mapc (lambda (c)
|
|
|
|
|
(ein:cell-save-text c)
|
|
|
|
|
(ein:notebook-delete-cell notebook c)
|
|
|
|
|
(ein:cell-deactivate c))
|
|
|
|
|
cells)
|
|
|
|
|
(ein:kill-new cells)))
|
|
|
|
|
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(defun ein:notebook-kill-cell-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Kill (\"cut\") the cell at point.
|
2012-06-11 14:13:57 +02:00
|
|
|
|
Note that the kill-ring for cells is not shared with the default
|
2012-06-11 06:15:34 +02:00
|
|
|
|
kill-ring of Emacs (kill-ring for texts)."
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(interactive)
|
2012-06-13 00:18:12 +02:00
|
|
|
|
(ein:notebook-with-cells-in-region
|
|
|
|
|
(ein:notebook-kill-cells ein:notebook cells)
|
2012-06-13 12:17:31 +02:00
|
|
|
|
(deactivate-mark)
|
2012-05-15 05:03:30 +02:00
|
|
|
|
(ein:aif (ein:notebook-get-current-cell) (ein:cell-goto it))))
|
2012-05-14 23:47:10 +02:00
|
|
|
|
|
2012-05-15 02:30:27 +02:00
|
|
|
|
(defun ein:notebook-copy-cell-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Copy the cell at point. (Put the current cell into the kill-ring.)"
|
2012-05-15 02:30:27 +02:00
|
|
|
|
(interactive)
|
2012-06-13 00:18:12 +02:00
|
|
|
|
(ein:notebook-with-cells-in-region
|
2012-06-13 12:17:31 +02:00
|
|
|
|
(deactivate-mark)
|
2012-06-17 12:52:09 +02:00
|
|
|
|
(let ((cells (mapcar
|
|
|
|
|
(lambda (c)
|
|
|
|
|
(ein:cell-deactivate (ein:cell-copy c))) cells)))
|
|
|
|
|
(ein:log 'info "%s cells are copied." (length cells))
|
|
|
|
|
(ein:kill-new cells))))
|
2012-05-15 02:30:27 +02:00
|
|
|
|
|
2012-06-13 00:54:19 +02:00
|
|
|
|
(defun ein:notebook-insert-clone-below (notebook cell pivot)
|
|
|
|
|
(let ((clone (ein:cell-copy cell)))
|
|
|
|
|
;; Cell can be from another buffer, so reset `ewoc'.
|
|
|
|
|
(oset clone :ewoc (ein:$notebook-ewoc notebook))
|
|
|
|
|
(ein:notebook-insert-cell-below notebook clone pivot)
|
|
|
|
|
clone))
|
|
|
|
|
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(defun ein:notebook-yank-cell-command (&optional arg)
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Insert (\"paste\") the latest killed cell.
|
|
|
|
|
Prefixes are act same as the normal `yank' command."
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(interactive "*P")
|
2012-05-16 12:08:53 +02:00
|
|
|
|
;; Do not use `ein:notebook-with-cell'.
|
|
|
|
|
;; `ein:notebook-insert-cell-below' handles empty cell.
|
|
|
|
|
(let* ((cell (ein:notebook-get-current-cell))
|
|
|
|
|
(killed (ein:current-kill (cond
|
|
|
|
|
((listp arg) 0)
|
|
|
|
|
((eq arg '-) -2)
|
2012-06-13 00:54:19 +02:00
|
|
|
|
(t (1- arg))))))
|
|
|
|
|
(loop for c in killed
|
2012-06-13 00:18:12 +02:00
|
|
|
|
with last = cell
|
2012-06-13 00:54:19 +02:00
|
|
|
|
do (setq last (ein:notebook-insert-clone-below ein:notebook c last))
|
|
|
|
|
finally (ein:cell-goto last))))
|
2012-05-14 23:47:10 +02:00
|
|
|
|
|
2012-05-18 01:38:59 +02:00
|
|
|
|
(defun ein:notebook-maybe-new-cell (notebook type-or-cell)
|
|
|
|
|
"Return TYPE-OR-CELL as-is if it is a cell, otherwise return a new cell."
|
2012-05-23 18:46:09 +02:00
|
|
|
|
(let ((cell (if (ein:basecell-child-p type-or-cell)
|
|
|
|
|
type-or-cell
|
|
|
|
|
(ein:notebook-cell-from-type notebook type-or-cell))))
|
|
|
|
|
;; When newly created or copied, kernel is not attached or not the
|
|
|
|
|
;; kernel of this notebook. So reset it here.
|
|
|
|
|
(when (ein:codecell-p cell)
|
|
|
|
|
(oset cell :kernel (ein:$notebook-kernel notebook)))
|
2012-06-05 21:52:51 +02:00
|
|
|
|
(oset cell :events (ein:$notebook-events notebook))
|
2012-05-23 18:46:09 +02:00
|
|
|
|
cell))
|
2012-05-18 01:38:59 +02:00
|
|
|
|
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(defun ein:notebook-insert-cell-below (notebook type-or-cell base-cell)
|
2012-05-19 13:10:44 +02:00
|
|
|
|
"Insert a cell just after BASE-CELL and return the new cell."
|
2012-05-18 01:38:59 +02:00
|
|
|
|
(let ((cell (ein:notebook-maybe-new-cell notebook type-or-cell)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(when cell
|
|
|
|
|
(cond
|
|
|
|
|
((= (ein:notebook-ncells notebook) 0)
|
|
|
|
|
(ein:cell-enter-last cell))
|
|
|
|
|
(base-cell
|
2012-05-13 07:14:33 +02:00
|
|
|
|
(ein:cell-insert-below base-cell cell))
|
|
|
|
|
(t (error (concat "`base-cell' is `nil' but ncells != 0. "
|
|
|
|
|
"There is something wrong..."))))
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:notebook-empty-undo-maybe)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:cell-goto cell)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) t))
|
|
|
|
|
cell))
|
|
|
|
|
|
2012-05-11 00:23:42 +02:00
|
|
|
|
(defun ein:notebook-insert-cell-below-command (&optional markdown)
|
2012-05-14 22:12:08 +02:00
|
|
|
|
"Insert cell below. Insert markdown cell instead of code cell
|
2012-05-11 00:23:42 +02:00
|
|
|
|
when the prefix argument is given."
|
|
|
|
|
(interactive "P")
|
2012-05-13 07:11:04 +02:00
|
|
|
|
(let ((cell (ein:notebook-get-current-cell)))
|
|
|
|
|
;; Do not use `ein:notebook-with-cell'. When there is no cell,
|
|
|
|
|
;; This command should add the first cell. So this clause must be
|
|
|
|
|
;; executed even if `cell' is `nil'.
|
2012-05-15 05:03:30 +02:00
|
|
|
|
(ein:cell-goto
|
|
|
|
|
(ein:notebook-insert-cell-below ein:notebook
|
|
|
|
|
(if markdown 'markdown 'code)
|
|
|
|
|
cell))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-18 01:38:59 +02:00
|
|
|
|
(defun ein:notebook-insert-cell-above (notebook type-or-cell base-cell)
|
|
|
|
|
(let ((cell (ein:notebook-maybe-new-cell notebook type-or-cell)))
|
2012-05-14 22:12:08 +02:00
|
|
|
|
(when cell
|
|
|
|
|
(cond
|
|
|
|
|
((< (ein:notebook-ncells notebook) 2)
|
|
|
|
|
(ein:cell-enter-first cell))
|
|
|
|
|
(base-cell
|
|
|
|
|
(let ((prev-cell (ein:cell-prev base-cell)))
|
|
|
|
|
(if prev-cell
|
|
|
|
|
(ein:cell-insert-below prev-cell cell)
|
|
|
|
|
(ein:cell-enter-first cell))))
|
|
|
|
|
(t (error (concat "`base-cell' is `nil' but ncells > 1. "
|
|
|
|
|
"There is something wrong..."))))
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:notebook-empty-undo-maybe)
|
2012-05-14 22:12:08 +02:00
|
|
|
|
(ein:cell-goto cell)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) t))
|
|
|
|
|
cell))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-insert-cell-above-command (&optional markdown)
|
|
|
|
|
"Insert cell above. Insert markdown cell instead of code cell
|
|
|
|
|
when the prefix argument is given."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(let ((cell (ein:notebook-get-current-cell)))
|
2012-05-15 05:03:30 +02:00
|
|
|
|
(ein:cell-goto
|
|
|
|
|
(ein:notebook-insert-cell-above ein:notebook
|
|
|
|
|
(if markdown 'markdown 'code)
|
|
|
|
|
cell))))
|
2012-05-14 22:12:08 +02:00
|
|
|
|
|
2012-05-11 23:52:32 +02:00
|
|
|
|
(defun ein:notebook-toggle-cell-type ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Toggle the cell type of the cell at point.
|
|
|
|
|
Use `ein:notebook-change-cell-type' to change the cell type
|
|
|
|
|
directly."
|
2012-05-11 23:52:32 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell nil
|
2012-06-02 12:48:00 +02:00
|
|
|
|
(let ((type (case (ein:$notebook-nbformat ein:notebook)
|
|
|
|
|
(2 (ein:case-equal (oref cell :cell-type)
|
|
|
|
|
(("code") "markdown")
|
|
|
|
|
(("markdown") "code")))
|
|
|
|
|
(3 (ein:case-equal (oref cell :cell-type)
|
|
|
|
|
(("code") "markdown")
|
|
|
|
|
(("markdown") "raw")
|
|
|
|
|
(("raw") "heading")
|
|
|
|
|
(("heading") "code"))))))
|
2012-06-02 21:47:03 +02:00
|
|
|
|
(let ((new (ein:cell-convert-inplace cell type)))
|
|
|
|
|
(when (ein:codecell-p new)
|
|
|
|
|
(oset new :kernel (ein:$notebook-kernel ein:notebook)))
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:notebook-empty-undo-maybe)
|
2012-06-02 21:47:03 +02:00
|
|
|
|
(ein:cell-goto new)))))
|
2012-05-11 23:52:32 +02:00
|
|
|
|
|
2012-06-02 18:46:02 +02:00
|
|
|
|
(defun ein:notebook-change-cell-type ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Change the cell type of the current cell.
|
|
|
|
|
Prompt will appear in the minibuffer."
|
2012-06-02 18:46:02 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
(let* ((choices (case (ein:$notebook-nbformat ein:notebook)
|
|
|
|
|
(2 "cm")
|
|
|
|
|
(3 "cmr123456")))
|
|
|
|
|
(key (ein:ask-choice-char
|
|
|
|
|
(format "Cell type [%s]: " choices) choices))
|
|
|
|
|
(type (case key
|
|
|
|
|
(?c "code")
|
|
|
|
|
(?m "markdown")
|
|
|
|
|
(?r "raw")
|
|
|
|
|
(t "heading")))
|
|
|
|
|
(level (when (equal type "heading")
|
|
|
|
|
(string-to-number (char-to-string key)))))
|
2012-06-02 21:47:03 +02:00
|
|
|
|
(let ((new (ein:cell-convert-inplace cell type)))
|
|
|
|
|
(when (ein:codecell-p new)
|
|
|
|
|
(oset new :kernel (ein:$notebook-kernel ein:notebook)))
|
|
|
|
|
(when level
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:cell-change-level new type))
|
|
|
|
|
(ein:notebook-empty-undo-maybe)))))
|
2012-06-02 18:46:02 +02:00
|
|
|
|
|
2012-05-19 03:54:27 +02:00
|
|
|
|
(defun ein:notebook-split-cell-at-point (&optional no-trim)
|
|
|
|
|
"Split cell at current position. Newlines at the splitting
|
|
|
|
|
point will be removed. This can be omitted by giving a prefix
|
|
|
|
|
argument \(C-u)."
|
|
|
|
|
(interactive "P")
|
2012-05-17 15:48:21 +02:00
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
;; FIXME: should I inhibit undo?
|
|
|
|
|
(let* ((end (ein:cell-input-pos-max cell))
|
|
|
|
|
(pos (point))
|
|
|
|
|
(tail (buffer-substring pos end))
|
|
|
|
|
(new (ein:notebook-insert-cell-below ein:notebook
|
|
|
|
|
(oref cell :cell-type)
|
|
|
|
|
cell)))
|
|
|
|
|
(delete-region pos end)
|
2012-05-19 03:54:27 +02:00
|
|
|
|
(unless no-trim
|
2012-05-19 04:19:17 +02:00
|
|
|
|
(setq tail (ein:trim-left tail "\n"))
|
2012-05-19 03:54:27 +02:00
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char pos)
|
|
|
|
|
(ignore-errors
|
|
|
|
|
(while t
|
|
|
|
|
(search-backward-regexp "\n\\=")
|
|
|
|
|
(delete-char 1)))))
|
2012-05-17 15:48:21 +02:00
|
|
|
|
(ein:cell-set-text new tail))))
|
|
|
|
|
|
2012-05-19 13:23:26 +02:00
|
|
|
|
(defun ein:notebook-merge-cell-command (&optional prev)
|
|
|
|
|
"Merge next cell into current cell.
|
|
|
|
|
If prefix is given, merge current cell into previous cell."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
(when prev
|
|
|
|
|
(setq cell (ein:cell-prev cell))
|
2012-05-19 13:49:17 +02:00
|
|
|
|
(unless cell (error "No previous cell"))
|
2012-05-19 13:23:26 +02:00
|
|
|
|
(ein:cell-goto cell))
|
|
|
|
|
(let* ((next-cell (ein:cell-next cell))
|
2012-06-17 09:50:45 +02:00
|
|
|
|
(tail (ein:cell-get-text next-cell)))
|
2012-05-19 13:23:26 +02:00
|
|
|
|
(ein:notebook-delete-cell ein:notebook next-cell)
|
|
|
|
|
(save-excursion
|
|
|
|
|
(goto-char (1- (ein:cell-location cell :input t)))
|
|
|
|
|
(insert "\n" tail)))))
|
|
|
|
|
|
2012-05-11 16:38:29 +02:00
|
|
|
|
|
|
|
|
|
;;; Cell selection.
|
|
|
|
|
|
2012-05-18 02:59:00 +02:00
|
|
|
|
(defun ein:notebook-goto-input (ewoc-node up)
|
|
|
|
|
(let* ((ewoc-data (ewoc-data ewoc-node))
|
|
|
|
|
(cell (ein:$node-data ewoc-data))
|
|
|
|
|
(path (ein:$node-path ewoc-data))
|
|
|
|
|
(element (nth 1 path)))
|
|
|
|
|
(ein:aif
|
2012-05-18 03:54:23 +02:00
|
|
|
|
(if (memql element (if up '(output footer) '(prompt)))
|
2012-05-18 02:59:00 +02:00
|
|
|
|
cell
|
|
|
|
|
(funcall (if up #'ein:cell-prev #'ein:cell-next) cell))
|
2012-05-11 16:38:29 +02:00
|
|
|
|
(ein:cell-goto it)
|
2012-05-18 02:59:00 +02:00
|
|
|
|
(ein:log 'warn "No %s input!" (if up "previous" "next")))))
|
2012-05-11 16:38:29 +02:00
|
|
|
|
|
2012-05-18 02:59:00 +02:00
|
|
|
|
(defun ein:notebook-goto-input-in-notebook-buffer (up)
|
|
|
|
|
(ein:aif (ein:notebook-get-current-ewoc-node)
|
|
|
|
|
(ein:notebook-goto-input it up)
|
|
|
|
|
(ein:log 'warn "Not in notebook buffer!")))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-goto-next-input-command ()
|
2012-05-11 16:38:29 +02:00
|
|
|
|
(interactive)
|
2012-05-18 02:59:00 +02:00
|
|
|
|
(ein:notebook-goto-input-in-notebook-buffer nil))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-goto-prev-input-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-goto-input-in-notebook-buffer t))
|
2012-05-11 16:38:29 +02:00
|
|
|
|
|
2012-05-18 01:38:59 +02:00
|
|
|
|
|
|
|
|
|
;;; Cell movement
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-move-cell (notebook cell up)
|
|
|
|
|
(ein:aif (if up (ein:cell-prev cell) (ein:cell-next cell))
|
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(pivot-cell it))
|
|
|
|
|
(ein:cell-save-text cell)
|
|
|
|
|
(ein:notebook-delete-cell ein:notebook cell)
|
|
|
|
|
(funcall (if up
|
|
|
|
|
#'ein:notebook-insert-cell-above
|
|
|
|
|
#'ein:notebook-insert-cell-below)
|
|
|
|
|
notebook cell pivot-cell)
|
|
|
|
|
(ein:cell-goto cell)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) t))
|
|
|
|
|
(ein:log 'warn "No %s cell" (if up "previous" "next"))))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-move-cell-up-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
(ein:notebook-move-cell ein:notebook cell t)))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-move-cell-down-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
(ein:notebook-move-cell ein:notebook cell nil)))
|
|
|
|
|
|
2012-05-16 20:44:47 +02:00
|
|
|
|
|
|
|
|
|
;;; Cell collapsing and output clearing
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-toggle-output (notebook cell)
|
|
|
|
|
(ein:cell-toggle-output cell)
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:notebook-empty-undo-maybe)
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(setf (ein:$notebook-dirty notebook) t))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-toggle-output-command ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Toggle the visibility of the output of the cell at point.
|
|
|
|
|
This does not alter the actual data stored in the cell."
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
|
|
|
|
(ein:notebook-toggle-output ein:notebook cell)))
|
|
|
|
|
|
2012-05-16 21:18:25 +02:00
|
|
|
|
(defun ein:notebook-set-collapsed-all (notebook collapsed)
|
|
|
|
|
(mapc (lambda (c)
|
|
|
|
|
(when (ein:codecell-p c) (ein:cell-set-collapsed c collapsed)))
|
|
|
|
|
(ein:notebook-get-cells notebook))
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:notebook-empty-undo-maybe)
|
2012-05-16 21:18:25 +02:00
|
|
|
|
(setf (ein:$notebook-dirty notebook) t))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-set-collapsed-all-command (&optional show)
|
|
|
|
|
"Hide all cell output. When prefix is given, show all cell output."
|
|
|
|
|
(interactive "P")
|
|
|
|
|
(ein:notebook-set-collapsed-all ein:notebook (not show)))
|
|
|
|
|
|
2012-05-18 22:20:12 +02:00
|
|
|
|
(defun ein:notebook-clear-output-command (&optional preserve-input-prompt)
|
|
|
|
|
"Clear output from the current cell at point.
|
2012-05-18 22:12:18 +02:00
|
|
|
|
Do not clear input prompt when the prefix argument is given."
|
2012-05-18 22:20:12 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
|
|
|
|
(ein:cell-clear-output cell t t t)
|
|
|
|
|
(unless preserve-input-prompt
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:cell-set-input-prompt cell))
|
|
|
|
|
(ein:notebook-empty-undo-maybe)))
|
2012-05-18 22:20:12 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-clear-all-output-command (&optional preserve-input-prompt)
|
|
|
|
|
"Clear output from all cells.
|
|
|
|
|
Do not clear input prompts when the prefix argument is given."
|
2012-05-18 22:12:18 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(if ein:notebook
|
|
|
|
|
(loop for cell in (ein:notebook-get-cells ein:notebook)
|
|
|
|
|
do (when (ein:codecell-p cell)
|
|
|
|
|
(ein:cell-clear-output cell t t t)
|
|
|
|
|
(unless preserve-input-prompt
|
2012-06-16 22:14:20 +02:00
|
|
|
|
(ein:cell-set-input-prompt cell))
|
|
|
|
|
(ein:notebook-empty-undo-maybe)))
|
2012-05-18 22:12:18 +02:00
|
|
|
|
(ein:log 'error "Not in notebook buffer!")))
|
|
|
|
|
|
2012-06-07 16:08:00 +02:00
|
|
|
|
|
|
|
|
|
;;; Traceback
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-view-traceback ()
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Open traceback viewer for the traceback at point."
|
2012-06-07 16:08:00 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
|
|
|
|
(let ((tb-data
|
|
|
|
|
(loop for out in (oref cell :outputs)
|
|
|
|
|
when (equal (plist-get out :output_type) "pyerr")
|
|
|
|
|
return (plist-get out :traceback))))
|
2012-06-07 23:46:18 +02:00
|
|
|
|
(if tb-data
|
|
|
|
|
(ein:tb-popup (ein:$notebook-traceback ein:notebook) tb-data)
|
|
|
|
|
(ein:log 'info "No Traceback found for the current cell.")))))
|
2012-06-07 16:08:00 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
;;; Kernel related things
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-start-kernel ()
|
2012-05-22 20:50:47 +02:00
|
|
|
|
(let* ((base-url (concat ein:base-kernel-url "kernels"))
|
|
|
|
|
(kernel (ein:kernel-new (ein:$notebook-url-or-port ein:notebook)
|
2012-05-22 22:34:00 +02:00
|
|
|
|
base-url
|
|
|
|
|
(ein:$notebook-events ein:notebook))))
|
2012-05-19 16:03:27 +02:00
|
|
|
|
(setf (ein:$notebook-kernel ein: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-05-22 22:31:53 +02:00
|
|
|
|
(ein:$notebook-notebook-id ein:notebook))
|
|
|
|
|
(loop for cell in (ein:notebook-get-cells ein:notebook)
|
|
|
|
|
do (when (ein:codecell-p cell)
|
|
|
|
|
(ein:cell-set-kernel cell kernel)))))
|
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)
|
|
|
|
|
(if ein:notebook
|
|
|
|
|
(when (y-or-n-p "Really restart kernel? ")
|
|
|
|
|
(ein:notebook-restart-kernel ein:notebook))
|
|
|
|
|
(ein:log 'error "Not in notebook buffer!")))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-get-current-ewoc-node (&optional pos)
|
|
|
|
|
(ein:aand ein:notebook (ein:$notebook-ewoc it) (ewoc-locate it pos)))
|
|
|
|
|
|
2012-05-10 21:52:40 +02:00
|
|
|
|
(defun ein:notebook-get-nearest-cell-ewoc-node (&optional pos max cell-p)
|
2012-05-10 19:55:49 +02:00
|
|
|
|
(ein:aif (ein:notebook-get-current-ewoc-node pos)
|
|
|
|
|
(let ((ewoc-node it))
|
|
|
|
|
;; FIXME: can be optimized using the argument `max'
|
|
|
|
|
(while (and ewoc-node
|
2012-05-10 21:52:40 +02:00
|
|
|
|
(not (and (ein:cell-ewoc-node-p ewoc-node)
|
|
|
|
|
(if cell-p
|
|
|
|
|
(funcall cell-p
|
|
|
|
|
(ein:cell-from-ewoc-node ewoc-node))
|
|
|
|
|
t))))
|
2012-05-19 16:07:18 +02:00
|
|
|
|
(setq ewoc-node (ewoc-next (ein:$notebook-ewoc ein:notebook)
|
|
|
|
|
ewoc-node)))
|
2012-05-10 19:55:49 +02:00
|
|
|
|
ewoc-node)))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:notebook-get-current-cell (&optional pos)
|
2012-05-10 21:08:27 +02:00
|
|
|
|
(let ((cell (ein:cell-from-ewoc-node
|
|
|
|
|
(ein:notebook-get-current-ewoc-node pos))))
|
2012-05-10 13:05:02 +02:00
|
|
|
|
(when (ein:basecell-child-p cell) cell)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-06-13 00:18:12 +02:00
|
|
|
|
(defun ein:notebook-get-cells-in-region (beg end)
|
|
|
|
|
(ein:clip-list (ein:aand ein:notebook (ein:notebook-get-cells it))
|
|
|
|
|
(ein:notebook-get-current-cell beg)
|
|
|
|
|
(ein:notebook-get-current-cell end)))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-get-cells-in-region-or-at-point ()
|
|
|
|
|
(if (region-active-p)
|
|
|
|
|
(ein:notebook-get-cells-in-region (region-beginning) (region-end))
|
|
|
|
|
(list (ein:notebook-get-current-cell))))
|
|
|
|
|
|
2012-06-17 13:41:23 +02:00
|
|
|
|
(defun ein:notebook-execute-cell (notebook cell)
|
|
|
|
|
(ein:kernel-if-ready (ein:$notebook-kernel notebook)
|
|
|
|
|
(ein:cell-execute cell)
|
|
|
|
|
(setf (ein:$notebook-dirty notebook) t)
|
|
|
|
|
cell))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:notebook-execute-current-cell ()
|
2012-05-17 02:57:32 +02:00
|
|
|
|
"Execute cell at point."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(interactive)
|
2012-05-11 14:39:41 +02:00
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
2012-06-17 13:41:23 +02:00
|
|
|
|
(ein:notebook-execute-cell ein:notebook cell)))
|
2012-05-17 02:57:32 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-execute-current-cell-and-goto-next ()
|
2012-06-17 13:41:23 +02:00
|
|
|
|
"Execute cell at point if it is a code cell and move to the
|
|
|
|
|
next cell, or insert if none."
|
2012-05-17 02:57:32 +02:00
|
|
|
|
(interactive)
|
2012-06-17 13:41:23 +02:00
|
|
|
|
(ein:notebook-with-cell nil
|
|
|
|
|
(when (ein:codecell-p cell)
|
|
|
|
|
(ein:notebook-execute-cell ein:notebook cell))
|
|
|
|
|
(ein:aif (ein:cell-next cell)
|
|
|
|
|
(ein:cell-goto it)
|
|
|
|
|
(ein:notebook-insert-cell-below ein:notebook 'code cell))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-17 05:26:11 +02:00
|
|
|
|
(defun ein:notebook-execute-all-cell ()
|
|
|
|
|
"Execute all cells in the current notebook buffer."
|
|
|
|
|
(interactive)
|
|
|
|
|
(if ein:notebook
|
|
|
|
|
(loop for cell in (ein:notebook-get-cells ein:notebook)
|
|
|
|
|
when (ein:codecell-p cell)
|
2012-05-22 22:34:56 +02:00
|
|
|
|
do (ein:cell-execute cell))
|
2012-05-17 05:26:11 +02:00
|
|
|
|
(ein:log 'error "Not in notebook buffer!")))
|
|
|
|
|
|
2012-05-16 04:53:38 +02:00
|
|
|
|
(defun ein:notebook-request-tool-tip (notebook cell func)
|
2012-05-22 22:03:06 +02:00
|
|
|
|
(let ((kernel (ein:$notebook-kernel notebook))
|
|
|
|
|
(callbacks
|
|
|
|
|
(list :object_info_reply
|
|
|
|
|
(cons #'ein:cell-finish-tooltip cell))))
|
|
|
|
|
(ein:kernel-object-info-request kernel func callbacks)))
|
2012-05-16 04:53:38 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-request-tool-tip-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
2012-05-19 16:03:27 +02:00
|
|
|
|
(ein:kernel-if-ready (ein:$notebook-kernel ein:notebook)
|
2012-05-16 05:04:30 +02:00
|
|
|
|
(let ((func (ein:object-at-point)))
|
2012-05-16 04:53:38 +02:00
|
|
|
|
(ein:notebook-request-tool-tip ein:notebook cell func)))))
|
|
|
|
|
|
2012-05-23 04:23:17 +02:00
|
|
|
|
(defun ein:notebook-request-help (notebook)
|
|
|
|
|
(ein:kernel-if-ready (ein:$notebook-kernel notebook)
|
|
|
|
|
(let ((func (ein:object-at-point)))
|
|
|
|
|
(when func
|
|
|
|
|
(ein:kernel-execute (ein:$notebook-kernel notebook)
|
|
|
|
|
(format "%s?" func) ; = code
|
|
|
|
|
nil ; = callbacks
|
|
|
|
|
;; It looks like that magic command does
|
|
|
|
|
;; not work in silent mode.
|
|
|
|
|
:silent nil)))))
|
|
|
|
|
|
2012-05-18 04:30:49 +02:00
|
|
|
|
(defun ein:notebook-request-help-command ()
|
|
|
|
|
(interactive)
|
2012-05-23 04:23:17 +02:00
|
|
|
|
(ein:notebook-request-help ein:notebook))
|
2012-05-18 04:30:49 +02:00
|
|
|
|
|
2012-05-18 04:31:57 +02:00
|
|
|
|
(defun ein:notebook-request-tool-tip-or-help-command (&optional pager)
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Show the help for the object at point using tooltip.
|
|
|
|
|
When the prefix argument ``C-u`` is given, open the help in the
|
2012-06-12 23:30:13 +02:00
|
|
|
|
pager buffer. You can explicitly specify the object by selecting it."
|
2012-05-18 04:31:57 +02:00
|
|
|
|
(interactive "P")
|
|
|
|
|
(if pager
|
|
|
|
|
(ein:notebook-request-help-command)
|
|
|
|
|
(ein:notebook-request-tool-tip-command)))
|
|
|
|
|
|
2012-05-23 11:26:51 +02:00
|
|
|
|
(defun ein:notebook-complete-at-point (notebook)
|
2012-05-22 22:03:06 +02:00
|
|
|
|
(let ((kernel (ein:$notebook-kernel notebook))
|
|
|
|
|
(callbacks
|
|
|
|
|
(list :complete_reply
|
|
|
|
|
(cons #'ein:completer-finish-completing nil))))
|
2012-05-23 11:26:51 +02:00
|
|
|
|
(ein:kernel-complete kernel
|
|
|
|
|
(thing-at-point 'line)
|
|
|
|
|
(current-column)
|
|
|
|
|
callbacks)))
|
2012-05-11 09:59:02 +02:00
|
|
|
|
|
2012-05-23 11:27:52 +02:00
|
|
|
|
(defun ein:notebook-complete-command ()
|
2012-05-11 09:59:02 +02:00
|
|
|
|
(interactive)
|
2012-05-11 14:39:41 +02:00
|
|
|
|
(ein:notebook-with-cell #'ein:codecell-p
|
2012-05-19 16:03:27 +02:00
|
|
|
|
(ein:kernel-if-ready (ein:$notebook-kernel ein:notebook)
|
2012-05-23 11:26:51 +02:00
|
|
|
|
(ein:notebook-complete-at-point ein:notebook))))
|
2012-05-11 09:59:02 +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)
|
|
|
|
|
(ein:kernel-interrupt (ein:$notebook-kernel ein:notebook)))
|
|
|
|
|
|
2012-05-13 07:37:19 +02:00
|
|
|
|
(defun ein:notebook-kernel-kill-command ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(when (y-or-n-p "Really kill kernel?")
|
|
|
|
|
(ein:kernel-kill (ein:$notebook-kernel ein:notebook))))
|
|
|
|
|
|
2012-06-02 20:40:22 +02:00
|
|
|
|
;; misc kernel related
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-eval-string (code)
|
2012-06-11 06:15:34 +02:00
|
|
|
|
"Evaluate a code. Prompt will appear asking the code to run.
|
|
|
|
|
This is handy when you want to execute something quickly without
|
|
|
|
|
making a cell. If the code outputs something, it will go to the
|
|
|
|
|
shared output buffer. You can open the buffer by the command
|
|
|
|
|
`ein:shared-output-pop-to-buffer'."
|
2012-06-02 20:40:22 +02:00
|
|
|
|
(interactive "sIP[y]: ")
|
|
|
|
|
(let ((cell (ein:shared-output-get-cell))
|
|
|
|
|
(kernel (ein:$notebook-kernel ein:notebook))
|
|
|
|
|
(code (ein:trim-indent code)))
|
|
|
|
|
(ein:cell-execute cell kernel code))
|
|
|
|
|
(ein:log 'info "Code \"%s\" is sent to the kernel." code))
|
|
|
|
|
|
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)
|
|
|
|
|
(when ein:notebook (ein:notebook-sync-directory ein:notebook)))
|
|
|
|
|
|
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)
|
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
|
(erase-buffer)
|
|
|
|
|
;; Enable nonsep for ewoc object (the last argument is non-nil).
|
|
|
|
|
;; This is for putting read-only text properties to the newlines.
|
|
|
|
|
(setf (ein:$notebook-ewoc notebook)
|
|
|
|
|
(ewoc-create 'ein:notebook-pp
|
2012-05-21 04:29:43 +02:00
|
|
|
|
(ein:propertize-read-only "\n")
|
2012-05-08 06:41:17 +02:00
|
|
|
|
nil t))
|
|
|
|
|
(mapc (lambda (cell-data)
|
|
|
|
|
(ein:cell-enter-last
|
2012-05-10 05:20:52 +02:00
|
|
|
|
(ein:notebook-cell-from-json ein:notebook cell-data)))
|
2012-05-08 06:41:17 +02:00
|
|
|
|
;; Only handle 1 worksheet for now, as in notebook.js
|
|
|
|
|
(plist-get (nth 0 (plist-get data :worksheets)) :cells))))
|
|
|
|
|
|
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-06-10 04:04:31 +02:00
|
|
|
|
(let ((cells (mapcar (lambda (c)
|
|
|
|
|
(ein:cell-to-json
|
|
|
|
|
c (ein:notebook-discard-output-p notebook c)))
|
|
|
|
|
(ein:notebook-get-cells notebook))))
|
2012-05-25 22:58:01 +02:00
|
|
|
|
`((worksheets . [((cells . ,(apply #'vector cells)))])
|
|
|
|
|
(metadata . ,(ein:$notebook-metadata notebook)))))
|
2012-05-08 06:15:23 +02:00
|
|
|
|
|
2012-05-17 04:08:18 +02:00
|
|
|
|
(defun ein:notebook-save-notebook (notebook retry)
|
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-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-05-25 22:12:34 +02:00
|
|
|
|
(ein:query-ajax
|
|
|
|
|
(ein:notebook-url notebook)
|
|
|
|
|
: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
|
|
|
|
|
(cons notebook retry))
|
|
|
|
|
:status-code
|
2012-05-27 01:58:39 +02:00
|
|
|
|
`((204 . ,(cons #'ein:notebook-save-notebook-success notebook))))))
|
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-05-17 04:08:18 +02:00
|
|
|
|
(ein:notebook-save-notebook ein:notebook 0))
|
2012-05-08 08:24:20 +02:00
|
|
|
|
|
2012-05-25 22:12:34 +02:00
|
|
|
|
(defun* ein:notebook-save-notebook-workaround (nb-retry &rest args
|
|
|
|
|
&key
|
|
|
|
|
status
|
2012-05-26 20:00:17 +02:00
|
|
|
|
response-status
|
2012-05-25 22:12:34 +02:00
|
|
|
|
&allow-other-keys)
|
|
|
|
|
;; 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-05-25 22:12:34 +02:00
|
|
|
|
(let ((notebook (car nb-retry))
|
|
|
|
|
(retry (cdr nb-retry)))
|
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))
|
|
|
|
|
(ein:notebook-save-notebook notebook (1+ retry)))
|
|
|
|
|
(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-05-25 22:43:56 +02:00
|
|
|
|
(with-current-buffer (ein:notebook-buffer notebook)
|
|
|
|
|
(set-buffer-modified-p nil))
|
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-05-25 22:12:34 +02:00
|
|
|
|
(defun ein:notebook-save-notebook-error (notebook &rest ignore)
|
2012-05-23 19:08:07 +02:00
|
|
|
|
(ein:log 'info "Failed to save 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_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-05-23 21:50:25 +02:00
|
|
|
|
(let ((name (ein:$notebook-notebook-name ein:notebook)))
|
|
|
|
|
(unless (string-match "Untitled[0-9]+" name)
|
|
|
|
|
name)))))
|
2012-05-13 05:06:49 +02:00
|
|
|
|
(ein:notebook-set-notebook-name ein:notebook name)
|
|
|
|
|
(rename-buffer (ein:notebook-get-buffer-name ein:notebook))
|
2012-05-17 04:08:18 +02:00
|
|
|
|
(ein:notebook-save-notebook ein:notebook 0))
|
2012-05-13 05:06:49 +02:00
|
|
|
|
|
2012-06-14 12:24:40 +02:00
|
|
|
|
(defun ein:notebook-kill-kernel-then-close-command ()
|
|
|
|
|
"Kill kernel and then kill notebook buffer.
|
|
|
|
|
It does not kill buffer if killing kernel fails. To close
|
|
|
|
|
notebook without killing kernel, just close the buffer as usual."
|
|
|
|
|
(interactive)
|
|
|
|
|
(when (ein:notebook-ask-before-kill-buffer)
|
|
|
|
|
(ein:kernel-kill
|
|
|
|
|
(ein:$notebook-kernel ein:notebook)
|
|
|
|
|
(lambda (notebook)
|
|
|
|
|
(let ((ein:notebook-kill-buffer-ask nil))
|
|
|
|
|
(kill-buffer (ein:notebook-buffer notebook))))
|
|
|
|
|
(list ein:notebook))))
|
|
|
|
|
|
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))
|
|
|
|
|
|
|
|
|
|
(defun ein:notebook-mode ()
|
|
|
|
|
(funcall (ein:notebook-choose-mode)))
|
|
|
|
|
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(defvar ein:notebook-mode-map (make-sparse-keymap))
|
|
|
|
|
|
|
|
|
|
(let ((map ein:notebook-mode-map))
|
|
|
|
|
(define-key map "\C-c\C-c" 'ein:notebook-execute-current-cell)
|
|
|
|
|
(define-key map (kbd "M-RET")
|
|
|
|
|
'ein:notebook-execute-current-cell-and-goto-next)
|
|
|
|
|
(define-key map "\C-c\C-e" 'ein:notebook-toggle-output-command)
|
|
|
|
|
(define-key map "\C-c\C-v" 'ein:notebook-set-collapsed-all-command)
|
|
|
|
|
(define-key map "\C-c\C-l" 'ein:notebook-clear-output-command)
|
|
|
|
|
(define-key map (kbd "C-c C-S-l") 'ein:notebook-clear-all-output-command)
|
|
|
|
|
(define-key map "\C-c\C-k" 'ein:notebook-kill-cell-command)
|
|
|
|
|
(define-key map "\C-c\M-w" 'ein:notebook-copy-cell-command)
|
2012-06-18 17:01:52 +02:00
|
|
|
|
(define-key map "\C-c\C-w" 'ein:notebook-copy-cell-command)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(define-key map "\C-c\C-y" 'ein:notebook-yank-cell-command)
|
|
|
|
|
(define-key map "\C-c\C-a" 'ein:notebook-insert-cell-above-command)
|
|
|
|
|
(define-key map "\C-c\C-b" 'ein:notebook-insert-cell-below-command)
|
|
|
|
|
(define-key map "\C-c\C-t" 'ein:notebook-toggle-cell-type)
|
|
|
|
|
(define-key map "\C-c\C-u" 'ein:notebook-change-cell-type)
|
|
|
|
|
(define-key map "\C-c\C-s" 'ein:notebook-split-cell-at-point)
|
|
|
|
|
(define-key map "\C-c\C-m" 'ein:notebook-merge-cell-command)
|
|
|
|
|
(define-key map "\C-c\C-n" 'ein:notebook-goto-next-input-command)
|
|
|
|
|
(define-key map "\C-c\C-p" 'ein:notebook-goto-prev-input-command)
|
2012-06-14 16:22:13 +02:00
|
|
|
|
(define-key map (kbd "C-<up>") 'ein:notebook-goto-prev-input-command)
|
|
|
|
|
(define-key map (kbd "C-<down>") 'ein:notebook-goto-next-input-command)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(define-key map (kbd "C-c <up>") 'ein:notebook-move-cell-up-command)
|
|
|
|
|
(define-key map (kbd "C-c <down>") 'ein:notebook-move-cell-down-command)
|
2012-06-14 16:22:13 +02:00
|
|
|
|
(define-key map (kbd "M-<up>") 'ein:notebook-move-cell-up-command)
|
|
|
|
|
(define-key map (kbd "M-<down>") 'ein:notebook-move-cell-down-command)
|
2012-06-14 12:42:57 +02:00
|
|
|
|
(define-key map "\C-c\C-f" 'ein:notebook-request-tool-tip-or-help-command)
|
|
|
|
|
(define-key map "\C-c\C-i" 'ein:notebook-complete-command)
|
|
|
|
|
(define-key map "\C-c\C-x" 'ein:notebook-view-traceback)
|
|
|
|
|
(define-key map "\C-c\C-r" 'ein:notebook-restart-kernel-command)
|
|
|
|
|
(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)
|
|
|
|
|
(define-key map (kbd "C-:") 'ein:notebook-eval-string)
|
|
|
|
|
(define-key map "\C-c\C-o" 'ein:notebook-console-open)
|
|
|
|
|
(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
|
|
|
|
|
|
|
|
|
(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-05-18 23:41:33 +02:00
|
|
|
|
;; "Sync" `ein:notebook-plain-mode-map' with `ein:notebook-mode-map'.
|
|
|
|
|
;; This way, `ein:notebook-plain-mode-map' automatically changes when
|
|
|
|
|
;; `ein:notebook-mode-map' is changed.
|
|
|
|
|
(setcdr ein:notebook-plain-mode-map (cdr ein:notebook-mode-map))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-21 18:05:57 +02:00
|
|
|
|
(setcdr ein:notebook-python-mode-map (cdr ein:notebook-mode-map))
|
|
|
|
|
|
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
|
|
|
|
|
(ein:$notebook-url-or-port ein:notebook)
|
|
|
|
|
(ein:$notebook-notebook-id ein:notebook)
|
|
|
|
|
(if print (list "print")))))
|
2012-05-19 17:16:30 +02:00
|
|
|
|
(message "Opening %s in browser" url)
|
|
|
|
|
(browse-url url)))
|
|
|
|
|
|
2012-05-19 18:16:35 +02:00
|
|
|
|
(defun ein:notebook-modified-p (&optional buffer)
|
2012-05-20 03:19:55 +02:00
|
|
|
|
(unless buffer (setq buffer (current-buffer)))
|
2012-05-20 02:34:10 +02:00
|
|
|
|
(when (buffer-live-p buffer)
|
|
|
|
|
(with-current-buffer buffer
|
|
|
|
|
(and (ein:$notebook-p ein:notebook)
|
|
|
|
|
(or (ein:$notebook-dirty ein:notebook)
|
|
|
|
|
(buffer-modified-p))))))
|
2012-05-19 18:16:35 +02:00
|
|
|
|
|
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-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-06-08 13:17:41 +02:00
|
|
|
|
(defun ein:notebook-force-kill-buffers (buffers)
|
|
|
|
|
"Kill notebook BUFFERS without confirmation."
|
|
|
|
|
(let ((ein:notebook-kill-buffer-ask nil))
|
|
|
|
|
(mapc #'kill-buffer buffers)))
|
|
|
|
|
|
2012-05-23 10:48:43 +02:00
|
|
|
|
(defun ein:notebook-opened-buffers ()
|
|
|
|
|
"Return list of opened buffers.
|
|
|
|
|
This function also cleans up closed buffers stores in
|
|
|
|
|
`ein:notebook-opened-map'."
|
|
|
|
|
(let (buffers)
|
|
|
|
|
(maphash (lambda (k b) (if (buffer-live-p b)
|
|
|
|
|
(push b buffers)
|
|
|
|
|
(remhash k ein:notebook-opened-map)))
|
|
|
|
|
ein:notebook-opened-map)
|
|
|
|
|
buffers))
|
|
|
|
|
|
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
|
|
|
|
|
(ein:notebook-opened-buffers))))
|
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-06-08 13:17:41 +02:00
|
|
|
|
(ein:notebook-force-kill-buffers 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-05-19 17:58:02 +02:00
|
|
|
|
(defun ein:notebook-kill-buffer-callback ()
|
|
|
|
|
"Call notebook destructor. This function is called via `kill-buffer-hook'."
|
|
|
|
|
(when (ein:$notebook-p ein:notebook)
|
|
|
|
|
(ein:notebook-del ein:notebook)))
|
|
|
|
|
|
|
|
|
|
(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-05-25 15:44:00 +02:00
|
|
|
|
(defun ein:notebook-kill-all-buffers ()
|
|
|
|
|
(interactive)
|
|
|
|
|
(let ((buffers (ein:notebook-opened-buffers)))
|
|
|
|
|
(if buffers
|
|
|
|
|
(if (y-or-n-p
|
|
|
|
|
(format (concat "You have %s unsaved notebook(s). "
|
|
|
|
|
"Really kill all of them?")
|
|
|
|
|
(length buffers)))
|
|
|
|
|
(progn (ein:log 'info "Killing all notebook buffers...")
|
2012-06-08 13:17:41 +02:00
|
|
|
|
(ein:notebook-force-kill-buffers buffers)
|
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-14 22:23:43 +02:00
|
|
|
|
|
|
|
|
|
;;; Console integration
|
|
|
|
|
|
2012-05-19 15:03:55 +02:00
|
|
|
|
(defcustom ein:notebook-console-security-dir ""
|
2012-05-14 20:32:10 +02:00
|
|
|
|
"Security directory setting.
|
|
|
|
|
|
2012-06-11 04:21:30 +02:00
|
|
|
|
Following types are valid:
|
|
|
|
|
|
|
|
|
|
string
|
|
|
|
|
Use this value as a path to security directory.
|
|
|
|
|
Handy when you have only one IPython server.
|
|
|
|
|
alist
|
|
|
|
|
An alist whose element is \"(URL-OR-PORT . DIR)\".
|
|
|
|
|
Key (URL-OR-PORT) can be string (URL), integer (port), or
|
|
|
|
|
`default' (symbol). The value of `default' is used when
|
|
|
|
|
other key does not much. Normally you should have this
|
|
|
|
|
entry.
|
|
|
|
|
function
|
|
|
|
|
Called with an argument URL-OR-PORT (integer or string).
|
|
|
|
|
You can have complex setting using this."
|
2012-05-19 15:03:55 +02:00
|
|
|
|
:type '(choice
|
|
|
|
|
(string :tag "Security directory"
|
|
|
|
|
"~/.config/ipython/profile_nbserver/security/")
|
|
|
|
|
(alist :tag "Security directory mapping"
|
|
|
|
|
:key-type (choice :tag "URL or PORT"
|
|
|
|
|
(string :tag "URL" "http://127.0.0.1:8888")
|
|
|
|
|
(integer :tag "PORT" 8888)
|
|
|
|
|
(const default))
|
|
|
|
|
:value-type (string :tag "Security directory"))
|
|
|
|
|
(function :tag "Security directory getter"
|
|
|
|
|
(lambda (url-or-port)
|
|
|
|
|
(format "~/.config/ipython/profile_%s/security/"
|
|
|
|
|
url-or-port))))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-09 03:36:08 +02:00
|
|
|
|
(defcustom ein:notebook-console-executable (executable-find "ipython")
|
|
|
|
|
"IPython executable used for console.
|
|
|
|
|
|
2012-06-11 04:21:30 +02:00
|
|
|
|
Example: ``\"/user/bin/ipython\"``.
|
|
|
|
|
Types same as `ein:notebook-console-security-dir' are valid."
|
2012-06-09 03:36:08 +02:00
|
|
|
|
:type '(choice
|
|
|
|
|
(string :tag "IPython executable" "/user/bin/ipython")
|
|
|
|
|
(alist :tag "IPython executable mapping"
|
|
|
|
|
:key-type (choice :tag "URL or PORT"
|
|
|
|
|
(string :tag "URL" "http://127.0.0.1:8888")
|
|
|
|
|
(integer :tag "PORT" 8888)
|
|
|
|
|
(const default))
|
|
|
|
|
:value-type (string :tag "IPython executable"
|
|
|
|
|
"/user/bin/ipython"))
|
|
|
|
|
(function :tag "IPython executable getter"
|
|
|
|
|
(lambda (url-or-port) (executable-find "ipython"))))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-05-19 15:03:55 +02:00
|
|
|
|
(defcustom ein:notebook-console-args "--profile nbserver"
|
2012-05-14 21:03:23 +02:00
|
|
|
|
"Additional argument when using console.
|
|
|
|
|
|
2012-06-11 04:21:30 +02:00
|
|
|
|
Example: ``\"--ssh HOSTNAME\"``.
|
|
|
|
|
Types same as `ein:notebook-console-security-dir' are valid."
|
2012-05-19 15:03:55 +02:00
|
|
|
|
:type '(choice
|
|
|
|
|
(string :tag "Arguments to IPython"
|
|
|
|
|
"--profile nbserver --ssh HOSTNAME")
|
|
|
|
|
(alist :tag "Arguments mapping"
|
|
|
|
|
:key-type (choice :tag "URL or PORT"
|
|
|
|
|
(string :tag "URL" "http://127.0.0.1:8888")
|
|
|
|
|
(integer :tag "PORT" 8888)
|
|
|
|
|
(const default))
|
|
|
|
|
:value-type (string :tag "Arguments to IPython"
|
|
|
|
|
"--profile nbserver --ssh HOSTNAME"))
|
|
|
|
|
(function :tag "Additional arguments getter"
|
|
|
|
|
(lambda (url-or-port)
|
|
|
|
|
(format "--ssh %s" url-or-port))))
|
|
|
|
|
:group 'ein)
|
2012-05-14 21:03:23 +02:00
|
|
|
|
|
2012-05-15 03:52:59 +02:00
|
|
|
|
(defun ein:notebook-console-security-dir-get (notebook)
|
2012-05-14 21:03:23 +02:00
|
|
|
|
(let ((dir (ein:choose-setting 'ein:notebook-console-security-dir
|
|
|
|
|
(ein:$notebook-url-or-port notebook))))
|
|
|
|
|
(if (equal dir "")
|
|
|
|
|
dir
|
|
|
|
|
(file-name-as-directory (expand-file-name dir)))))
|
|
|
|
|
|
2012-06-09 03:36:08 +02:00
|
|
|
|
(defun ein:notebook-console-executable-get (notebook)
|
|
|
|
|
(ein:choose-setting 'ein:notebook-console-executable
|
|
|
|
|
(ein:$notebook-url-or-port notebook)))
|
|
|
|
|
|
2012-05-15 03:52:59 +02:00
|
|
|
|
(defun ein:notebook-console-args-get (notebook)
|
2012-05-14 21:03:23 +02:00
|
|
|
|
(ein:choose-setting 'ein:notebook-console-args
|
|
|
|
|
(ein:$notebook-url-or-port notebook)))
|
2012-05-14 20:32:10 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:notebook-console-open ()
|
|
|
|
|
"Open IPython console.
|
2012-05-14 21:03:23 +02:00
|
|
|
|
To use this function, `ein:notebook-console-security-dir' and
|
|
|
|
|
`ein:notebook-console-args' must be set properly.
|
2012-06-11 04:21:30 +02:00
|
|
|
|
This function requires `Fabian Gallina's python.el`_ for now;
|
|
|
|
|
It should be possible to support python-mode.el. Patches are welcome!
|
|
|
|
|
|
|
|
|
|
.. _`Fabian Gallina's python.el`: https://github.com/fgallina/python.el"
|
2012-05-14 21:03:23 +02:00
|
|
|
|
;; FIXME: use %connect_info to get connection file, then I can get
|
|
|
|
|
;; rid of `ein:notebook-console-security-dir'.
|
2012-05-14 20:32:10 +02:00
|
|
|
|
(interactive)
|
|
|
|
|
(unless ein:notebook (error "Not in notebook buffer!"))
|
|
|
|
|
(if (fboundp 'python-shell-switch-to-shell)
|
2012-06-09 04:40:23 +02:00
|
|
|
|
(let* ((dir (ein:notebook-console-security-dir-get ein:notebook))
|
|
|
|
|
(kid (ein:$kernel-kernel-id
|
|
|
|
|
(ein:$notebook-kernel ein:notebook)))
|
|
|
|
|
(ipy (ein:notebook-console-executable-get ein:notebook))
|
|
|
|
|
(args (ein:notebook-console-args-get ein:notebook))
|
|
|
|
|
(python-shell-setup-codes nil)
|
|
|
|
|
(python-shell-interpreter
|
|
|
|
|
(format "python %s console --existing %skernel-%s.json %s"
|
|
|
|
|
ipy dir kid args))
|
|
|
|
|
;; python.el makes dedicated process when
|
|
|
|
|
;; `buffer-file-name' has some value.
|
|
|
|
|
(buffer-file-name (buffer-name)))
|
|
|
|
|
;; Automatically answer y to the question "Make dedicated process?"
|
|
|
|
|
(flet ((y-or-n-p (prompt) t))
|
|
|
|
|
(funcall 'python-shell-switch-to-shell)))
|
2012-05-14 20:32:10 +02:00
|
|
|
|
(ein:log 'warn "python.el is not loaded!")))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(provide 'ein-notebook)
|
|
|
|
|
|
|
|
|
|
;;; ein-notebook.el ends here
|