2012-05-07 14:41:15 +02:00
|
|
|
|
;;; ein-cell.el --- Cell 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-cell.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-cell.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-cell.el. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
2012-05-18 04:01:37 +02:00
|
|
|
|
;; Implementation note. Current implementation of cell has redundant
|
|
|
|
|
;; and not-guaranteed-to-be consistent information: `element' and
|
|
|
|
|
;; `ein:$node'. This part must be moved to ein-node.el module to
|
|
|
|
|
;; make it well capsuled.
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; IPython has cell.js, codecell.js and textcell.js.
|
|
|
|
|
;; But let's start with one file.
|
|
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
|
|
(eval-when-compile (require 'cl))
|
2012-05-10 04:24:49 +02:00
|
|
|
|
(require 'eieio)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(require 'ansi-color)
|
2012-07-10 02:47:47 +02:00
|
|
|
|
(require 'comint)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(require 'ein-log)
|
|
|
|
|
(require 'ein-utils)
|
|
|
|
|
(require 'ein-node)
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(require 'ein-kernel)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 22:19:00 +02:00
|
|
|
|
|
|
|
|
|
;;; Faces
|
|
|
|
|
|
2012-05-20 23:38:31 +02:00
|
|
|
|
(defface ein:cell-input-prompt
|
|
|
|
|
'((t :inherit header-line))
|
|
|
|
|
"Face for cell input prompt"
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-05-21 02:05:48 +02:00
|
|
|
|
(defface ein:cell-input-area
|
|
|
|
|
'((((class color) (background light))
|
|
|
|
|
:background "honeydew1")
|
|
|
|
|
(((class color) (background dark))
|
2012-05-23 19:41:02 +02:00
|
|
|
|
:background "#383838"))
|
2012-05-21 02:05:48 +02:00
|
|
|
|
"Face for cell input area"
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-07-20 20:38:04 +02:00
|
|
|
|
(defface ein:cell-heading-1
|
|
|
|
|
'((t :height 1.1 :inherit ein:cell-heading-2))
|
|
|
|
|
"Face for level 1 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defface ein:cell-heading-2
|
|
|
|
|
'((t :height 1.1 :inherit ein:cell-heading-3))
|
|
|
|
|
"Face for level 2 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defface ein:cell-heading-3
|
|
|
|
|
'((t :height 1.1 :inherit ein:cell-heading-4))
|
|
|
|
|
"Face for level 3 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defface ein:cell-heading-4
|
|
|
|
|
'((t :height 1.1 :inherit ein:cell-heading-5))
|
|
|
|
|
"Face for level 4 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defface ein:cell-heading-5
|
|
|
|
|
'((t :height 1.1 :inherit ein:cell-heading-6))
|
|
|
|
|
"Face for level 5 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
|
|
|
|
(defface ein:cell-heading-6
|
2012-07-20 20:51:37 +02:00
|
|
|
|
'((t :weight bold :inherit (variable-pitch ein:cell-input-area)))
|
2012-07-20 20:38:04 +02:00
|
|
|
|
"Face for level 6 heading."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-05-20 23:38:31 +02:00
|
|
|
|
(defface ein:cell-output-prompt
|
|
|
|
|
'((t :inherit header-line))
|
|
|
|
|
"Face for cell output prompt"
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-05-20 22:19:00 +02:00
|
|
|
|
(defface ein:cell-output-stderr
|
|
|
|
|
'((((class color) (background light))
|
|
|
|
|
:background "PeachPuff")
|
|
|
|
|
(((class color) (background dark))
|
|
|
|
|
:background "#8c5353"))
|
2012-05-20 23:27:31 +02:00
|
|
|
|
"Face for stderr cell output"
|
2012-05-20 22:19:00 +02:00
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-21 16:17:14 +02:00
|
|
|
|
(defface ein:pos-tip-face
|
2012-07-25 22:16:37 +02:00
|
|
|
|
'((t (:inherit 'popup-tip-face)))
|
2012-06-21 16:17:14 +02:00
|
|
|
|
"Face for tooltip when using pos-tip backend."
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-11 19:11:33 +02:00
|
|
|
|
|
|
|
|
|
;;; Customization
|
|
|
|
|
|
|
|
|
|
(defcustom ein:cell-traceback-level 1
|
|
|
|
|
"Number of traceback stack to show.
|
|
|
|
|
Hidden tracebacks are not discarded. You can always view them
|
|
|
|
|
using the command `ein:notebook-view-traceback'."
|
|
|
|
|
:type '(choice (integer :tag "Number of stack to show" 1)
|
|
|
|
|
(const :tag "Show all traceback" nil))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-07-17 18:48:02 +02:00
|
|
|
|
(defcustom ein:cell-max-num-outputs 5
|
|
|
|
|
"Number of maximum outputs to be shown by default.
|
2012-07-17 19:13:32 +02:00
|
|
|
|
To view full output, use `ein:notebook-show-in-shared-output'."
|
2012-07-17 18:48:02 +02:00
|
|
|
|
:type '(choice (integer :tag "Number of outputs to show" 5)
|
|
|
|
|
(const :tag "Show all traceback" nil))
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-07-29 14:43:10 +02:00
|
|
|
|
(defcustom ein:cell-autoexec-prompt "⚡"
|
|
|
|
|
"Prompt shown when the cell is executed automatically when
|
|
|
|
|
autoexec-enabled connected buffers are saved."
|
|
|
|
|
:type 'string
|
|
|
|
|
:group 'ein)
|
|
|
|
|
|
2012-06-11 19:11:33 +02:00
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
|
|
|
|
;;; EIEIO related utils
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:56:30 +02:00
|
|
|
|
(defmacro ein:oset-if-empty (obj slot value)
|
|
|
|
|
`(unless (and (slot-boundp ,obj ,slot) (oref ,obj ,slot))
|
|
|
|
|
(oset ,obj ,slot ,value)))
|
|
|
|
|
|
|
|
|
|
(defmacro ein:oref-safe (obj slot)
|
|
|
|
|
`(when (slot-boundp ,obj ,slot)
|
|
|
|
|
(oref ,obj ,slot)))
|
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
2012-05-20 22:19:00 +02:00
|
|
|
|
;;; Cell classes
|
2012-05-10 05:56:30 +02:00
|
|
|
|
|
2012-05-10 04:24:49 +02:00
|
|
|
|
(defclass ein:basecell ()
|
|
|
|
|
((cell-type :initarg :cell-type :type string)
|
|
|
|
|
(read-only :initarg :read-only :initform nil :type boolean)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ewoc :initarg :ewoc :type ewoc)
|
2012-05-10 04:24:49 +02:00
|
|
|
|
(element :initarg :element :initform nil :type list
|
|
|
|
|
:documentation "ewoc nodes")
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(element-names :initarg :element-names)
|
2012-05-10 05:56:30 +02:00
|
|
|
|
(input :initarg :input :type string
|
2012-05-10 04:24:49 +02:00
|
|
|
|
:documentation "Place to hold data until it is rendered via `ewoc'.")
|
|
|
|
|
(outputs :initarg :outputs :initform nil :type list)
|
2012-06-04 16:18:17 +02:00
|
|
|
|
(events :initarg :events :type ein:events)
|
2012-05-10 04:24:49 +02:00
|
|
|
|
(cell-id :initarg :cell-id :initform (ein:utils-uuid) :type string))
|
|
|
|
|
"Notebook cell base class")
|
|
|
|
|
|
|
|
|
|
(defclass ein:codecell (ein:basecell)
|
|
|
|
|
((cell-type :initarg :cell-type :initform "code")
|
2012-05-22 23:53:25 +02:00
|
|
|
|
(kernel :initarg :kernel :type ein:$kernel)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(element-names :initform (:prompt :input :output :footer))
|
2012-05-23 22:52:34 +02:00
|
|
|
|
(input-prompt-number :initarg :input-prompt-number
|
2012-05-23 23:01:41 +02:00
|
|
|
|
:documentation "\
|
|
|
|
|
Integer or \"*\" (running state).
|
|
|
|
|
Implementation note:
|
|
|
|
|
Typed `:input-prompt-number' becomes a problem when reading a
|
|
|
|
|
notebook that saved "*". So don't add `:type'!")
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(collapsed :initarg :collapsed :initform nil :type boolean)
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(running :initarg :running :initform nil :type boolean)
|
|
|
|
|
(dynamic :initarg :dynamic :initform nil :type boolean
|
|
|
|
|
:documentation "\
|
|
|
|
|
Whether cell output is evaluated dynamically or not.
|
|
|
|
|
|
|
|
|
|
Only Emacs lisp type output data will be affected by this
|
|
|
|
|
slot (Javascript will not be evaluated). This value must be set
|
|
|
|
|
to `t' when executing cell. See `ein:notebook-execute-cell'.
|
|
|
|
|
In the implantation of IPython web client it is passed around via
|
|
|
|
|
argument, but since it is difficult to pass argument to EWOC
|
|
|
|
|
pretty printer, `ein:codecell' instance holds this setting in a
|
2012-07-29 14:43:10 +02:00
|
|
|
|
slot.")
|
|
|
|
|
(autoexec :initarg :autoexec :initform nil :type boolean)))
|
2012-05-10 04:24:49 +02:00
|
|
|
|
|
|
|
|
|
(defclass ein:textcell (ein:basecell)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
((cell-type :initarg :cell-type :initform "text")
|
|
|
|
|
(element-names :initform (:prompt :input :footer))))
|
2012-05-10 04:24:49 +02:00
|
|
|
|
|
|
|
|
|
(defclass ein:htmlcell (ein:textcell)
|
|
|
|
|
((cell-type :initarg :cell-type :initform "html")))
|
|
|
|
|
|
|
|
|
|
(defclass ein:markdowncell (ein:textcell)
|
|
|
|
|
((cell-type :initarg :cell-type :initform "markdown")))
|
|
|
|
|
|
2012-05-19 23:45:59 +02:00
|
|
|
|
(defclass ein:rawcell (ein:textcell)
|
|
|
|
|
((cell-type :initarg :cell-type :initform "raw")))
|
|
|
|
|
|
|
|
|
|
(defclass ein:headingcell (ein:textcell)
|
|
|
|
|
((cell-type :initarg :cell-type :initform "heading")
|
|
|
|
|
(level :initarg :level :initform 1)))
|
2012-05-10 04:24:49 +02:00
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
|
|
|
|
;;; Cell factory
|
|
|
|
|
|
2012-05-10 04:24:49 +02:00
|
|
|
|
(defun ein:cell-class-from-type (type)
|
|
|
|
|
(ein:case-equal type
|
|
|
|
|
(("code") 'ein:codecell)
|
|
|
|
|
(("text") 'ein:textcell)
|
|
|
|
|
(("html") 'ein:htmlcell)
|
|
|
|
|
(("markdown") 'ein:markdowncell)
|
2012-05-19 23:45:59 +02:00
|
|
|
|
(("raw") 'ein:rawcell)
|
2012-07-17 18:29:00 +02:00
|
|
|
|
(("heading") 'ein:headingcell)
|
|
|
|
|
;; Defined in ein-shared-output.el:
|
|
|
|
|
(("shared-output") 'ein:shared-output-cell)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:20:52 +02:00
|
|
|
|
(defun ein:cell-from-type (type &rest args)
|
2012-05-10 05:39:20 +02:00
|
|
|
|
(apply (ein:cell-class-from-type type) "Cell" args))
|
2012-05-10 05:20:52 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:cell-from-json (data &rest args)
|
2012-05-10 05:39:20 +02:00
|
|
|
|
(ein:cell-init (apply #'ein:cell-from-type
|
|
|
|
|
(plist-get data :cell_type) args) data))
|
2012-05-10 12:45:38 +02:00
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-init ((cell ein:codecell) data)
|
2012-05-10 05:56:30 +02:00
|
|
|
|
(ein:oset-if-empty cell :outputs (plist-get data :outputs))
|
|
|
|
|
(ein:oset-if-empty cell :input (plist-get data :input))
|
|
|
|
|
(ein:aif (plist-get data :prompt_number)
|
|
|
|
|
(ein:oset-if-empty cell :input-prompt-number it))
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(ein:oset-if-empty cell :collapsed
|
|
|
|
|
(let ((v (plist-get data :collapsed)))
|
|
|
|
|
(if (eql v json-false) nil v)))
|
2012-05-10 12:45:38 +02:00
|
|
|
|
cell)
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-init ((cell ein:textcell) data)
|
|
|
|
|
(ein:aif (plist-get data :source)
|
|
|
|
|
(oset cell :input it))
|
|
|
|
|
cell)
|
|
|
|
|
|
2012-05-19 23:45:59 +02:00
|
|
|
|
(defmethod ein:cell-init ((cell ein:headingcell) data)
|
|
|
|
|
(call-next-method)
|
|
|
|
|
(ein:aif (plist-get data :level)
|
|
|
|
|
(oset cell :level it))
|
|
|
|
|
cell)
|
|
|
|
|
|
2012-05-11 19:00:40 +02:00
|
|
|
|
(defmethod ein:cell-convert ((cell ein:basecell) type)
|
2012-05-11 23:52:04 +02:00
|
|
|
|
(let ((new (ein:cell-from-type type)))
|
2012-05-11 19:00:40 +02:00
|
|
|
|
;; copy attributes
|
|
|
|
|
(loop for k in '(:read-only :ewoc)
|
2012-05-11 23:52:04 +02:00
|
|
|
|
do (set-slot-value new k (slot-value cell k)))
|
2012-05-11 19:00:40 +02:00
|
|
|
|
;; copy input
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(oset new :input (if (ein:cell-active-p cell)
|
|
|
|
|
(ein:cell-get-text cell)
|
|
|
|
|
(oref cell :input)))
|
2012-05-11 19:00:40 +02:00
|
|
|
|
;; copy output when the new cell has it
|
|
|
|
|
(when (memq :output (oref new :element-names))
|
|
|
|
|
(oset new :outputs (mapcar 'identity (oref cell :outputs))))
|
|
|
|
|
new))
|
|
|
|
|
|
2012-07-21 14:00:30 +02:00
|
|
|
|
(defmethod ein:cell-convert ((cell ein:headingcell) type)
|
|
|
|
|
(let ((new (call-next-method)))
|
|
|
|
|
(when (ein:headingcell-p new)
|
|
|
|
|
(oset new :level (oref cell :level)))
|
|
|
|
|
new))
|
|
|
|
|
|
2012-05-11 19:00:40 +02:00
|
|
|
|
(defmethod ein:cell-copy ((cell ein:basecell))
|
|
|
|
|
(ein:cell-convert cell (oref cell :cell-type)))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-convert-inplace ((cell ein:basecell) type)
|
|
|
|
|
"Convert CELL to TYPE and redraw corresponding ewoc nodes."
|
|
|
|
|
(let ((new (ein:cell-convert cell type)))
|
|
|
|
|
;; copy element attribute
|
|
|
|
|
(loop for k in (oref new :element-names)
|
|
|
|
|
with old-element = (oref cell :element)
|
2012-05-11 23:52:04 +02:00
|
|
|
|
do (oset new :element
|
|
|
|
|
(plist-put (oref new :element) k
|
|
|
|
|
(plist-get old-element k))))
|
2012-05-11 19:00:40 +02:00
|
|
|
|
;; setting ewoc nodes
|
2012-05-11 23:52:04 +02:00
|
|
|
|
(loop for en in (ein:cell-all-element cell)
|
2012-05-11 19:00:40 +02:00
|
|
|
|
for node = (ewoc-data en)
|
|
|
|
|
do (setf (ein:$node-data node) new))
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
2012-05-11 19:00:40 +02:00
|
|
|
|
;; delete ewoc nodes that is not copied
|
|
|
|
|
(apply
|
|
|
|
|
#'ewoc-delete (oref new :ewoc)
|
|
|
|
|
(apply
|
|
|
|
|
#'append
|
2012-05-11 23:52:04 +02:00
|
|
|
|
(loop for name in (oref cell :element-names)
|
|
|
|
|
unless (memq name (oref new :element-names))
|
|
|
|
|
collect (let ((ens (ein:cell-element-get cell name)))
|
2012-05-11 19:00:40 +02:00
|
|
|
|
(if (listp ens) ens (list ens))))))
|
|
|
|
|
;; draw ewoc node
|
|
|
|
|
(loop with ewoc = (oref new :ewoc)
|
|
|
|
|
for en in (ein:cell-all-element new)
|
|
|
|
|
do (ewoc-invalidate ewoc en)))
|
|
|
|
|
new))
|
|
|
|
|
|
2012-06-02 18:46:02 +02:00
|
|
|
|
(defmethod ein:cell-change-level ((cell ein:headingcell) level)
|
2012-07-20 17:09:43 +02:00
|
|
|
|
(assert (integerp level))
|
2012-06-02 18:46:02 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
|
|
|
|
(oset cell :level level)
|
|
|
|
|
;; draw ewoc node
|
|
|
|
|
(loop with ewoc = (oref cell :ewoc)
|
|
|
|
|
for en in (ein:cell-all-element cell)
|
|
|
|
|
do (ewoc-invalidate ewoc en))))
|
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
|
|
|
|
;;; Getter/setter
|
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(defmethod ein:cell-num-outputs ((cell ein:codecell))
|
|
|
|
|
(length (oref cell :outputs)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(defmethod ein:cell-num-outputs ((cell ein:textcell))
|
|
|
|
|
0)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(defmethod ein:cell-element-get ((cell ein:basecell) prop &rest args)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
"Return ewoc node named PROP in CELL.
|
|
|
|
|
If PROP is `:output' a list of ewoc nodes is returned.
|
2012-05-10 05:03:10 +02:00
|
|
|
|
A specific node can be specified using optional ARGS."
|
|
|
|
|
(if (memq prop (oref cell :element-names))
|
|
|
|
|
(plist-get (oref cell :element) prop)
|
|
|
|
|
(error "PROP %s is not supported." prop)))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-element-get ((cell ein:codecell) prop &optional index)
|
|
|
|
|
(let ((element (oref cell :element)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(if index
|
|
|
|
|
(progn
|
|
|
|
|
(assert (eql prop :output))
|
|
|
|
|
(nth index (plist-get element prop)))
|
|
|
|
|
(case prop
|
|
|
|
|
(:after-input
|
|
|
|
|
(ein:aif (nth 0 (plist-get element :output))
|
|
|
|
|
it
|
|
|
|
|
(plist-get element :footer)))
|
|
|
|
|
(:after-output (plist-get element :footer))
|
|
|
|
|
(:before-input (plist-get element :prompt))
|
|
|
|
|
(:before-output (plist-get element :input))
|
|
|
|
|
(:last-output
|
|
|
|
|
(ein:aif (plist-get element :output)
|
|
|
|
|
(car (last it))
|
|
|
|
|
(plist-get element :input)))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(t (call-next-method))))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(defmethod ein:cell-element-get ((cell ein:textcell) prop)
|
|
|
|
|
(let ((element (oref cell :element)))
|
|
|
|
|
(case prop
|
|
|
|
|
(:after-input (plist-get element :footer))
|
|
|
|
|
(:before-input (plist-get element :prompt))
|
|
|
|
|
(t (call-next-method)))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-11 00:48:22 +02:00
|
|
|
|
(defmethod ein:cell-all-element ((cell ein:basecell))
|
|
|
|
|
(list (ein:cell-element-get cell :prompt)
|
|
|
|
|
(ein:cell-element-get cell :input)
|
|
|
|
|
(ein:cell-element-get cell :footer)))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-all-element ((cell ein:codecell))
|
|
|
|
|
(append (call-next-method)
|
|
|
|
|
(ein:cell-element-get cell :output)))
|
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
|
|
|
|
;; EWOC
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:cell-make-element (make-node num-outputs)
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(let ((buffer-undo-list t)) ; disable undo recording
|
|
|
|
|
(list
|
|
|
|
|
:prompt (funcall make-node 'prompt)
|
|
|
|
|
:input (funcall make-node 'input)
|
|
|
|
|
:output (loop for i from 0 below num-outputs
|
|
|
|
|
collect (funcall make-node 'output i))
|
|
|
|
|
:footer (funcall make-node 'footer))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-enter-last ((cell ein:basecell))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(let* ((ewoc (oref cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; Use `cell' as data for ewoc. Use the whole cell data even
|
|
|
|
|
;; if it is not used, to access it from the notebook buffer.
|
|
|
|
|
;; It is equivalent to `this.element.data("cell", this)' in
|
|
|
|
|
;; IPython.Cell (see cell.js).
|
|
|
|
|
(make-node
|
|
|
|
|
(lambda (&rest path)
|
|
|
|
|
(ewoc-enter-last ewoc (ein:node-new `(cell ,@path) cell))))
|
|
|
|
|
(element (ein:cell-make-element make-node
|
|
|
|
|
(ein:cell-num-outputs cell))))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(oset cell :element element)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
cell))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-enter-first ((cell ein:basecell))
|
2012-05-14 22:12:08 +02:00
|
|
|
|
(let* ((ewoc (oref cell :ewoc))
|
|
|
|
|
(node nil)
|
|
|
|
|
(make-node
|
|
|
|
|
(lambda (&rest path)
|
|
|
|
|
(let ((ewoc-data (ein:node-new `(cell ,@path) cell)))
|
|
|
|
|
(setq node
|
|
|
|
|
(if node
|
|
|
|
|
(ewoc-enter-after ewoc node ewoc-data)
|
|
|
|
|
(ewoc-enter-first ewoc ewoc-data))))))
|
|
|
|
|
(element (ein:cell-make-element make-node
|
|
|
|
|
(ein:cell-num-outputs cell))))
|
|
|
|
|
(oset cell :element element)
|
|
|
|
|
cell))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-insert-below ((base-cell ein:basecell) other-cell)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(let* ((ewoc (oref base-cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(node (ein:cell-element-get base-cell :footer))
|
|
|
|
|
(make-node
|
|
|
|
|
(lambda (&rest path)
|
|
|
|
|
(setq node (ewoc-enter-after
|
|
|
|
|
ewoc node (ein:node-new `(cell ,@path) other-cell)))))
|
|
|
|
|
(element (ein:cell-make-element make-node
|
|
|
|
|
(ein:cell-num-outputs other-cell))))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(oset other-cell :element element)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
other-cell))
|
|
|
|
|
|
|
|
|
|
(defun ein:cell-pp (path data)
|
|
|
|
|
(case (car path)
|
|
|
|
|
(prompt (ein:cell-insert-prompt data))
|
|
|
|
|
(input (ein:cell-insert-input data))
|
|
|
|
|
(output (ein:cell-insert-output (cadr path) data))
|
2012-05-20 20:04:04 +02:00
|
|
|
|
(footer (ein:cell-insert-footer data))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(defmethod ein:cell-insert-prompt ((cell ein:codecell))
|
2012-05-20 18:31:33 +02:00
|
|
|
|
"Insert prompt of the CELL in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-pp'."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; Newline is inserted in `ein:cell-insert-input'.
|
2012-05-08 04:47:15 +02:00
|
|
|
|
(ein:insert-read-only
|
2012-07-29 14:43:10 +02:00
|
|
|
|
(concat
|
|
|
|
|
(format "In [%s]:" (or (ein:oref-safe cell :input-prompt-number) " "))
|
|
|
|
|
(when (oref cell :autoexec) " %s" ein:cell-autoexec-prompt))
|
2012-05-20 23:38:31 +02:00
|
|
|
|
'font-lock-face 'ein:cell-input-prompt))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-insert-prompt ((cell ein:textcell))
|
|
|
|
|
(ein:insert-read-only
|
2012-06-02 12:21:07 +02:00
|
|
|
|
(format "%s:" (oref cell :cell-type))
|
2012-05-20 23:38:31 +02:00
|
|
|
|
'font-lock-face 'ein:cell-input-prompt))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-19 23:45:59 +02:00
|
|
|
|
(defmethod ein:cell-insert-prompt ((cell ein:headingcell))
|
|
|
|
|
(ein:insert-read-only
|
2012-06-02 12:21:07 +02:00
|
|
|
|
(format "h%s:" (oref cell :level))
|
2012-05-20 23:38:31 +02:00
|
|
|
|
'font-lock-face 'ein:cell-input-prompt))
|
2012-05-19 23:45:59 +02:00
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-insert-input ((cell ein:basecell))
|
2012-05-20 18:31:33 +02:00
|
|
|
|
"Insert input of the CELL in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-pp'."
|
2012-05-21 16:28:51 +02:00
|
|
|
|
(let ((start (1+ (point))))
|
|
|
|
|
;; Newlines must allow insertion before/after its position.
|
|
|
|
|
(insert (propertize "\n" 'read-only t 'rear-nonsticky t)
|
2012-07-20 20:51:37 +02:00
|
|
|
|
(or (ein:oref-safe cell :input) "")
|
2012-05-21 16:28:51 +02:00
|
|
|
|
(propertize "\n" 'read-only t))
|
|
|
|
|
;; Highlight background using overlay.
|
|
|
|
|
(let ((ol (make-overlay start (point))))
|
2012-07-20 20:51:37 +02:00
|
|
|
|
(overlay-put ol 'face (ein:cell-get-input-area-face cell))
|
2012-05-21 16:28:51 +02:00
|
|
|
|
;; `evaporate' = `t': Overlay is deleted when the region become empty.
|
|
|
|
|
(overlay-put ol 'evaporate t))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-20 20:51:37 +02:00
|
|
|
|
(defmethod ein:cell-get-input-area-face ((cell ein:basecell))
|
|
|
|
|
"Return the face (symbol) for input area."
|
|
|
|
|
'ein:cell-input-area)
|
2012-07-20 20:38:04 +02:00
|
|
|
|
|
2012-07-20 20:51:37 +02:00
|
|
|
|
(defmethod ein:cell-get-input-area-face ((cell ein:headingcell))
|
|
|
|
|
(intern (format "ein:cell-heading-%d" (oref cell :level))))
|
2012-07-20 20:38:04 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:cell-insert-output (index cell)
|
2012-05-20 18:31:33 +02:00
|
|
|
|
"Insert INDEX-th output of the CELL in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-pp'."
|
2012-07-17 18:48:02 +02:00
|
|
|
|
(if (or (oref cell :collapsed)
|
|
|
|
|
(and ein:cell-max-num-outputs
|
2012-07-28 02:02:49 +02:00
|
|
|
|
(>= index ein:cell-max-num-outputs)))
|
2012-05-16 20:56:51 +02:00
|
|
|
|
(progn
|
2012-07-17 18:48:02 +02:00
|
|
|
|
(when (and (not (oref cell :collapsed))
|
2012-07-28 02:02:49 +02:00
|
|
|
|
(= index ein:cell-max-num-outputs)
|
|
|
|
|
(> (point) (point-at-bol)))
|
2012-07-17 18:48:02 +02:00
|
|
|
|
;; The first output which exceeds `ein:cell-max-num-outputs'.
|
|
|
|
|
(ein:insert-read-only "\n"))
|
2012-07-28 01:52:31 +02:00
|
|
|
|
(ein:insert-read-only "."))
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(let ((out (nth index (oref cell :outputs))))
|
2012-05-20 21:14:42 +02:00
|
|
|
|
;; Handle newline for previous stream output.
|
2012-05-20 19:54:21 +02:00
|
|
|
|
;; In IPython JS, it is handled in `append_stream' because JS
|
|
|
|
|
;; does not need to care about newline (DOM does it for JS).
|
|
|
|
|
;; FIXME: Maybe I should abstract ewoc in some way and get rid
|
|
|
|
|
;; of this.
|
|
|
|
|
(let ((last-out (and (> index 0)
|
|
|
|
|
(nth (1- index) (oref cell :outputs)))))
|
2012-05-20 21:14:42 +02:00
|
|
|
|
;; If previous output is stream type, consider adding newline
|
2012-05-20 21:12:09 +02:00
|
|
|
|
(when (and last-out
|
|
|
|
|
(equal (plist-get last-out :output_type) "stream"))
|
2012-05-20 21:14:42 +02:00
|
|
|
|
;; Check if the last output is from the same stream.
|
|
|
|
|
;; If so, do *NOT* insert newline, otherwise insert newline.
|
2012-05-20 21:12:09 +02:00
|
|
|
|
(unless (and (equal (plist-get out :output_type) "stream")
|
2012-05-20 19:54:21 +02:00
|
|
|
|
(equal (plist-get out :stream)
|
|
|
|
|
(plist-get last-out :stream)))
|
2012-05-20 23:13:00 +02:00
|
|
|
|
(ein:cell-append-stream-text-fontified "\n" last-out))))
|
2012-05-20 19:54:21 +02:00
|
|
|
|
;; Finally insert real data
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(ein:case-equal (plist-get out :output_type)
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(("pyout") (ein:cell-append-pyout cell out))
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(("pyerr") (ein:cell-append-pyerr cell out))
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(("display_data") (ein:cell-append-display-data cell out))
|
2012-05-20 18:22:38 +02:00
|
|
|
|
(("stream") (ein:cell-append-stream cell out))))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 20:04:04 +02:00
|
|
|
|
(defmethod ein:cell-insert-footer ((cell ein:basecell))
|
2012-05-20 18:31:33 +02:00
|
|
|
|
"Insert footer (just a new line) of the CELL in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-pp'."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:insert-read-only "\n"))
|
|
|
|
|
|
2012-05-20 20:04:04 +02:00
|
|
|
|
(defmethod ein:cell-insert-footer ((cell ein:codecell))
|
2012-07-28 01:52:31 +02:00
|
|
|
|
(if (or (oref cell :collapsed)
|
|
|
|
|
(and ein:cell-max-num-outputs
|
|
|
|
|
(> (ein:cell-num-outputs cell) ein:cell-max-num-outputs)))
|
|
|
|
|
;; Add a newline after the last ".".
|
|
|
|
|
(ein:insert-read-only "\n")
|
|
|
|
|
(let ((last-out (car (last (oref cell :outputs)))))
|
|
|
|
|
(when (equal (plist-get last-out :output_type) "stream")
|
|
|
|
|
(ein:cell-append-stream-text-fontified "\n" last-out))))
|
2012-05-20 20:04:04 +02:00
|
|
|
|
(call-next-method))
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 21:06:16 +02:00
|
|
|
|
(defun ein:cell-node-p (node &optional element-name)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(let* ((path (ein:$node-path node))
|
|
|
|
|
(p0 (car path))
|
|
|
|
|
(p1 (cadr path))
|
|
|
|
|
(cell (ein:$node-path node)))
|
2012-05-10 21:06:16 +02:00
|
|
|
|
(and cell (eql p0 'cell) (or (not element-name) (eql p1 element-name)))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 21:06:16 +02:00
|
|
|
|
(defun ein:cell-ewoc-node-p (ewoc-node &optional element-name)
|
|
|
|
|
(ein:cell-node-p (ewoc-data ewoc-node) element-name))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-10 21:08:27 +02:00
|
|
|
|
(defun ein:cell-from-ewoc-node (ewoc-node)
|
|
|
|
|
(ein:aand ewoc-node (ewoc-data it) (ein:$node-data it)))
|
|
|
|
|
|
2012-05-17 15:48:21 +02:00
|
|
|
|
(defmethod ein:cell-input-pos-min ((cell ein:basecell))
|
2012-07-22 16:57:41 +02:00
|
|
|
|
"Return editable minimum point in the input area of the CELL.
|
|
|
|
|
If the input area of the CELL does not exist, return `nil'"
|
2012-07-22 16:50:45 +02:00
|
|
|
|
(let* ((input-node (ein:cell-element-get cell :input)))
|
2012-05-17 15:48:21 +02:00
|
|
|
|
;; 1+ for skipping newline
|
2012-07-22 16:57:41 +02:00
|
|
|
|
(when input-node (1+ (ewoc-location input-node)))))
|
2012-05-17 15:48:21 +02:00
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-input-pos-max ((cell ein:basecell))
|
2012-07-22 16:57:41 +02:00
|
|
|
|
"Return editable maximum point in the input area of the CELL.
|
|
|
|
|
If the input area of the CELL does not exist, return `nil'"
|
2012-05-17 15:48:21 +02:00
|
|
|
|
(let* ((ewoc (oref cell :ewoc))
|
|
|
|
|
(input-node (ein:cell-element-get cell :input)))
|
|
|
|
|
;; 1- for skipping newline
|
2012-07-22 16:57:41 +02:00
|
|
|
|
(when input-node (1- (ewoc-location (ewoc-next ewoc input-node))))))
|
2012-05-17 15:48:21 +02:00
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-get-text ((cell ein:basecell))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
"Grab text in the input area of the cell at point."
|
2012-05-17 15:48:21 +02:00
|
|
|
|
(let* ((beg (ein:cell-input-pos-min cell))
|
|
|
|
|
(end (ein:cell-input-pos-max cell)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(buffer-substring beg end)))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-set-text ((cell ein:basecell) text)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(let* ((input-node (ein:cell-element-get cell :input))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ewoc (oref cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; 1+/1- is for skipping newline
|
|
|
|
|
(beg (1+ (ewoc-location input-node)))
|
|
|
|
|
(end (1- (ewoc-location (ewoc-next ewoc input-node)))))
|
|
|
|
|
(save-excursion
|
2012-05-10 05:03:10 +02:00
|
|
|
|
;; probably it is better to set :input and update via ewoc?
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(goto-char beg)
|
|
|
|
|
(delete-region beg end)
|
|
|
|
|
(insert text))))
|
|
|
|
|
|
2012-05-14 23:47:10 +02:00
|
|
|
|
(defmethod ein:cell-save-text ((cell ein:basecell))
|
|
|
|
|
(oset cell :input (ein:cell-get-text cell)))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-deactivate ((cell ein:basecell))
|
|
|
|
|
(oset cell :element nil)
|
|
|
|
|
cell)
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-active-p ((cell ein:basecell))
|
|
|
|
|
(oref cell :element))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-running-set ((cell ein:codecell) running)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; FIXME: change the appearance of the cell
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(oset cell :running running))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-16 21:18:25 +02:00
|
|
|
|
(defmethod ein:cell-set-collapsed ((cell ein:codecell) collapsed)
|
|
|
|
|
"Set `:collapsed' slot of CELL and invalidate output ewoc nodes."
|
|
|
|
|
(oset cell :collapsed collapsed)
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(apply #'ewoc-invalidate
|
|
|
|
|
(oref cell :ewoc)
|
|
|
|
|
(ein:cell-element-get cell :output)))
|
|
|
|
|
|
2012-05-16 21:18:25 +02:00
|
|
|
|
(defmethod ein:cell-toggle-output ((cell ein:codecell))
|
|
|
|
|
"Toggle `:collapsed' slot of CELL and invalidate output ewoc nodes."
|
|
|
|
|
(ein:cell-set-collapsed cell (not (oref cell :collapsed))))
|
|
|
|
|
|
2012-07-29 14:43:10 +02:00
|
|
|
|
(defmethod ein:cell-invalidate-prompt ((cell ein:codecell))
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ewoc-invalidate (oref cell :ewoc)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:cell-element-get cell :prompt))))
|
|
|
|
|
|
2012-07-29 14:43:10 +02:00
|
|
|
|
(defmethod ein:cell-set-input-prompt ((cell ein:codecell) &optional number)
|
|
|
|
|
(oset cell :input-prompt-number number)
|
|
|
|
|
(ein:cell-invalidate-prompt cell))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-set-autoexec ((cell ein:codecell) bool)
|
2012-07-29 16:15:09 +02:00
|
|
|
|
(oset cell :autoexec bool)
|
|
|
|
|
(ein:cell-invalidate-prompt cell))
|
2012-07-29 14:43:10 +02:00
|
|
|
|
|
2012-07-29 14:58:56 +02:00
|
|
|
|
(defmethod ein:cell-autoexec-p ((cell ein:basecell))
|
|
|
|
|
nil)
|
|
|
|
|
|
2012-07-29 14:43:10 +02:00
|
|
|
|
(defmethod ein:cell-autoexec-p ((cell ein:codecell))
|
|
|
|
|
(oref cell :autoexec))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-toggle-autoexec ((cell ein:codecell))
|
2012-07-29 16:15:09 +02:00
|
|
|
|
(ein:cell-set-autoexec cell (not (ein:cell-autoexec-p cell))))
|
2012-07-29 14:43:10 +02:00
|
|
|
|
|
2012-06-21 16:17:14 +02:00
|
|
|
|
(declare-function pos-tip-show "pos-tip")
|
2012-06-21 16:22:46 +02:00
|
|
|
|
(declare-function popup-tip "popup")
|
2012-06-21 16:17:14 +02:00
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(defun ein:cell-finish-tooltip (cell content)
|
2012-05-27 05:34:54 +02:00
|
|
|
|
;; See: Tooltip.prototype._show (tooltip.js)
|
2012-07-08 13:45:30 +02:00
|
|
|
|
(let ((tooltip (ein:kernel-construct-help-string content))
|
|
|
|
|
(defstring (ein:kernel-construct-defstring content))
|
|
|
|
|
(name (plist-get content :name)))
|
2012-05-27 05:34:54 +02:00
|
|
|
|
(if tooltip
|
|
|
|
|
(cond
|
2012-06-21 16:17:14 +02:00
|
|
|
|
((and window-system (featurep 'pos-tip))
|
|
|
|
|
(pos-tip-show tooltip 'ein:pos-tip-face nil nil 0))
|
2012-06-21 16:22:46 +02:00
|
|
|
|
((featurep 'popup)
|
|
|
|
|
(popup-tip tooltip))
|
2012-05-27 05:34:54 +02:00
|
|
|
|
(t (when (stringp defstring)
|
|
|
|
|
(message (ein:trim (ansi-color-apply defstring))))))
|
|
|
|
|
(ein:log 'info "no info for %s" name))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-21 14:32:11 +02:00
|
|
|
|
(defmethod ein:cell-goto ((cell ein:basecell) &optional relpos)
|
|
|
|
|
"Go to the input area of the given CELL.
|
|
|
|
|
RELPOS is the position relative to the input area. Default is 0."
|
|
|
|
|
(unless relpos (setq relpos 0))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ewoc-goto-node (oref cell :ewoc) (ein:cell-element-get cell :input))
|
2012-07-21 14:32:11 +02:00
|
|
|
|
;; `1+' to skip the newline
|
|
|
|
|
(forward-char (1+ relpos)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-21 14:31:42 +02:00
|
|
|
|
(defmethod ein:cell-relative-point ((cell ein:basecell) &optional pos)
|
|
|
|
|
"Return the point relative to the input area of CELL.
|
|
|
|
|
If the position POS is not given, current point is considered."
|
|
|
|
|
(unless pos (setq pos (point)))
|
|
|
|
|
(- pos (1+ (ewoc-location (ein:cell-element-get cell :input)))))
|
|
|
|
|
|
2012-05-19 13:10:44 +02:00
|
|
|
|
(defmethod ein:cell-location ((cell ein:basecell) &optional elm end)
|
|
|
|
|
"Return the starting location of CELL.
|
2012-06-16 21:04:47 +02:00
|
|
|
|
ELM is a name (keyword) of element that `ein:cell-element-get'
|
|
|
|
|
understands. Note that you can't use `:output' since it returns
|
|
|
|
|
a list. Use `:after-input' instead.
|
2012-05-19 13:10:44 +02:00
|
|
|
|
If END is non-`nil', return the location of next element."
|
|
|
|
|
(unless elm (setq elm :prompt))
|
|
|
|
|
(let ((element (oref cell :element)))
|
|
|
|
|
(when end
|
|
|
|
|
(setq elm (case elm
|
|
|
|
|
(:prompt :input)
|
|
|
|
|
(:input :after-input)
|
|
|
|
|
(:output :after-output)))
|
|
|
|
|
(unless elm
|
|
|
|
|
(setq cell (ein:cell-next cell))
|
|
|
|
|
(setq elm :prompt)))
|
|
|
|
|
(if cell
|
|
|
|
|
(ewoc-location (ein:cell-element-get cell elm))
|
|
|
|
|
(assert end)
|
|
|
|
|
(point-max))))
|
|
|
|
|
|
2012-05-11 18:39:40 +02:00
|
|
|
|
|
|
|
|
|
;; Data manipulation
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-clear-output ((cell ein:codecell) stdout stderr other)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; codecell.js in IPytohn implements it using timeout and callback.
|
|
|
|
|
;; As it is unclear why timeout is needed, just clear output
|
|
|
|
|
;; instantaneously for now.
|
|
|
|
|
(ein:log 'debug "cell-clear-output stdout=%s stderr=%s other=%s"
|
|
|
|
|
stdout stderr other)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(let ((ewoc (oref cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(output-nodes (ein:cell-element-get cell :output)))
|
|
|
|
|
(if (and stdout stderr other)
|
|
|
|
|
(progn
|
|
|
|
|
;; clear all
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(apply #'ewoc-delete ewoc output-nodes))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(plist-put (oref cell :element) :output nil)
|
2012-05-10 13:20:07 +02:00
|
|
|
|
(oset cell :outputs nil))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(let* ((ewoc-node-list
|
|
|
|
|
(append
|
|
|
|
|
(when stdout (ein:node-filter output-nodes :is 'output-stdout))
|
|
|
|
|
(when stderr (ein:node-filter output-nodes :is 'output-stderr))
|
|
|
|
|
(when stdout (ein:node-filter output-nodes
|
|
|
|
|
:is 'output-subarea
|
|
|
|
|
:not 'output-stderr
|
|
|
|
|
:not 'output-stdout))))
|
|
|
|
|
(indices
|
|
|
|
|
(mapcar (lambda (n) (last (ein:$node-path (ewoc-data n))))
|
|
|
|
|
ewoc-node-list)))
|
|
|
|
|
;; remove from buffer
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(let ((inhibit-read-only t)
|
|
|
|
|
(buffer-undo-list t)) ; disable undo recording
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(apply #'ewoc-delete ewoc ewoc-node-list))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
;; remove from `:element'
|
|
|
|
|
(let* ((element (oref cell :element))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(old-output (plist-get element :output))
|
|
|
|
|
(new-ouptut (ein:remove-by-index old-output indices)))
|
|
|
|
|
(plist-put element :output new-ouptut))
|
|
|
|
|
;; remove cleared outputs from internal data
|
2012-05-10 13:20:07 +02:00
|
|
|
|
(oset cell :outputs
|
2012-05-23 20:20:02 +02:00
|
|
|
|
(ein:remove-by-index (oref cell :outputs) indices))))
|
|
|
|
|
;; Footer may have extra (possibly colored) newline due to the
|
|
|
|
|
;; last output type. So invalidate it here.
|
|
|
|
|
;; See `ein:cell-insert-footer' (for codecell).
|
|
|
|
|
(ewoc-invalidate ewoc (ein:cell-element-get cell :footer))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:cell-output-json-to-class (json)
|
|
|
|
|
(ein:case-equal (plist-get json :output_type)
|
|
|
|
|
(("pyout")
|
2012-05-20 23:27:31 +02:00
|
|
|
|
'(output-subarea))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(("pyerr")
|
2012-05-20 23:27:31 +02:00
|
|
|
|
'(output-subarea))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(("display_data")
|
2012-05-20 23:27:31 +02:00
|
|
|
|
'(output-subarea))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(("stream")
|
2012-05-20 23:27:31 +02:00
|
|
|
|
(list 'output-stream 'output-subarea
|
|
|
|
|
(intern (format "output-%s" (plist-get json :stream)))))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-append-output ((cell ein:codecell) json dynamic)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; (ein:cell-expand cell)
|
|
|
|
|
;; (ein:flush-clear-timeout)
|
2012-05-10 13:20:07 +02:00
|
|
|
|
(oset cell :outputs
|
|
|
|
|
(append (oref cell :outputs) (list json)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; enter last output element
|
|
|
|
|
(let* ((inhibit-read-only t)
|
2012-05-13 18:59:03 +02:00
|
|
|
|
(buffer-undo-list t) ; disable undo recording
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ewoc (oref cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(index (1- (ein:cell-num-outputs cell)))
|
|
|
|
|
(path `(cell output ,index))
|
|
|
|
|
(class (ein:cell-output-json-to-class json))
|
|
|
|
|
(data (ein:node-new path cell class))
|
|
|
|
|
(last-node (ein:cell-element-get cell :last-output))
|
|
|
|
|
(ewoc-node (ewoc-enter-after ewoc last-node data))
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(element (oref cell :element)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(plist-put element :output
|
2012-05-20 20:04:04 +02:00
|
|
|
|
(append (plist-get element :output) (list ewoc-node)))
|
|
|
|
|
(ewoc-invalidate ewoc (ein:cell-element-get cell :footer))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(defmethod ein:cell-append-pyout ((cell ein:codecell) json)
|
2012-05-20 18:36:54 +02:00
|
|
|
|
"Insert pyout type output in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-insert-output'."
|
2012-05-20 23:38:31 +02:00
|
|
|
|
(ein:insert-read-only (format "Out [%s]:"
|
|
|
|
|
(or (plist-get json :prompt_number) " "))
|
|
|
|
|
'font-lock-face 'ein:cell-output-prompt)
|
|
|
|
|
(ein:insert-read-only "\n")
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(ein:cell-append-mime-type json (oref cell :dynamic))
|
2012-05-20 18:22:38 +02:00
|
|
|
|
(ein:insert-read-only "\n"))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-append-pyerr ((cell ein:codecell) json)
|
2012-05-20 18:36:54 +02:00
|
|
|
|
"Insert pyerr type output in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-insert-output'."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(mapc (lambda (tb)
|
|
|
|
|
(ein:cell-append-text tb)
|
|
|
|
|
(ein:cell-append-text "\n"))
|
2012-06-11 21:20:15 +02:00
|
|
|
|
(let ((tb (plist-get json :traceback))
|
|
|
|
|
(level ein:cell-traceback-level))
|
|
|
|
|
(if (and level (> (- (length tb) 2) level))
|
2012-06-11 19:11:33 +02:00
|
|
|
|
(cons "\nTruncated Traceback (Use C-c C-x to view full TB):"
|
2012-06-11 21:20:15 +02:00
|
|
|
|
(last tb (1+ level)))
|
2012-06-11 19:11:33 +02:00
|
|
|
|
tb)))
|
2012-05-20 18:22:38 +02:00
|
|
|
|
(ein:insert-read-only "\n"))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-07-10 07:51:41 +02:00
|
|
|
|
(ein:deflocal ein:cell-append-stream-last-cell nil
|
|
|
|
|
"The last cell in which `ein:cell-append-stream' is used.")
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-append-stream ((cell ein:codecell) json)
|
2012-05-20 18:36:54 +02:00
|
|
|
|
"Insert stream type output in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-insert-output'."
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(unless (plist-get json :stream)
|
|
|
|
|
(plist-put json :stream "stdout"))
|
2012-07-10 07:51:41 +02:00
|
|
|
|
(unless (eq cell ein:cell-append-stream-last-cell)
|
|
|
|
|
;; Avoid applying unclosed ANSI escape code in the cell. Note
|
|
|
|
|
;; that I don't need to distinguish stdout/stderr because it looks
|
|
|
|
|
;; like normal terminal does not.
|
|
|
|
|
(setq ansi-color-context nil))
|
2012-07-10 02:47:47 +02:00
|
|
|
|
(let ((start (point)))
|
|
|
|
|
(ein:cell-append-stream-text-fontified (plist-get json :text) json)
|
|
|
|
|
(comint-carriage-motion start (point)))
|
2012-05-20 19:54:21 +02:00
|
|
|
|
;; NOTE: newlines for stream is handled in `ein:cell-insert-output'.
|
|
|
|
|
;; So do not insert newline here.
|
2012-07-10 07:51:41 +02:00
|
|
|
|
(setq ein:cell-append-stream-last-cell cell))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 23:13:00 +02:00
|
|
|
|
(defun ein:cell-append-stream-text-fontified (text json)
|
|
|
|
|
"Insert TEXT with font properties defined by JSON data."
|
|
|
|
|
(if (equal (plist-get json :stream) "stderr")
|
|
|
|
|
(ein:cell-append-text text 'font-lock-face 'ein:cell-output-stderr)
|
|
|
|
|
(ein:cell-append-text text)))
|
|
|
|
|
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(defmethod ein:cell-append-display-data ((cell ein:codecell) json)
|
2012-05-20 18:36:54 +02:00
|
|
|
|
"Insert display-data type output in the buffer.
|
|
|
|
|
Called from ewoc pretty printer via `ein:cell-insert-output'."
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(ein:cell-append-mime-type json (oref cell :dynamic))
|
2012-05-20 18:22:38 +02:00
|
|
|
|
(ein:insert-read-only "\n"))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
|
|
(defun ein:cell-append-mime-type (json dynamic)
|
|
|
|
|
(loop
|
2012-07-14 15:17:24 +02:00
|
|
|
|
for key in '(emacs-lisp svg png jpeg text latex html javascript)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
for type = (intern (format ":%s" key)) ; something like `:text'
|
|
|
|
|
for value = (plist-get json type) ; FIXME: optimize
|
|
|
|
|
when (plist-member json type)
|
2012-05-08 05:03:55 +02:00
|
|
|
|
return
|
|
|
|
|
(case key
|
2012-05-20 05:18:25 +02:00
|
|
|
|
;; NOTE: Normally `javascript' and `html' will not be inserted as
|
|
|
|
|
;; they come out after `text'. Maybe it is better to inform user
|
|
|
|
|
;; when one of them is inserted.
|
2012-05-08 05:03:55 +02:00
|
|
|
|
(javascript
|
|
|
|
|
(when dynamic
|
|
|
|
|
(ein:log 'info (concat "ein:cell-append-mime-type does not support "
|
2012-05-20 05:18:25 +02:00
|
|
|
|
"dynamic javascript. got: %s") value))
|
|
|
|
|
(ein:insert-read-only (plist-get json type)))
|
2012-05-21 01:46:12 +02:00
|
|
|
|
(emacs-lisp
|
2012-05-22 00:04:24 +02:00
|
|
|
|
(when dynamic
|
2012-05-23 03:19:22 +02:00
|
|
|
|
(ein:cell-safe-read-eval-insert (plist-get json type))))
|
2012-05-08 05:03:55 +02:00
|
|
|
|
((html latex text)
|
|
|
|
|
(ein:insert-read-only (plist-get json type)))
|
|
|
|
|
(svg
|
|
|
|
|
(insert-image (create-image value key t)))
|
|
|
|
|
((png jpeg)
|
|
|
|
|
(insert-image (create-image (base64-decode-string value) key t))))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-20 22:19:00 +02:00
|
|
|
|
(defun ein:cell-append-text (data &rest properties)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
;; FIXME: implement HTML special escaping
|
|
|
|
|
;; escape ANSI & HTML specials in plaintext:
|
2012-05-20 22:19:00 +02:00
|
|
|
|
(apply #'ein:insert-read-only (ansi-color-apply data) properties))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
2012-05-23 03:19:22 +02:00
|
|
|
|
(defun ein:cell-safe-read-eval-insert (text)
|
|
|
|
|
(ein:insert-read-only
|
|
|
|
|
(condition-case err
|
|
|
|
|
(save-excursion
|
|
|
|
|
;; given code can be `pop-to-buffer' or something.
|
|
|
|
|
(format "%S" (eval (read text))))
|
|
|
|
|
(error
|
|
|
|
|
(ein:log 'warn "Got an error while executing: '%s'"
|
|
|
|
|
text)
|
|
|
|
|
(format "Error: %S" err)))))
|
|
|
|
|
|
2012-05-25 00:23:09 +02:00
|
|
|
|
(defmethod ein:cell-to-json ((cell ein:codecell) &optional discard-output)
|
2012-05-08 08:26:56 +02:00
|
|
|
|
"Return json-ready alist."
|
|
|
|
|
`((input . ,(ein:cell-get-text cell))
|
|
|
|
|
(cell_type . "code")
|
2012-05-10 22:05:54 +02:00
|
|
|
|
,@(ein:aif (ein:oref-safe cell :input-prompt-number)
|
2012-05-08 08:26:56 +02:00
|
|
|
|
`((prompt_number . ,it)))
|
2012-05-25 00:23:09 +02:00
|
|
|
|
(outputs . ,(if discard-output [] (apply #'vector (oref cell :outputs))))
|
2012-05-08 08:26:56 +02:00
|
|
|
|
(language . "python")
|
2012-05-16 20:44:47 +02:00
|
|
|
|
(collapsed . ,(if (oref cell :collapsed) t json-false))))
|
2012-05-08 05:53:18 +02:00
|
|
|
|
|
2012-05-25 05:22:14 +02:00
|
|
|
|
(defmethod ein:cell-to-json ((cell ein:textcell) &optional discard-output)
|
2012-05-10 05:03:10 +02:00
|
|
|
|
`((cell_type . ,(oref cell :cell-type))
|
2012-05-10 02:20:21 +02:00
|
|
|
|
(source . ,(ein:cell-get-text cell))))
|
|
|
|
|
|
2012-05-25 05:22:14 +02:00
|
|
|
|
(defmethod ein:cell-to-json ((cell ein:headingcell) &optional discard-output)
|
2012-05-19 23:45:59 +02:00
|
|
|
|
(let ((json (call-next-method)))
|
|
|
|
|
(append json `((level . ,(oref cell :level))))))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-next ((cell ein:basecell))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
"Return next cell of the given CELL or nil if CELL is the last one."
|
2012-05-10 05:03:10 +02:00
|
|
|
|
(ein:aif (ewoc-next (oref cell :ewoc)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(ein:cell-element-get cell :footer))
|
|
|
|
|
(let ((cell (ein:$node-data (ewoc-data it))))
|
2012-05-10 14:16:48 +02:00
|
|
|
|
(when (ein:basecell-child-p cell)
|
2012-05-07 14:41:15 +02:00
|
|
|
|
cell))))
|
|
|
|
|
|
2012-05-20 00:21:07 +02:00
|
|
|
|
(defmethod ein:cell-prev ((cell ein:basecell))
|
2012-05-11 16:38:29 +02:00
|
|
|
|
"Return previous cell of the given CELL or nil if CELL is the first one."
|
|
|
|
|
(ein:aif (ewoc-prev (oref cell :ewoc)
|
|
|
|
|
(ein:cell-element-get cell :prompt))
|
|
|
|
|
(let ((cell (ein:$node-data (ewoc-data it))))
|
|
|
|
|
(when (ein:basecell-child-p cell)
|
|
|
|
|
cell))))
|
|
|
|
|
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
|
|
|
|
;;; Kernel related calls.
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-set-kernel ((cell ein:codecell) kernel)
|
|
|
|
|
(oset cell :kernel kernel))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-execute ((cell ein:codecell))
|
2012-05-24 13:17:42 +02:00
|
|
|
|
(ein:cell-execute-internal cell
|
|
|
|
|
(oref cell :kernel)
|
|
|
|
|
(ein:cell-get-text cell)
|
|
|
|
|
:silent nil))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-execute-internal ((cell ein:codecell)
|
|
|
|
|
kernel code &rest args)
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(ein:cell-clear-output cell t t t)
|
2012-05-23 22:52:34 +02:00
|
|
|
|
(ein:cell-set-input-prompt cell "*")
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(ein:cell-running-set cell t)
|
|
|
|
|
(oset cell :dynamic t)
|
2012-06-16 18:45:01 +02:00
|
|
|
|
(apply #'ein:kernel-execute kernel code (ein:cell-make-callbacks cell) args))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-make-callbacks ((cell ein:codecell))
|
|
|
|
|
(list
|
|
|
|
|
:execute_reply (cons #'ein:cell--handle-execute-reply cell)
|
|
|
|
|
:output (cons #'ein:cell--handle-output cell)
|
|
|
|
|
:clear_output (cons #'ein:cell--handle-clear-output cell)
|
|
|
|
|
:set_next_input (cons #'ein:cell--handle-set-next-input cell)))
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
|
|
|
|
(defmethod ein:cell--handle-execute-reply ((cell ein:codecell) content)
|
2012-05-23 20:10:52 +02:00
|
|
|
|
(ein:cell-set-input-prompt cell (plist-get content :execution_count))
|
2012-05-23 22:52:34 +02:00
|
|
|
|
(ein:cell-running-set cell nil)
|
2012-06-16 23:33:58 +02:00
|
|
|
|
(let ((events (oref cell :events)))
|
|
|
|
|
(ein:events-trigger events 'set_dirty.Notebook '(:value t))
|
|
|
|
|
(ein:events-trigger events 'maybe_reset_undo.Notebook)))
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
2012-06-04 16:18:17 +02:00
|
|
|
|
(defmethod ein:cell--handle-set-next-input ((cell ein:codecell) text)
|
2012-06-16 23:33:58 +02:00
|
|
|
|
(let ((events (oref cell :events)))
|
|
|
|
|
(ein:events-trigger events 'set_next_input.Notebook
|
|
|
|
|
(list :cell cell :text text))
|
|
|
|
|
(ein:events-trigger events 'maybe_reset_undo.Notebook)))
|
2012-06-04 16:18:17 +02:00
|
|
|
|
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Output area
|
|
|
|
|
|
|
|
|
|
;; These function should go to ein-output-area.el. But as cell and
|
|
|
|
|
;; EWOC is connected in complicated way, I will leave them in
|
|
|
|
|
;; ein-cell.el.
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell--handle-output ((cell ein:codecell) msg-type content)
|
|
|
|
|
(let* ((json (list :output_type msg-type)))
|
2012-05-23 01:31:56 +02:00
|
|
|
|
(ein:case-equal msg-type
|
|
|
|
|
(("stream")
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(plist-put json :text (plist-get content :data))
|
|
|
|
|
(plist-put json :stream (plist-get content :name)))
|
2012-05-23 01:31:56 +02:00
|
|
|
|
(("display_data" "pyout")
|
|
|
|
|
(when (equal msg-type "pyout")
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(plist-put json :prompt_number (plist-get content :execution_count)))
|
|
|
|
|
(setq json (ein:output-area-convert-mime-types
|
|
|
|
|
json (plist-get content :data))))
|
2012-05-23 01:31:56 +02:00
|
|
|
|
(("pyerr")
|
2012-05-22 21:31:23 +02:00
|
|
|
|
(plist-put json :ename (plist-get content :ename))
|
|
|
|
|
(plist-put json :evalue (plist-get content :evalue))
|
|
|
|
|
(plist-put json :traceback (plist-get content :traceback))))
|
|
|
|
|
(ein:cell-append-output cell json t)
|
|
|
|
|
;; (oset cell :dirty t)
|
2012-06-16 23:33:58 +02:00
|
|
|
|
(ein:events-trigger (oref cell :events) 'maybe_reset_undo.Notebook)))
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defun ein:output-area-convert-mime-types (json data)
|
|
|
|
|
(loop for (prop . mime) in '((:text . :text/plain)
|
|
|
|
|
(:html . :text/html)
|
|
|
|
|
(:svg . :image/svg+xml)
|
|
|
|
|
(:png . :image/png)
|
|
|
|
|
(:jpeg . :image/jpeg)
|
|
|
|
|
(:latex . :text/latex)
|
|
|
|
|
(:json . :application/json)
|
|
|
|
|
(:javascript . :application/javascript)
|
|
|
|
|
(:emacs-lisp . :application/emacs-lisp))
|
|
|
|
|
when (plist-member data mime)
|
|
|
|
|
do (plist-put json prop (plist-get data mime)))
|
|
|
|
|
json)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell--handle-clear-output ((cell ein:codecell) content)
|
|
|
|
|
(ein:cell-clear-output cell
|
|
|
|
|
(plist-get content :stdout)
|
|
|
|
|
(plist-get content :stderr)
|
2012-06-16 23:33:58 +02:00
|
|
|
|
(plist-get content :other))
|
|
|
|
|
(ein:events-trigger (oref cell :events) 'maybe_reset_undo.Notebook))
|
2012-05-22 21:31:23 +02:00
|
|
|
|
|
2012-06-10 04:04:31 +02:00
|
|
|
|
|
|
|
|
|
;;; Misc.
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-has-image-ouput-p ((cell ein:codecell))
|
|
|
|
|
"Return `t' if given cell has image output, `nil' otherwise."
|
|
|
|
|
(loop for out in (oref cell :outputs)
|
|
|
|
|
when (or (plist-member out :svg)
|
|
|
|
|
(plist-member out :png)
|
|
|
|
|
(plist-member out :jpeg))
|
|
|
|
|
return t))
|
|
|
|
|
|
|
|
|
|
(defmethod ein:cell-has-image-ouput-p ((cell ein:textcell))
|
|
|
|
|
nil)
|
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
|
(provide 'ein-cell)
|
|
|
|
|
|
|
|
|
|
;;; ein-cell.el ends here
|