2012-05-07 14:41:15 +02:00
|
|
|
;;; ein-cell.el --- Cell module
|
|
|
|
|
|
|
|
;; Copyright (C) 2012- Takafumi Arakaki
|
|
|
|
|
|
|
|
;; Author: Takafumi Arakaki
|
|
|
|
|
|
|
|
;; 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:
|
|
|
|
|
|
|
|
;; 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)
|
|
|
|
|
|
|
|
(require 'ein-log)
|
|
|
|
(require 'ein-utils)
|
|
|
|
(require 'ein-node)
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
;; (data :initarg :data
|
|
|
|
;; :documentation "default JSON data - FIXME: remove this!")
|
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 04:24:49 +02:00
|
|
|
(input :initarg :input :initform "" :type string
|
|
|
|
:documentation "Place to hold data until it is rendered via `ewoc'.")
|
|
|
|
(outputs :initarg :outputs :initform nil :type list)
|
|
|
|
(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-10 05:03:10 +02:00
|
|
|
(element-names :initform (:prompt :input :output :footer))
|
2012-05-10 04:24:49 +02:00
|
|
|
(input-prompt-number :initarg :input-prompt-number :type integer)))
|
|
|
|
|
|
|
|
(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")))
|
|
|
|
|
|
|
|
(defclass ein:rstcell (ein:textcell)
|
|
|
|
((cell-type :initarg :cell-type :initform "rst")))
|
|
|
|
|
|
|
|
(defun ein:cell-class-from-type (type)
|
|
|
|
(ein:case-equal type
|
|
|
|
(("code") 'ein:codecell)
|
|
|
|
(("text") 'ein:textcell)
|
|
|
|
(("html") 'ein:htmlcell)
|
|
|
|
(("markdown") 'ein:markdowncell)
|
|
|
|
(("rst") 'ein:rstcell)))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
2012-05-10 05:20:52 +02:00
|
|
|
(defun ein:cell-from-type (type &rest args)
|
|
|
|
(apply (ein:cell-class-from-type type) args))
|
|
|
|
|
|
|
|
(defun ein:cell-from-json (data &rest args)
|
|
|
|
(ein:cell-init (ein:cell-from-type (plist-get data :cell_type) args) data))
|
2012-05-10 12:45:38 +02:00
|
|
|
|
|
|
|
(defmacro ein:oset-if-unbound (obj slot value)
|
|
|
|
`(unless (slot-boundp ,obj ,slot)
|
|
|
|
(oset ,obj ,slot ,value)))
|
|
|
|
|
|
|
|
(defmethod ein:cell-init ((cell ein:codecell) data)
|
|
|
|
(ein:oset-if-unbound cell :outputs (plist-get data :outputs))
|
|
|
|
(ein:oset-if-unbound cell :input (plist-get data :input))
|
|
|
|
(ein:oset-if-unbound cell :input-prompt-number
|
|
|
|
(plist-get data :prompt_number))
|
|
|
|
cell)
|
|
|
|
|
|
|
|
(defmethod ein:cell-init ((cell ein:textcell) data)
|
|
|
|
(ein:aif (plist-get data :source)
|
|
|
|
(oset cell :input it))
|
|
|
|
cell)
|
|
|
|
|
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
|
|
|
|
|
|
|
(defun ein:cell-make-element (make-node num-outputs)
|
|
|
|
(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)))
|
|
|
|
|
|
|
|
(defun ein:cell-enter-last (cell)
|
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))
|
|
|
|
|
|
|
|
(defun ein:cell-insert-below (base-cell 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))
|
|
|
|
(footer (ein:cell-insert-footer))))
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
(defmethod ein:cell-insert-prompt ((cell ein:codecell))
|
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-05-10 05:03:10 +02:00
|
|
|
(format "In [%s]:" (or (oref cell :input-prompt-number) " "))))
|
|
|
|
|
|
|
|
(defmethod ein:cell-insert-prompt ((cell ein:textcell))
|
|
|
|
(ein:insert-read-only
|
|
|
|
(format "In [%s]:" (oref cell :cell_type))))
|
2012-05-07 14:41:15 +02:00
|
|
|
|
|
|
|
(defun ein:cell-insert-input (cell)
|
|
|
|
;; Newlines must allow insertion before/after its position.
|
|
|
|
(insert (propertize "\n" 'read-only t 'rear-nonsticky t)
|
2012-05-10 05:03:10 +02:00
|
|
|
(or (oref cell :input) "")
|
2012-05-07 14:41:15 +02:00
|
|
|
(propertize "\n" 'read-only t)))
|
|
|
|
|
|
|
|
(defvar ein:cell-output-dynamic nil)
|
|
|
|
|
|
|
|
(defun ein:cell-insert-output (index cell)
|
2012-05-10 05:03:10 +02:00
|
|
|
(let ((out (nth index (oref :cell outputs)))
|
2012-05-07 14:41:15 +02:00
|
|
|
(dynamic ein:cell-output-dynamic))
|
|
|
|
(ein:case-equal (plist-get out :output_type)
|
|
|
|
(("pyout") (ein:cell-append-pyout cell out dynamic))
|
|
|
|
(("pyerr") (ein:cell-append-pyerr cell out))
|
|
|
|
(("display_data") (ein:cell-append-display-data cell out dynamic))
|
|
|
|
(("stream") (ein:cell-append-stream cell out))))
|
|
|
|
(ein:insert-read-only "\n"))
|
|
|
|
|
|
|
|
(defun ein:cell-insert-footer ()
|
|
|
|
(ein:insert-read-only "\n"))
|
|
|
|
|
|
|
|
|
|
|
|
(defun ein:cell-node-p (node &optional cell-type)
|
|
|
|
(let* ((path (ein:$node-path node))
|
|
|
|
(p0 (car path))
|
|
|
|
(p1 (cadr path))
|
|
|
|
(cell (ein:$node-path node)))
|
|
|
|
(and cell (eql p0 'cell) (or (not cell-type) (eql p1 cell-type)))))
|
|
|
|
|
|
|
|
(defun ein:cell-ewoc-node-p (ewoc-node &optional cell-type)
|
|
|
|
(ein:cell-node-p (ewoc-data ewoc-node) cell-type))
|
|
|
|
|
|
|
|
(defun ein:cell-get-text (cell)
|
|
|
|
"Grab text in the input area of the cell at point."
|
2012-05-10 05:03:10 +02:00
|
|
|
(let* ((ewoc (oref cell :ewoc))
|
2012-05-07 14:41:15 +02:00
|
|
|
(input-node (ein:cell-element-get cell :input))
|
|
|
|
;; 1+/1- is for skipping newline
|
|
|
|
(beg (1+ (ewoc-location input-node)))
|
|
|
|
(end (1- (ewoc-location (ewoc-next ewoc input-node)))))
|
|
|
|
(buffer-substring beg end)))
|
|
|
|
|
|
|
|
(defun ein:cell-set-text (cell text)
|
|
|
|
(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))))
|
|
|
|
|
|
|
|
(defun ein:cell-running-set (cell running)
|
|
|
|
;; 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
|
|
|
|
|
|
|
(defun ein:cell-set-input-prompt (cell &optional number)
|
2012-05-10 05:03:10 +02:00
|
|
|
(oset cell :input-prompt-number number)
|
2012-05-07 14:41:15 +02:00
|
|
|
(let ((inhibit-read-only t))
|
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))))
|
|
|
|
|
|
|
|
(defun ein:cell-finish-completing (cell matched-text matches)
|
|
|
|
;; FIXME: implement!
|
|
|
|
(ein:log 'info "`ein:cell-finish-completing' is not implemented!"))
|
|
|
|
|
|
|
|
(defun ein:cell-finish-tooltip (cell content)
|
|
|
|
;; FIXME: implement!
|
|
|
|
(ein:log 'info "`ein:cell-finish-tooltip' is not implemented!"))
|
|
|
|
|
|
|
|
(defun ein:cell-goto (cell)
|
2012-05-10 05:03:10 +02:00
|
|
|
(ewoc-goto-node (oref cell :ewoc) (ein:cell-element-get cell :input))
|
2012-05-07 14:41:15 +02:00
|
|
|
;; Skip the newline
|
|
|
|
(forward-char))
|
|
|
|
|
|
|
|
(defun ein:cell-clear-output (cell stdout stderr other)
|
|
|
|
;; 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
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
(apply #'ewoc-delete ewoc output-nodes))
|
2012-05-10 05:03:10 +02:00
|
|
|
(plist-put (oref cell :element) :output nil)
|
|
|
|
(setf (oref :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
|
|
|
|
(let ((inhibit-read-only t))
|
|
|
|
(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 05:03:10 +02:00
|
|
|
(setf (oref :cell outputs)
|
|
|
|
(ein:remove-by-index (oref :cell outputs) indices))))))
|
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")
|
|
|
|
'(ouput-subarea))
|
|
|
|
(("pyerr")
|
|
|
|
'(ouput-subarea))
|
|
|
|
(("display_data")
|
|
|
|
'(ouput-subarea))
|
|
|
|
(("stream")
|
|
|
|
(list 'ouput-stream 'ouput-subarea
|
|
|
|
(intern (format "ouput-%s" (plist-get json :stream)))))))
|
|
|
|
|
|
|
|
(defun ein:cell-append-output (cell json dynamic)
|
|
|
|
;; (ein:cell-expand cell)
|
|
|
|
;; (ein:flush-clear-timeout)
|
2012-05-10 05:03:10 +02:00
|
|
|
(setf (oref :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-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
|
|
|
|
(append (plist-get element :output) (list ewoc-node)))))
|
|
|
|
|
|
|
|
(defun ein:cell-append-pyout (cell json dynamic)
|
|
|
|
(ein:insert-read-only (format "Out [%s]:\n"
|
|
|
|
(or (plist-get json :prompt_number) " ")))
|
|
|
|
(ein:cell-append-mime-type json dynamic))
|
|
|
|
|
|
|
|
(defun ein:cell-append-pyerr (cell json)
|
|
|
|
(mapc (lambda (tb)
|
|
|
|
(ein:cell-append-text tb)
|
|
|
|
(ein:cell-append-text "\n"))
|
|
|
|
(plist-get json :traceback)))
|
|
|
|
|
|
|
|
(defun ein:cell-append-stream (cell json)
|
|
|
|
(unless (plist-get json :stream)
|
|
|
|
(plist-put json :stream "stdout"))
|
|
|
|
(let ((last (last (ein:cell-element-get cell :output))))
|
|
|
|
(when (and last
|
|
|
|
(equal (plist-get last :output_type) "stream")
|
|
|
|
(equal (plist-get json :stream) (plist-get last :stream)))
|
|
|
|
(ein:insert-read-only (plist-get json :text)))))
|
|
|
|
|
|
|
|
(defun ein:cell-append-display-data (cell json dynamic)
|
|
|
|
(ein:cell-append-mime-type json dynamic))
|
|
|
|
|
|
|
|
(defun ein:cell-append-mime-type (json dynamic)
|
|
|
|
(loop
|
2012-05-08 05:04:24 +02:00
|
|
|
for key in '(javascript svg png jpeg text html latex)
|
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
|
|
|
|
(javascript
|
|
|
|
(when dynamic
|
|
|
|
(ein:log 'info (concat "ein:cell-append-mime-type does not support "
|
|
|
|
"dynamic javascript. got: %s") value)))
|
|
|
|
((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
|
|
|
|
|
|
|
(defun ein:cell-append-text (data)
|
|
|
|
;; FIXME: implement HTML special escaping
|
|
|
|
;; escape ANSI & HTML specials in plaintext:
|
|
|
|
(ein:insert-read-only (ansi-color-apply data)))
|
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
(defmethod ein:cell-to-json ((cell ein:codecell))
|
2012-05-08 08:26:56 +02:00
|
|
|
"Return json-ready alist."
|
|
|
|
`((input . ,(ein:cell-get-text cell))
|
|
|
|
(cell_type . "code")
|
2012-05-10 05:03:10 +02:00
|
|
|
,@(ein:aif (oref cell :input-prompt-number)
|
2012-05-08 08:26:56 +02:00
|
|
|
`((prompt_number . ,it)))
|
2012-05-10 05:03:10 +02:00
|
|
|
(outputs . ,(apply #'vector (oref :cell outputs)))
|
2012-05-08 08:26:56 +02:00
|
|
|
(language . "python")
|
|
|
|
;; FIXME: implement `collapsed'
|
|
|
|
(collapsed . ,json-false)))
|
2012-05-08 05:53:18 +02:00
|
|
|
|
2012-05-10 05:03:10 +02:00
|
|
|
(defmethod ein:cell-to-json ((cell ein:textcell))
|
|
|
|
`((cell_type . ,(oref cell :cell-type))
|
2012-05-10 02:20:21 +02:00
|
|
|
(source . ,(ein:cell-get-text cell))))
|
|
|
|
|
2012-05-07 14:41:15 +02:00
|
|
|
(defun ein:cell-next (cell)
|
|
|
|
"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 05:03:10 +02:00
|
|
|
(when (ein:basecell-p cell)
|
2012-05-07 14:41:15 +02:00
|
|
|
cell))))
|
|
|
|
|
|
|
|
(provide 'ein-cell)
|
|
|
|
|
|
|
|
;;; ein-cell.el ends here
|