:image/png not :png

This commit is contained in:
dickmao 2020-01-11 16:03:54 -05:00
parent ce4252d2af
commit 702f04064a
20 changed files with 184 additions and 656 deletions

View file

@ -37,9 +37,7 @@
(!cons "memory" ecukes-exclude-tags)
(!cons "content" ecukes-exclude-tags)
(when (eq system-type 'darwin)
(!cons "julia" ecukes-exclude-tags)))
(unless (fboundp 'libxml-parse-xml-region)
(!cons "julia" ecukes-exclude-tags))
(!cons "svg" ecukes-exclude-tags))
(defvar ein:testing-jupyter-server-root (f-parent (f-dirname load-file-name)))

View file

@ -220,7 +220,8 @@ Scenario: Undo needs to at least work for reopened notebooks
And I press "C-/"
And I undo again
And I undo again
Then the cursor should be at point "106"
And I undo again
Then the cursor should be at point "124"
@undo
Scenario: Toggling between markdown and codecell does not break undo

View file

@ -1,78 +0,0 @@
;;; ein-cell-output.el --- Cell module
;; (C) 2015- John M. Miller
;; Author: John M. Miller (millejoh at mac dot com)
;; This file is NOT part of GNU Emacs.
;; ein-cell-output.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-output.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-output.el. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Because wiriting cell outputs to nbformat v4.0 json is complicated
;; enought that it warrants a file all to its own.
;;; Code:
(require 'ein-cell)
(defvar ein:output-type-map
'((:svg . :image/svg+xml) (:png . :image/png) (:jpeg . :image/jpeg)
(:text . :text/plain)
(:html . :text/html) (:latex . :text/latex) (:javascript . :text/javascript)))
(defun ein:output-property (maybe-property)
(cdr (assoc maybe-property ein:output-type-map)))
;;; Dealing with Code cell outputs
(defun ein:cell-stream-output-to-json (output)
`((output_type . "stream")
(name . ,(plist-get output :stream))
(text . ,(plist-get output :text))))
(defun ein:cell-error-output-to-json (output)
`((output_type . "error")
(ename . ,(plist-get output :ename))
(evalue . ,(plist-get output :evalue))
(traceback . ,(plist-get output :traceback))))
(defun ein:cell-execute-result-output-to-json (output)
(let ((data (aif (plist-get output :text)
`("text/plain" . ,it)
(plist-get output :data))))
`((output_type . "execute_result")
(metadata . ,(make-hash-table))
(execution_count . ,(or (plist-get output :prompt_number)
(plist-get output :execution_count)))
(data . (,data)))))
(defun ein:maybe-get-output-mime-data (output)
(cl-loop for type in '(:svg :png :jpeg :html :latex :javascript :text)
if (plist-get output type)
collecting (cons (ein:output-property type) (plist-get output type))))
(defun ein:cell-display-data-output-to-json (output)
(let ((data (or (ein:maybe-get-output-mime-data output)
(plist-get output :data))))
`((output_type . "display_data")
(data . ,data)
(metadata . ,(make-hash-table)))))
(defun ein:find-and-make-outputs (output-plist)
(cl-loop for prop in ein:output-type-map
when (plist-get output-plist (cdr prop))
collect (list (cdr prop) (plist-get output-plist (cdr prop)))))
(provide 'ein-cell-output)

View file

@ -113,36 +113,6 @@ Delete current text first, thus effecting a \"refresh\"."
"Face for cell output area errors"
:group 'ein)
(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
'((t :weight bold :inherit (variable-pitch ein:cell-input-area)))
"Face for level 6 heading."
:group 'ein)
(defface ein:cell-output-prompt
'((t :inherit header-line))
"Face for cell output prompt"
@ -280,7 +250,6 @@ a number will limit the number of lines in a cell output."
(("html") 'ein:htmlcell)
(("markdown") 'ein:markdowncell)
(("raw") 'ein:rawcell)
(("heading") 'ein:headingcell)
(("shared-output") 'ein:shared-output-cell)
(t (error "No cell type called %S" type))))
@ -318,12 +287,6 @@ a number will limit the number of lines in a cell output."
(setf (slot-value cell 'input) it))
cell)
(cl-defmethod ein:cell-init ((cell ein:headingcell) data) ;; FIXME: Was :after method
(cl-call-next-method)
(aif (plist-get data :level)
(setf (slot-value cell 'level) it))
cell)
(cl-defmethod ein:cell-convert ((cell ein:basecell) type)
(let ((new (ein:cell-from-type type)))
;; copy attributes
@ -345,12 +308,6 @@ a number will limit the number of lines in a cell output."
(setf (slot-value new 'kernel) (slot-value cell 'kernel)))
new))
(cl-defmethod ein:cell-convert ((cell ein:headingcell) type)
(let ((new (cl-call-next-method)))
(when (ein:headingcell-p new)
(setf (slot-value new 'level) (slot-value cell 'level)))
new))
(cl-defmethod ein:cell-copy ((cell ein:basecell))
(ein:cell-convert cell (slot-value cell 'cell-type)))
@ -385,16 +342,6 @@ a number will limit the number of lines in a cell output."
do (ein:cell--ewoc-invalidate ewoc en)))
new))
(cl-defmethod ein:cell-change-level ((cell ein:headingcell) level)
(assert (integerp level))
(let ((inhibit-read-only t)
(buffer-undo-list t)) ; disable undo recording
(setf (slot-value cell 'level) level)
;; draw ewoc node
(cl-loop with ewoc = (slot-value cell 'ewoc)
for en in (ein:cell-all-element cell)
do (ein:cell--ewoc-invalidate ewoc en))))
;;; Getter/setter
(cl-defmethod ein:cell-num-outputs ((cell ein:codecell))
@ -534,11 +481,6 @@ Return language name as a string or `nil' when not defined.
(format "%s:" (slot-value cell 'cell-type))
'font-lock-face 'ein:cell-input-prompt))
(cl-defmethod ein:cell-insert-prompt ((cell ein:headingcell))
(ein:insert-read-only
(format "h%s:" (slot-value cell 'level))
'font-lock-face 'ein:cell-input-prompt))
(cl-defmethod ein:cell-insert-input ((cell ein:basecell))
"Insert input of the CELL in the buffer.
Called from ewoc pretty printer via `ein:cell-pp'."
@ -557,9 +499,6 @@ Return language name as a string or `nil' when not defined.
"Return the face (symbol) for input area."
'ein:cell-input-area)
(cl-defmethod ein:cell-get-input-area-face ((cell ein:headingcell))
(intern (format "ein:cell-heading-%d" (slot-value cell 'level))))
(cl-defmethod ein:cell-get-output-area-face-for-output-type (output-type)
"Return the face (symbol) for output area."
(ein:case-equal output-type
@ -956,27 +895,24 @@ Called from ewoc pretty printer via `ein:cell-insert-output'."
(make-obsolete-variable 'ein:output-type-preference nil "0.17.0")
(defun ein:cell-output-type (mime-type)
"Investigate why :image/svg+xml to :svg and :text/plain to :text"
(defun ein:cell-extract-image-format (mime-type)
"From :image/svg+xml to \"svg\"."
(let* ((mime-str (if (symbolp mime-type) (symbol-name mime-type) mime-type))
(minor-kw (car (nreverse (split-string mime-str "/"))))
(minor (car (nreverse (split-string minor-kw ":")))))
(intern (concat ":"
(cond ((string= minor "plain") "text")
(t (cl-subseq minor 0 (cl-search "+" minor))))))))
(cl-subseq minor 0 (cl-search "+" minor))))
(defun ein:cell-append-mime-type (json)
(ein:output-area-case-type
json
(cl-case type
((:html)
((:text/html)
(funcall (ein:output-area-get-html-renderer) value))
((:svg :png :jpeg)
((:image/svg+xml :image/png :image/jpeg)
(let ((image (create-image (condition-case nil
(base64-decode-string value)
(error value))
(intern (car (nreverse
(split-string (symbol-name type) ":"))))
(intern-soft (ein:cell-extract-image-format type))
t)))
(if ein:output-area-inlined-images
(ein:insert-image image)
@ -999,124 +935,38 @@ Called from ewoc pretty printer via `ein:cell-insert-output'."
text)
(format "Error: %S" err)))))
(cl-defmethod ein:cell-to-json ((cell ein:codecell) &optional discard-output)
(cl-defmethod ein:cell-to-json ((cell ein:codecell))
"Return json-ready alist."
`((input . ,(ein:cell-get-text cell))
(cell_type . "code")
,@(aif (ein:oref-safe cell 'input-prompt-number)
`((prompt_number . ,it)))
(outputs . ,(if discard-output [] (apply #'vector (slot-value cell 'outputs))))
(outputs . ,(apply #'vector (slot-value cell 'outputs)))
(language . ,(or (ein:cell-language cell) "python"))
(collapsed . ,(if (slot-value cell 'collapsed) t json-false))))
(defvar ein:output-type-map
'((:svg . :image/svg+xml) (:png . :image/png) (:jpeg . :image/jpeg)
(:text . :text/plain)
(:html . :text/html) (:latex . :text/latex) (:javascript . :text/javascript)))
(defun ein:output-property-p (maybe-property)
(assoc maybe-property ein:output-type-map))
(cl-defmethod ein:cell-to-nb4-json ((cell ein:codecell) wsidx &optional discard-output)
(let* ((metadata (slot-value cell 'metadata))
(outputs (if discard-output []
(slot-value cell 'outputs)))
(renamed-outputs '())
(execute-count (aif (ein:oref-safe cell 'input-prompt-number)
(and (numberp it) it))))
(setq metadata (plist-put metadata :collapsed (if (slot-value cell 'collapsed) t json-false)))
(setq metadata (plist-put metadata :autoscroll json-false))
(setq metadata (plist-put metadata :ein.tags (format "worksheet-%s" wsidx)))
(unless discard-output
(dolist (output outputs)
(let ((otype (plist-get output :output_type)))
(ein:log 'debug "Saving output of type %S" otype)
(if (and (or (equal otype "display_data")
(equal otype "execute_result"))
(null (plist-get output :metadata)))
(plist-put output :metadata (make-hash-table)))
(setq renamed-outputs
(append renamed-outputs
(list (let ((ocopy (cl-copy-list output))
(new-output '()))
(cl-loop while ocopy
do (let ((prop (pop ocopy))
(value (pop ocopy)))
(ein:log 'debug "Checking property %s for output type '%s'"
prop otype)
(cond
((equal prop :stream) (progn (push value new-output)
(push :name new-output)))
((and (or (equal otype "display_data")
(equal otype "execute_result"))
(ein:output-property-p prop))
(let ((new-prop (cdr (ein:output-property-p prop))))
(if (plist-member new-output :data)
(setq new-output (plist-put new-output :data
(append (plist-get new-output :data)
(list new-prop (list value))
)))
(push (list new-prop (list value)) new-output)
(push :data new-output))
))
((and (equal otype "display_data")
(equal prop :text))
(ein:log 'debug "SAVE-NOTEBOOK: Skipping unnecessary :text data."))
;; ((and (equal otype "execute_result")
;; (ein:output-property-p prop)
;; ;; (or (equal prop :text)
;; ;; (equal prop :html)
;; ;; (equal prop :latex))
;; )
;; (ein:log 'debug "Fixing execute_result (%s?)." otype)
;; (let ((new-prop (cdr (ein:output-property-p prop))))
;; (push (list new-prop (list value)) new-output)
;; (push :data new-output)))
((and (equal otype "execute_result")
(equal prop :prompt_number))
(ein:log 'debug "SAVE-NOTEBOOK: Fixing prompt_number property.")
(push value new-output)
(push :execution_count new-output))
(t (progn (push value new-output) (push prop new-output)))))
finally return new-output))))
))))
(cl-defmethod ein:cell-to-nb4-json ((cell ein:codecell) wsidx)
(let ((execute-count (aif (ein:oref-safe cell 'input-prompt-number)
(and (numberp it) it)))
(metadata (slot-value cell 'metadata)))
`((source . ,(ein:cell-get-text cell))
(cell_type . "code")
,@(if execute-count
`((execution_count . ,execute-count))
`((execution_count)))
(outputs . ,(apply #'vector (or renamed-outputs outputs)))
(metadata . ,metadata))))
,@(when execute-count
`((execution_count . ,execute-count)))
(outputs . ,(apply #'vector (slot-value cell 'outputs)))
(metadata . ,(plist-put metadata :collapsed (if (slot-value cell 'collapsed) t
json-false))))))
(cl-defmethod ein:cell-to-json ((cell ein:textcell) &optional discard-output)
(cl-defmethod ein:cell-to-json ((cell ein:textcell))
`((cell_type . ,(slot-value cell 'cell-type))
(source . ,(ein:cell-get-text cell))))
(cl-defmethod ein:cell-to-nb4-json ((cell ein:textcell) wsidx &optional discard-output)
(cl-defmethod ein:cell-to-nb4-json ((cell ein:textcell) wsidx)
(let ((metadata (slot-value cell 'metadata)))
(setq metadata (plist-put metadata :ein.tags (format "worksheet-%s" wsidx)))
`((cell_type . ,(slot-value cell 'cell-type))
(source . ,(ein:cell-get-text cell))
(metadata . ,metadata))))
(cl-defmethod ein:cell-to-nb4-json ((cell ein:headingcell) wsidx &optional discard-output)
(let ((metadata (slot-value cell 'metadata))
(header (make-string (slot-value cell 'level) ?#)))
(setq metadata (plist-put metadata :ein.tags (format "worksheet-%s" wsidx)))
`((cell_type . "markdown")
(source . ,(format "%s %s" header (ein:cell-get-text cell)))
(metadata . ,metadata))))
(cl-defmethod ein:cell-to-json ((cell ein:headingcell) &optional discard-output)
(let ((json (cl-call-next-method)))
(append json `((level . ,(slot-value cell 'level))))))
(metadata . ,(plist-put metadata :collapsed json-false)))))
(cl-defmethod ein:cell-next ((cell ein:basecell))
"Return next cell of the given CELL or nil if CELL is the last one."
@ -1175,48 +1025,16 @@ Called from ewoc pretty printer via `ein:cell-insert-output'."
(let ((events (slot-value cell 'events)))
(ein:events-trigger events 'set_next_input.Worksheet
(list :cell cell :text text))
(ein:events-trigger events 'maybe_reset_undo.Worksheet cell)
))
(ein:events-trigger events 'maybe_reset_undo.Worksheet cell)))
;;; 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.
(cl-defmethod ein:cell--handle-output ((cell ein:codecell) msg-type content
_metadata)
(let* ((json (list :output_type msg-type)))
(ein:case-equal msg-type
(("stream")
(plist-put json :text (or (plist-get content :data)
(plist-get content :text))) ;; Horrible hack to deal with version 5.0 of messaging protocol.
(plist-put json :stream (plist-get content :name)))
(("display_data" "pyout" "execute_result") ;; in v4 nbformat execute_result == pyout
(when (or (equal msg-type "pyout")
(equal msg-type "execute_result"))
(plist-put json :prompt_number (plist-get content :execution_count)))
(setq json (ein:output-area-convert-mime-types json (plist-get content :data))))
(("pyerr" "error")
(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)
(cl-defmethod ein:cell--handle-output ((cell ein:codecell) msg-type content meta)
;; (ein:output-area-convert-mime-types content (plist-get content :data))
(ein:cell-append-output cell
(plist-put
(plist-put content :output_type msg-type)
:metadata meta))
;; (setf (slot-value cell 'dirty) t)
(ein:events-trigger (slot-value cell 'events) 'maybe_reset_undo.Worksheet cell)))
(defun ein:output-area-convert-mime-types (json data)
(let ((known-mimes (cl-remove-if-not
#'identity
(mapcar (lambda (x) (intern-soft (concat ":" x)))
(mailcap-mime-types)))))
(mapc (lambda (x)
(-when-let* ((mime-val (plist-get data x))
(minor-kw (ein:cell-output-type x)))
(setq json (plist-put json minor-kw mime-val))))
known-mimes)
json))
(ein:events-trigger (slot-value cell 'events) 'maybe_reset_undo.Worksheet cell))
(cl-defmethod ein:cell--handle-clear-output ((cell ein:codecell) content
_metadata)
@ -1230,18 +1048,15 @@ Called from ewoc pretty printer via `ein:cell-insert-output'."
;;; Misc.
(cl-defmethod ein:cell-has-image-ouput-p ((cell ein:codecell))
(cl-defmethod ein:cell-has-image-output-p ((cell ein:codecell))
"Return `t' if given cell has image output, `nil' otherwise."
(cl-loop for out in (slot-value cell 'outputs)
when (or (plist-member out :svg)
(plist-member out :image/svg+xml)
(plist-member out :png)
(seq-some (lambda (out)
(or (plist-member out :image/svg+xml)
(plist-member out :image/png)
(plist-member out :jpeg)
(plist-member out :image/jpeg))
return t))
(plist-member out :image/jpeg)))
(slot-value cell 'outputs)))
(cl-defmethod ein:cell-has-image-ouput-p ((cell ein:textcell))
(cl-defmethod ein:cell-has-image-output-p ((cell ein:textcell))
nil)
(cl-defmethod ein:cell-get-tb-data ((cell ein:codecell))

View file

@ -166,10 +166,6 @@
((nbformat :initarg :nbformat :type integer)
(get-notebook-name :initarg :get-notebook-name :type cons
:accessor ein:worksheet--notebook-name)
;; This slot introduces too much complexity so therefore must be
;; removed later. This is here only for backward compatible
;; reason.
(discard-output-p :initarg :discard-output-p :accessor ein:worksheet--discard-output-p)
(saved-cells :initarg :saved-cells :initform nil
:accessor ein:worksheet--saved-cells
:documentation
@ -251,7 +247,7 @@
(input :initarg :input :type string
:documentation "Place to hold data until it is rendered via `ewoc'.")
(outputs :initarg :outputs :initform nil :type list)
(metadata :initarg :metadata :initform nil :type list :accessor ein:cell-metadata) ;; For nbformat >= 4
(metadata :initarg :metadata :initform nil :type list :accessor ein:cell-metadata)
(events :initarg :events :type ein:events)
(cell-id :initarg :cell-id :initform (ein:utils-uuid) :type string
:accessor ein:cell-id))
@ -290,11 +286,6 @@ auto-execution mode flag in the connected buffer is `t'.")))
(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)))
;;; Notifications
(defclass ein:notification-status ()
@ -331,9 +322,9 @@ auto-execution mode flag in the connected buffer is `t'.")))
(ein:notification-status
"NotebookStatus"
:s2m
'((notebook_saving.Notebook . "Saving Notebook...")
(notebook_saved.Notebook . "Notebook is saved")
(notebook_save_failed.Notebook . "Failed to save Notebook!")))
'((notebook_saving.Notebook . "Saving notebook...")
(notebook_saved.Notebook . "Notebook saved")
(notebook_save_failed.Notebook . "Failed saving notebook!")))
:type ein:notification-status)
(kernel
:initarg :kernel
@ -342,7 +333,7 @@ auto-execution mode flag in the connected buffer is `t'.")))
"KernelStatus"
:s2m
'((status_idle.Kernel . nil)
(status_busy.Kernel . "Kernel is busy...")
(status_busy.Kernel . "Kernel busy...")
(status_restarting.Kernel . "Kernel restarting...")
(status_restarted.Kernel . "Kernel restarted")
(status_dead.Kernel . "Kernel requires restart \\<ein:notebook-mode-map>\\[ein:notebook-restart-session-command-km]")
@ -352,7 +343,6 @@ auto-execution mode flag in the connected buffer is `t'.")))
:type ein:notification-status))
"Notification widget for Notebook.")
;;; Events
(defclass ein:events ()

View file

@ -296,9 +296,11 @@ global setting. For global setting and more information, see
:type "PUT"
:headers '(("Content-Type" . "application/json"))
:timeout ein:content-query-timeout
:data (encode-coding-string (ein:content-to-json content) buffer-file-coding-system)
:data (encode-coding-string (ein:content-to-json content)
buffer-file-coding-system)
:success (apply-partially #'ein:content-save-success callback cbargs)
:error (apply-partially #'ein:content-save-error (ein:content-url content) errcb errcbargs))
:error (apply-partially #'ein:content-save-error
(ein:content-url content) errcb errcbargs))
(ein:content-save-legacy content callback cbargs)))
(cl-defun ein:content-save-success (callback cbargs &key status response &allow-other-keys)

View file

@ -211,7 +211,7 @@ CALLBACK of arity 1, the kernel.
(let ((session-id (plist-get data :id)))
(if (plist-get data :kernel)
(setq data (plist-get data :kernel)))
(destructuring-bind (&key id &allow-other-keys) data
(cl-destructuring-bind (&key id &allow-other-keys) data
(ein:log 'verbose "ein:kernel-retrieve-session--success: kernel-id=%s session-id=%s"
id session-id)
(setf (ein:$kernel-kernel-id kernel) id)
@ -308,7 +308,6 @@ See https://github.com/ipython/ipython/pull/3307"
(ein:log 'info "Kernel connect_request_reply received."))
(defun ein:kernel-run-after-start-hook (kernel)
(ein:log 'debug "EIN:KERNEL-RUN-AFTER-START-HOOK")
(mapc #'ein:funcall-packed
(ein:$kernel-after-start-hook kernel)))
@ -331,15 +330,6 @@ delete the kernel on the server side"
(ein:log 'verbose "Kernel %s unavailable" (ein:$kernel-kernel-id kernel))
(ein:kernel-reconnect-session kernel callback)))
;;; Main public methods
;; NOTE: The argument CALLBACKS for the following functions is almost
;; same as the JS implementation in IPython. However, as Emacs
;; lisp does not support closure, value is "packed" using
;; `cons': `car' is the actual callback function and `cdr' is
;; its first argument. It's like using `cons' instead of
;; `$.proxy'.
(defun ein:kernel-object-info-request (kernel objname callbacks &optional cursor-pos detail-level)
"Send object info request of OBJNAME to KERNEL.
@ -385,63 +375,18 @@ http://ipython.org/ipython-doc/dev/development/messaging.html#object-information
(stop-on-error nil))
"Execute CODE on KERNEL.
When calling this method pass a CALLBACKS structure of the form:
The CALLBACKS plist looks like:
(:execute_reply EXECUTE-REPLY-CALLBACK
:output OUTPUT-CALLBACK
:clear_output CLEAR-OUTPUT-CALLBACK
:set_next_input SET-NEXT-INPUT)
Right hand sides ending -CALLBACK above must cons a FUNCTION and its
`packed' ARGUMENT which is a sublist of args:
Right hand sides ending -CALLBACK above are of the form (FUNCTION ARG1 ... ARGN).
(Hindsight: this was all much better implemented using `apply-partially')
(FUNCTION . ARGUMENT)
Call signature
--------------
::
(`funcall' EXECUTE-REPLY-CALLBACK ARGUMENT CONTENT METADATA)
(`funcall' OUTPUT-CALLBACK ARGUMENT MSG-TYPE CONTENT METADATA)
(`funcall' CLEAR-OUTPUT-CALLBACK ARGUMENT CONTENT METADATA)
(`funcall' SET-NEXT-INPUT ARGUMENT TEXT)
* Both CONTENT and METADATA objects are plist.
* The MSG-TYPE argument for OUTPUT-CALLBACK is a string
(one of `stream', `display_data', `pyout' and `pyerr').
* The CONTENT object for CLEAR-OUTPUT-CALLBACK has
`stdout', `stderr' and `other' fields that are booleans.
* The SET-NEXT-INPUT callback will be passed the `set_next_input' payload,
which is a string.
See `ein:kernel--handle-shell-reply' for how the callbacks are called.
Links
-----
* For general description of CONTENT and METADATA:
http://ipython.org/ipython-doc/dev/development/messaging.html#general-message-format
* `execute_reply' message is documented here:
http://ipython.org/ipython-doc/dev/development/messaging.html#execute
* Output type messages is documented here:
http://ipython.org/ipython-doc/dev/development/messaging.html#messages-on-the-pub-sub-socket
Sample implementations
----------------------
* `ein:cell--handle-execute-reply'
* `ein:cell--handle-output'
* `ein:cell--handle-clear-output'
* `ein:cell--handle-set-next-input'
Return randomly generated MSG-ID tag uniquely identifying expectation of a kernel response.
"
;; FIXME: Consider changing callback to use `&key'.
;; Otherwise, adding new arguments to callback requires
;; backward incompatible changes (hence a big diff), unlike
;; Javascript. Downside of this is that there is no short way
;; to write anonymous callback because there is no `lambda*'.
;; You can use `function*', but that's bit long...
;; FIXME: Consider allowing a list of fixed argument so that the
;; call signature becomes something like:
;; (funcall FUNCTION [ARG ...] CONTENT METADATA)
(assert (ein:kernel-live-p kernel) nil "execute_reply: Kernel is not active.")
(let* ((content (list
:code code
@ -452,7 +397,7 @@ Sample implementations
:stop_on_error (or stop-on-error json-false)))
(msg (ein:kernel--get-msg kernel "execute_request" content))
(msg-id (plist-get (plist-get msg :header) :msg_id)))
(ein:log 'debug "KERNEL-EXECUTE: code=%s msg_id=%s" code msg-id)
(ein:log 'debug "ein:kernel-execute: code=%s msg_id=%s" code msg-id)
(run-hook-with-args 'ein:pre-kernel-execute-functions msg)
(ein:websocket-send-shell-channel kernel msg)
(ein:kernel-set-callbacks-for-msg kernel msg-id callbacks)
@ -577,36 +522,6 @@ Example::
(ein:kernel-set-callbacks-for-msg kernel msg-id callbacks)
msg-id))
(defun ein:kernel-kernel-info-request (kernel callbacks)
"Request core information of KERNEL.
When calling this method pass a CALLBACKS structure of the form::
(:kernel_info_reply (FUNCTION . ARGUMENT))
Call signature::
(`funcall' FUNCTION ARGUMENT CONTENT METADATA)
CONTENT and METADATA are given by `kernel_info_reply' message.
`kernel_info_reply' message is documented here:
http://ipython.org/ipython-doc/dev/development/messaging.html#kernel-info
Example::
(ein:kernel-kernel-info-request
(ein:get-kernel)
'(:kernel_info_reply (message . \"CONTENT: %S\\nMETADATA: %S\")))
"
(assert (ein:kernel-live-p kernel) nil "kernel_info_reply: Kernel is not active.")
(ein:log 'debug "EIN:KERNEL-KERNEL-INFO-REQUEST: Sending request.")
(let* ((msg (ein:kernel--get-msg kernel "kernel_info_request" nil))
(msg-id (plist-get (plist-get msg :header) :msg_id)))
(ein:websocket-send-shell-channel kernel msg)
(ein:kernel-set-callbacks-for-msg kernel msg-id callbacks)
msg-id))
(defun ein:kernel-interrupt (kernel)
(when (ein:kernel-live-p kernel)
(ein:log 'info "Interrupting kernel")
@ -670,17 +585,18 @@ We need this to have proper behavior for the 'Stop' command in the ein:notebookl
(gethash msg-id (ein:$kernel-msg-callbacks kernel)))
(defun ein:kernel-set-callbacks-for-msg (kernel msg-id callbacks)
"Set up promise for MSG-ID."
(puthash msg-id callbacks (ein:$kernel-msg-callbacks kernel)))
(defun ein:kernel--handle-stdin-reply (kernel packet)
(setf (ein:$kernel-stdin-activep kernel) t)
(destructuring-bind
(cl-destructuring-bind
(&key header parent_header metadata content &allow-other-keys)
(ein:json-read-from-string packet)
(let ((msg-type (plist-get header :msg_type))
(msg-id (plist-get header :msg_id))
(password (plist-get content :password)))
(ein:log 'debug "KERNEL--HANDLE-STDIN-REPLY: msg_type=%s msg_id=%s"
(ein:log 'debug "ein:kernel--handle-stdin-reply: msg_type=%s msg_id=%s"
msg-type msg-id)
(cond ((string-equal msg-type "input_request")
(if (not (eql password :json-false))
@ -697,33 +613,10 @@ We need this to have proper behavior for the 'Stop' command in the ein:notebookl
(ein:websocket-send-stdin-channel kernel msg)
(setf (ein:$kernel-stdin-activep kernel) nil))))))))))
(defun ein:kernel--handle-shell-reply (kernel packet)
(destructuring-bind
(&key header content metadata parent_header &allow-other-keys)
(ein:json-read-from-string packet)
(let* ((msg-type (plist-get header :msg_type))
(msg-id (plist-get parent_header :msg_id))
(callbacks (ein:kernel-get-callbacks-for-msg kernel msg-id))
(cb (plist-get callbacks (intern (format ":%s" msg-type)))))
(ein:log 'debug "KERNEL--HANDLE-SHELL-REPLY: msg_type=%s msg_id=%s"
msg-type msg-id)
(run-hook-with-args 'ein:on-shell-reply-functions msg-type header content metadata)
(aif cb (ein:funcall-packed it content metadata))
(aif (plist-get content :payload)
(ein:kernel--handle-payload kernel callbacks it))
(let ((events (ein:$kernel-events kernel)))
(ein:case-equal msg-type
(("execute_reply")
(aif (plist-get content :execution_count)
;; It can be `nil' for silent execution
(ein:events-trigger events 'execution_count.Kernel it))))))))
(defun ein:kernel--handle-payload (kernel callbacks payload)
(cl-loop with events = (ein:$kernel-events kernel)
for p in payload
for text = (or (plist-get p :text)
(plist-get (plist-get p :data)
:text/plain))
for text = (or (plist-get p :text) (plist-get (plist-get p :data) :text/plain))
for source = (plist-get p :source)
if (member source '("IPython.kernel.zmq.page.page"
"IPython.zmq.page.page"
@ -740,24 +633,47 @@ We need this to have proper behavior for the 'Stop' command in the ein:notebookl
do (let ((cb (plist-get callbacks :set_next_input)))
(when cb (ein:funcall-packed cb text)))))
(defun ein:kernel--handle-shell-reply (kernel packet)
(cl-destructuring-bind
(&key header content metadata parent_header &allow-other-keys)
(ein:json-read-from-string packet)
(let* ((msg-type (plist-get header :msg_type))
(msg-id (plist-get parent_header :msg_id))
(callbacks (ein:kernel-get-callbacks-for-msg kernel msg-id)))
(ein:log 'debug "ein:kernel--handle-shell-reply: msg_type=%s msg_id=%s"
msg-type msg-id)
(run-hook-with-args 'ein:on-shell-reply-functions msg-type header content metadata)
(aif (plist-get callbacks (intern-soft (format ":%s" msg-type)))
(ein:funcall-packed it content metadata)
(ein:log 'info "ein:kernel--handle-shell-reply: No :%s callback for msg_id=%s"
msg-type msg-id))
(aif (plist-get content :payload)
(ein:kernel--handle-payload kernel callbacks it))
(let ((events (ein:$kernel-events kernel)))
(ein:case-equal msg-type
(("execute_reply")
(aif (plist-get content :execution_count)
(ein:events-trigger events 'execution_count.Kernel it))))))))
(defun ein:kernel--handle-iopub-reply (kernel packet)
(if (ein:$kernel-stdin-activep kernel)
(ein:ipdb--handle-iopub-reply kernel packet)
(destructuring-bind
(cl-destructuring-bind
(&key content metadata parent_header header &allow-other-keys)
(ein:json-read-from-string packet)
(let* ((msg-type (plist-get header :msg_type))
(msg-id (plist-get parent_header :msg_id))
(callbacks (ein:kernel-get-callbacks-for-msg kernel msg-id))
(events (ein:$kernel-events kernel)))
(ein:log 'debug "KERNEL--HANDLE-IOPUB-REPLY: msg_type=%s msg_id=%s"
(ein:log 'debug "ein:kernel--handle-iopub-reply: msg_type=%s msg_id=%s"
msg-type msg-id)
(if (and (not (equal msg-type "status")) (null callbacks))
(ein:log 'verbose "Not processing msg_type=%s msg_id=%s" msg-type msg-id)
(ein:case-equal msg-type
(("stream" "display_data" "pyout" "pyerr" "error" "execute_result")
(aif (plist-get callbacks :output)
(ein:funcall-packed it msg-type content metadata)))
(ein:funcall-packed it msg-type content metadata)
(ein:log 'warn (concat "ein:kernel--handle-iopub-reply: "
"No :output callback for msg_id=%s")
msg-id)))
(("status")
(ein:case-equal (plist-get content :execution_state)
(("busy")
@ -767,12 +683,13 @@ We need this to have proper behavior for the 'Stop' command in the ein:notebookl
(("dead")
(ein:kernel-disconnect kernel))))
(("data_pub")
(ein:log 'verbose (format "Received data_pub message w/content %s" packet)))
(ein:log 'verbose "ein:kernel--handle-iopub-reply: data_pub %S" packet))
(("clear_output")
(aif (plist-get callbacks :clear_output)
(ein:funcall-packed it content metadata)))))))))
;;; Utility functions
(ein:funcall-packed it content metadata)
(ein:log 'info (concat "ein:kernel--handle-iopub-reply: "
"No :clear_output callback for msg_id=%s")
msg-id))))))))
(defun ein:kernel-filename-to-python (kernel filename)
"See: `ein:filename-to-python'."
@ -792,7 +709,6 @@ Used in `ein:pytools-finish-tooltip', etc."
(defun ein:kernel-construct-help-string (content)
"Construct help string from CONTENT of ``:object_info_reply``.
Used in `ein:pytools-finish-tooltip', etc."
(ein:log 'debug "KERNEL-CONSTRUCT-HELP-STRING")
(let* ((defstring (ein:aand
(ein:kernel-construct-defstring content)
(ansi-color-apply it)
@ -807,7 +723,6 @@ Used in `ein:pytools-finish-tooltip', etc."
(help (ein:aand
(delete nil (list defstring docstring))
(ein:join-str "\n" it))))
(ein:log 'debug "KERNEL-CONSTRUCT-HELP-STRING: help=%s" help)
help))
(defun ein:kernel-request-stream (kernel code func &optional args)

View file

@ -44,7 +44,6 @@
(require 'ein-kernel)
(require 'ein-kernelinfo)
(require 'ein-cell)
(require 'ein-cell-output)
(require 'ein-worksheet)
(require 'ein-iexec)
(require 'ein-scratchsheet)
@ -65,47 +64,19 @@
;;; Configuration
(defcustom ein:notebook-discard-output-on-save 'no
"Configure if the output part of the cell should be saved or not.
.. warning:: This configuration is obsolete now.
Use nbconvert (https://github.com/ipython/nbconvert) to
strip output.
`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'.
"
:type '(choice (const :tag "No" 'no)
(const :tag "Yes" 'yes)
)
:group 'ein)
(make-obsolete-variable 'ein:use-smartrep nil "0.17.0")
(defvar *ein:notebook--pending-query* (make-hash-table :test 'equal)
"A map: (URL-OR-PORT . PATH) => t/nil")
(make-obsolete-variable 'ein:notebook-autosave-frequency nil "0.17.0")
(make-obsolete-variable 'ein:notebook-create-checkpoint-on-save nil "0.17.0")
(make-obsolete-variable 'ein:notebook-discard-output-on-save nil "0.17.0")
(defun ein:notebook-cell-has-image-output-p (-ignore- cell)
(ein:cell-has-image-ouput-p cell))
(defvar *ein:notebook--pending-query* (make-hash-table :test 'equal)
"A map: (URL-OR-PORT . PATH) => t/nil")
(defun ein:notebook-discard-output-p (notebook cell)
"Return non-`nil' if the output must be discarded, otherwise save."
(case ein:notebook-discard-output-on-save
(no nil)
(yes t)
(t (funcall ein:notebook-discard-output-on-save notebook cell))))
(defun ein:notebook-cell-has-image-output-p (_ignore cell)
(ein:cell-has-image-output-p cell))
;; As opening/saving notebook treats possibly huge data, define these
;; timeouts separately:
@ -548,9 +519,6 @@ This is equivalent to do ``C-c`` in the console program."
(funcall func
(ein:$notebook-nbformat notebook)
(ein:notebook-name-getter notebook)
(cons (lambda (notebook cell)
(ein:notebook-discard-output-p notebook cell))
notebook)
(ein:$notebook-kernel notebook)
(ein:$notebook-events notebook)))
@ -761,8 +729,8 @@ This is equivalent to do ``C-c`` in the console program."
(cl-defun ein:notebook-save-notebook-error (notebook &key symbol-status
&allow-other-keys)
(if (eq symbol-status 'user-cancel)
(ein:log 'info "Cancel saving notebook.")
(ein:log 'info "Failed to save notebook!")
(ein:log 'info "Cancelled save.")
(ein:log 'warn "Failed saving notebook!")
(ein:events-trigger (ein:$notebook-events notebook)
'notebook_save_failed.Notebook)))
@ -1437,19 +1405,12 @@ watch the fireworks!"
(aif ein:anything-kernel-history-search-key
(ein:notebook--define-key ein:notebook-mode-map it anything-ein-kernel-history))
(setq indent-tabs-mode nil) ;; Being T causes problems with Python code.
(ein:worksheet-imenu-setup)))
))
;; To avoid MuMaMo to discard `ein:notebook-mode', make it
;; permanent local.
(put 'ein:notebook-mode 'permanent-local t)
(define-derived-mode ein:notebook-plain-mode fundamental-mode "EIN[plain]"
"IPython notebook mode without fancy coloring."
(font-lock-mode))
(define-derived-mode ein:notebook-python-mode python-mode "EIN[python]"
"Use `python-mode' for whole notebook buffer.")
(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.

View file

@ -125,13 +125,34 @@ Usage::
(ein:xml-replace-attributes dom 'a 'href replace-p replacer)
(ein:xml-replace-attributes dom 'img 'src replace-p replacer)))
(defun ein:output-area-type (mime-type)
"Investigate why :image/svg+xml to :svg and :text/plain to :text"
(let* ((mime-str (if (symbolp mime-type) (symbol-name mime-type) mime-type))
(minor-kw (car (nreverse (split-string mime-str "/"))))
(minor (car (nreverse (split-string minor-kw ":")))))
(intern (concat ":"
(cond ((string= minor "plain") "text")
(t (cl-subseq minor 0 (cl-search "+" minor))))))))
(defun ein:output-area-convert-mime-types (json data)
(let ((known-mimes (cl-remove-if-not
#'identity
(mapcar (lambda (x) (intern-soft (concat ":" x)))
(mailcap-mime-types)))))
(mapc (lambda (x)
(-when-let* ((mime-val (plist-get data x))
(minor-kw (ein:output-area-type x)))
(setq json (plist-put json minor-kw mime-val))))
known-mimes)
json))
(defmacro ein:output-area-case-type (json &rest case-body)
`(progn (aif (plist-get ,json :data) (setq ,json it)) ;; nbformat v4 ???
`(progn (aif (plist-get ,json :data) (setq ,json it))
(seq-some (lambda (type)
(when-let ((value (plist-get ,json type)))
,@case-body
t))
(list :svg :png :jpeg :text :html :latex :javascript))))
(list :image/svg+xml :image/png :image/jpeg :text/plain :text/html :application/latex :application/tex :application/javascript))))
(provide 'ein-output-area)

View file

@ -117,7 +117,7 @@ working."
(lambda (name msg-type content -metadata-not-used-)
(ein:case-equal msg-type
(("stream" "display_data")
(ein:pytools-finish-tooltip name (ein:json-read-from-string (plist-get content :text)) nil))))
(ein:pytools-finish-tooltip name (ein:json-read-from-string (or (plist-get content :text) (plist-get (plist-get content :data) :text/plain))) nil))))
func)))
(ein:kernel-object-info-request
kernel func (list :object_info_reply
@ -178,7 +178,7 @@ pager buffer. You can explicitly specify the object by selecting it."
(ein:log 'debug "object[[%s]] other-window[[%s]]" object other-window)
(ein:case-equal msg-type
(("stream" "display_data")
(aif (or (plist-get content :text) (plist-get content :data))
(aif (or (plist-get content :text) (plist-get (plist-get content :data) :text/plain))
(if (string-match ein:pytools-jump-to-source-not-found-regexp it)
(ein:log 'info
"Jumping to the source of %s...Not found" object)
@ -231,7 +231,7 @@ is defined."
(destructuring-bind (kernel object callback) packed
(if (or (string= msg-type "stream")
(string= msg-type "display_data"))
(aif (or (plist-get content :text) (plist-get content :data))
(aif (or (plist-get content :text) (plist-get (plist-get content :data) :text/plain))
(if (string-match ein:pytools-jump-to-source-not-found-regexp it)
(ein:log 'info
"Source of %s not found" object)

View file

@ -37,11 +37,10 @@
:documentation
"Worksheet without needs for saving.")
(defun ein:scratchsheet-new (nbformat get-notebook-name discard-output-p
kernel events &rest args)
(defun ein:scratchsheet-new (nbformat get-notebook-name kernel events &rest args)
(apply #'make-instance 'ein:scratchsheet
:nbformat nbformat :get-notebook-name get-notebook-name
:discard-output-p discard-output-p :kernel kernel :events events
:kernel kernel :events events
args))
(cl-defmethod ein:worksheet--buffer-name ((ws ein:scratchsheet))

View file

@ -293,11 +293,10 @@ Normalize `buffer-undo-list' by removing extraneous details, and update the ein:
;;; Initialization of object and buffer
(defun ein:worksheet-new (nbformat get-notebook-name discard-output-p
kernel events &rest args)
(defun ein:worksheet-new (nbformat get-notebook-name kernel events &rest args)
(apply #'make-instance 'ein:worksheet
:nbformat nbformat :get-notebook-name get-notebook-name
:discard-output-p discard-output-p :kernel kernel :events events
:kernel kernel :events events
args))
(cl-defmethod ein:worksheet-bind-events ((ws ein:worksheet))
@ -463,21 +462,17 @@ Normalize `buffer-undo-list' by removing extraneous details, and update the ein:
"Convert worksheet WS into JSON ready alist.
It sets buffer internally so that caller doesn not have to set
current buffer."
(let* ((discard-output-p (ein:worksheet--discard-output-p ws))
(cells (ein:with-possibly-killed-buffer (ein:worksheet-buffer ws)
(let* ((cells (ein:with-possibly-killed-buffer (ein:worksheet-buffer ws)
(mapcar (lambda (c)
(ein:cell-to-json
c (ein:funcall-packed discard-output-p c)))
(ein:cell-to-json c))
(ein:worksheet-get-cells ws)))))
`((cells . ,(apply #'vector cells))
,@(ein:aand (ein:worksheet--metadata ws) `((metadata . ,it))))))
(cl-defmethod ein:worksheet-to-nb4-json ((ws ein:worksheet) wsidx)
(let* ((discard-output-p (slot-value ws 'discard-output-p))
(cells (ein:with-possibly-killed-buffer (ein:worksheet-buffer ws)
(let* ((cells (ein:with-possibly-killed-buffer (ein:worksheet-buffer ws)
(mapcar (lambda (c)
(ein:cell-to-nb4-json
c wsidx (ein:funcall-packed discard-output-p c)))
(ein:cell-to-nb4-json c wsidx))
(ein:worksheet-get-cells ws)))))
cells))
@ -613,7 +608,7 @@ If you really want use this command, you can do something like this
t))
(ein:worksheet--shift-undo-list cell)
(let ((inhibit-read-only t)
(buffer-undo-list t)) ; disable undo recording
(buffer-undo-list t))
(apply #'ewoc-delete
(slot-value ws 'ewoc)
(ein:cell-all-element cell)))
@ -772,13 +767,12 @@ directly."
(when focus (ein:cell-goto new relpos))
(ein:worksheet--unshift-undo-list new nil cell))))
(defun ein:worksheet-change-cell-type (ws cell type &optional level focus)
(defun ein:worksheet-change-cell-type (ws cell type &optional focus)
"Change the cell type of the current cell.
Prompt will appear in the minibuffer.
When used in as a Lisp function, TYPE (string) should be chose
from \"code\", \"markdown\", \"raw\" and \"heading\". LEVEL is
an integer used only when the TYPE is \"heading\"."
from \"code\", \"markdown\", \"raw\" and \"heading\"."
(interactive
(let* ((ws (ein:worksheet--get-ws-or-error))
(cell (ein:worksheet-get-current-cell))
@ -791,18 +785,12 @@ an integer used only when the TYPE is \"heading\"."
(type (case key
(?c "code")
(?m "markdown")
(?r "raw")
(t "heading")))
(level (when (equal type "heading")
(string-to-number (char-to-string key)))))
(list ws cell type level t)))
(?r "raw"))))
(list ws cell type t)))
(let ((relpos (ein:cell-relative-point cell))
(new (ein:cell-convert-inplace cell type)))
(when (ein:codecell-p new)
(setf (slot-value new 'kernel) (slot-value ws 'kernel)))
(when level
(ein:cell-change-level new level))
(ein:worksheet--unshift-undo-list cell)
(when focus (ein:cell-goto new relpos))))
@ -819,10 +807,7 @@ argument \(C-u)."
(head (buffer-substring beg pos))
(new (ein:worksheet-insert-cell-above ws
(slot-value cell 'cell-type)
cell))
)
(when (ein:headingcell-p cell)
(ein:cell-change-level new (slot-value cell 'level)))
cell)))
(undo-boundary)
(delete-region beg pos)
(unless no-trim
@ -1253,26 +1238,6 @@ function."
(ein:worksheet-get-cells ws))))))
ws (current-buffer)))))
;;; Imenu
(defun ein:worksheet-imenu-create-index ()
"`imenu-create-index-function' for notebook buffer."
;; As Imenu does not provide the way to represent level *and*
;; position, use #'s to do that.
(cl-loop for cell in (when (ein:worksheet-p ein:%worksheet%)
(seq-filter #'ein:headingcell-p
(ein:worksheet-get-cells ein:%worksheet%)))
for sharps = (cl-loop repeat (slot-value cell 'level) collect "#")
for text = (ein:cell-get-text cell)
for name = (ein:join-str "" (append sharps (list " " text)))
collect (cons name (ein:cell-input-pos-min cell))))
(defun ein:worksheet-imenu-setup ()
"Called via notebook mode hooks."
(setq imenu-create-index-function #'ein:worksheet-imenu-create-index))
;;; Workarounds
(defadvice fill-paragraph (around ein:worksheet-fill-paragraph activate)

View file

@ -120,8 +120,7 @@
(ein:output-area-case-type
json
(cl-case type
((:svg :png :jpeg)
(message "got here %s" type)
((:image/svg+xml :image/png :image/jpeg)
(let ((file (or explicit-file (ob-ein--inline-image-info value))))
(ob-ein--write-base64-image value file)
(setq result (format "[[file:%s]]" file))))

View file

@ -67,10 +67,6 @@ To make OUTPUTS data, use `ein:testing-codecell-pyout-data'."
(defun ein:testing-htmlcell-data (&optional source)
(ein:testing-textcell-data source "html"))
(defun ein:testing-headingcell-data (&optional source level)
(append (ein:testing-textcell-data source "heading")
(list :level (or level 1))))
(provide 'ein-testing-cell)
;;; ein-testing-cell.el ends here

View file

@ -128,47 +128,47 @@ some input
,regexp-display-data)))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
text ("some output") ((:data (:text "some output"))))
text ("some output") ((:data (:text/plain "some output"))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
latex
("some output \\\\LaTeX")
((:data (:latex "some output \\LaTeX"))))
((:data (:application/latex "some output \\LaTeX"))))
(when (image-type-available-p 'svg)
(eintest:gene-test-cell-insert-output-pyout-and-display-data
svg
("\\.")
((:data (:text "some output text" :svg ein:testing-example-svg)))))
((:data (:text/plain "some output text" :image/svg+xml ein:testing-example-svg)))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
html
("some output text")
((:data (:text "some output text" :html "<b>not shown</b>"))))
((:data (:text/plain "some output text" :text/html "<b>not shown</b>"))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
javascript
("some output text")
((:data (:text "some output text" :javascript "$.do.something()"))))
((:data (:text/plain "some output text" :application/javascript "$.do.something()"))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
text-two
("first output text" "second output text")
((:data (:text "first output text")) (:data (:text "second output text"))))
((:data (:text/plain "first output text")) (:data (:text/plain "second output text"))))
(eintest:gene-test-cell-insert-output-pyout-and-display-data
text-javascript
("first output text" "second output text")
((:data (:text "first output text"))
(:data (:text "second output text" :javascript "$.do.something()"))))
((:data (:text/plain "first output text"))
(:data (:text/plain "second output text" :application/javascript "$.do.something()"))))
(when (image-type-available-p 'svg)
(eintest:gene-test-cell-insert-output-pyout-and-display-data
text-latex-svg
("first output text" "second output \\\\LaTeX")
((:data (:text "first output text"))
(:data (:latex "second output \\LaTeX"))
(:data (:text "some output text" :svg ein:testing-example-svg)))))
((:data (:text/plain "first output text"))
(:data (:application/latex "second output \\LaTeX"))
(:data (:text/plain "some output text" :image/svg+xml ein:testing-example-svg)))))
;; Insert pyerr

View file

@ -23,8 +23,7 @@
(input (ein:join-str "\n" '("first input" "second input")))
(output-0 (list :output_type "execute_result"
:prompt_number output-prompt-number
:text (list "first output"
"second output")))
:text (list "first output" "second output")))
(data (ein:testing-codecell-data
input input-prompt-number (list output-0)))
(cell (eintest:cell-from-json data)))
@ -62,21 +61,13 @@
(should (ein:rawcell-p cell))
(should (equal (oref cell :input) input))))
(ert-deftest ein:cell-from-json-heading ()
(let* ((input (ein:join-str "\n" '("first input" "second input")))
(data (list :cell_type "heading" :source input))
(cell (eintest:cell-from-json data)))
(should (ein:headingcell-p cell))
(should (equal (oref cell :input) input))))
;; ein:cell-to-json
(defun eintest:cell-to-json (cell input &optional discard-output)
(defun eintest:cell-to-json (cell input)
(mocker-let ((ein:cell-get-text
(cell)
((:input (list cell) :output input))))
(ein:cell-to-json cell discard-output)))
(ein:cell-to-json cell)))
(ert-deftest ein:cell-to-json-code ()
(let* ((input-prompt-number 111)
@ -96,24 +87,6 @@
(should (equal (cdr (assq 'language alist)) "python"))
(should (equal (cdr (assq 'collapsed alist)) json-false))))
(ert-deftest ein:cell-to-json-code-discard-output ()
(let* ((input-prompt-number 111)
(output-prompt-number 222)
(input (ein:join-str "\n" '("first input" "second input")))
(output-0 (list :output_type "execute_result"
:prompt_number output-prompt-number
:text (list "first output"
"second output")))
(data (ein:testing-codecell-data
input input-prompt-number (list output-0)))
(cell (eintest:cell-from-json data))
(alist (eintest:cell-to-json cell input t)))
(should (equal (cdr (assq 'input alist)) "first input\nsecond input"))
(should (equal (cdr (assq 'cell_type alist)) "code"))
(should (equal (cdr (assq 'outputs alist)) []))
(should (equal (cdr (assq 'language alist)) "python"))
(should (equal (cdr (assq 'collapsed alist)) json-false))))
(ert-deftest ein:cell-to-json-text ()
(let* ((input (ein:join-str "\n" '("first input" "second input")))
(data (list :cell_type "text" :source input))
@ -146,16 +119,6 @@
(should (equal (cdr (assq 'cell_type alist)) "raw"))
(should (equal (cdr (assq 'source alist)) "first input\nsecond input"))))
(ert-deftest ein:cell-to-json-heading ()
(let* ((input (ein:join-str "\n" '("first input" "second input")))
(data (list :cell_type "heading" :source input))
(cell (eintest:cell-from-json data))
(alist (eintest:cell-to-json cell input)))
(should (equal (cdr (assq 'cell_type alist)) "heading"))
(should (equal (cdr (assq 'source alist)) "first input\nsecond input"))
(should (equal (cdr (assq 'level alist)) 1))))
;;; ein:cell-convert/copy
(ert-deftest ein:cell-convert-code-to-markdown ()
@ -206,7 +169,7 @@
(should (equal (oref new :input) input))))
(ert-deftest ein:cell-copy-text-types ()
(cl-loop for cell-type in '("text" "html" "markdown" "raw" "heading")
(cl-loop for cell-type in '("text" "html" "markdown" "raw")
for cell-p = (intern (format "ein:%scell-p" cell-type))
do
(let* ((input (ein:join-str "\n" '("first input" "second input")))

View file

@ -86,7 +86,7 @@
(ein:kernel--handle-shell-reply kernel (json-encode packet))))
(defun eintest:kernel-fake-stream (kernel msg-id data)
(let* ((content (list :data data
(let* ((content (list :text data
:name "stdout"))
(packet (list :header (list :msg_type "stream")
:parent_header (list :msg_id msg-id)
@ -143,16 +143,11 @@ is not found."
(list (ein:testing-codecell-data "import numpy")
(ein:testing-markdowncell-data "*markdown* text")
(ein:testing-rawcell-data "`raw` cell text")
(ein:testing-htmlcell-data "<b>HTML</b> text")
(ein:testing-headingcell-data "Heading 1" 1)
(ein:testing-headingcell-data "Heading 2" 2)
(ein:testing-headingcell-data "Heading 3" 3)
(ein:testing-headingcell-data "Heading 4" 4)
(ein:testing-headingcell-data "Heading 5" 5)
(ein:testing-headingcell-data "Heading 6" 6)))
(ein:testing-htmlcell-data "<b>HTML</b> text")))
(should (ein:$notebook-p ein:%notebook%))
(should (equal (ein:$notebook-notebook-name ein:%notebook%) ein:testing-notebook-dummy-name))
(should (equal (ein:worksheet-ncells ein:%worksheet%) 10))
(should (equal (ein:$notebook-notebook-name ein:%notebook%)
ein:testing-notebook-dummy-name))
(should (equal (ein:worksheet-ncells ein:%worksheet%) 4))
(let ((cells (ein:worksheet-get-cells ein:%worksheet%)))
(should (ein:codecell-p (nth 0 cells)))
(should (ein:markdowncell-p (nth 1 cells)))
@ -161,16 +156,8 @@ is not found."
(should (equal (ein:cell-get-text (nth 0 cells)) "import numpy"))
(should (equal (ein:cell-get-text (nth 1 cells)) "*markdown* text"))
(should (equal (ein:cell-get-text (nth 2 cells)) "`raw` cell text"))
(should (equal (ein:cell-get-text (nth 3 cells)) "<b>HTML</b> text"))
(cl-loop for i from 4 to 9
for level from 1
for cell = (nth i cells)
do (should (ein:headingcell-p cell))
do (should (equal (ein:cell-get-text cell)
(format "Heading %s" level)))
do (should (= (oref cell :level) level))))))
(should (equal (ein:cell-get-text (nth 3 cells)) "<b>HTML</b> text")))))
;;; Destructor
(defvar ein:testing-notebook-del-args-log 'nolog)
@ -340,7 +327,6 @@ some text
(when (< (ein:$notebook-nbformat ein:%notebook%) 4)
;; toggle to heading
(call-interactively #'ein:worksheet-toggle-cell-type)
(should (ein:headingcell-p (ein:worksheet-get-current-cell)))
(should (looking-back "some text"))
;; toggle to code
(call-interactively #'ein:worksheet-toggle-cell-type)
@ -356,11 +342,11 @@ some text
(should (ein:codecell-p (ein:worksheet-get-current-cell)))
(should (slot-boundp (ein:worksheet-get-current-cell) :kernel))
(let ((check
(lambda (type &optional level)
(lambda (type)
(let ((cell-p (intern (format "ein:%scell-p" type)))
(cell (ein:worksheet-get-current-cell)))
(ein:worksheet-change-cell-type ein:%worksheet% cell
type level t)
type t)
(let ((new (ein:worksheet-get-current-cell)))
(should-not (eq new cell))
(should (funcall cell-p new)))
@ -368,9 +354,6 @@ some text
;; change type: code (no change) -> markdown -> raw
(cl-loop for type in '("code" "markdown" "raw")
do (funcall check type))
;; change level: 1 to 6
(cl-loop for level from 1 to 6
do (funcall check "heading" level))
;; back to code
(funcall check "code")
(should (slot-boundp (ein:worksheet-get-current-cell) :kernel)))))

View file

@ -21,7 +21,7 @@
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(ein:notification-status-set kernel
'status_busy.Kernel)
(should (string-prefix-p "IP[y]: Kernel is busy... | /1\\ /2\\ /3\\ [+]"
(should (string-prefix-p "IP[y]: Kernel busy... | /1\\ /2\\ /3\\ [+]"
(ein:header-line)))))
(ert-deftest ein:header-line-notebook-status-busy ()
@ -30,7 +30,7 @@
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(ein:notification-status-set notebook
'notebook_saved.Notebook)
(should (string-prefix-p "IP[y]: Notebook is saved | /1\\ /2\\ /3\\ [+]"
(should (string-prefix-p "IP[y]: Notebook saved | /1\\ /2\\ /3\\ [+]"
(ein:header-line)))))
(ert-deftest ein:header-line-notebook-complex ()
@ -43,7 +43,7 @@
(ein:notification-status-set notebook
'notebook_saving.Notebook)
(should (string-prefix-p
(concat "IP[y]: Saving Notebook... | "
(concat "IP[y]: Saving notebook... | "
(substitute-command-keys "Kernel requires restart \\<ein:notebook-mode-map>\\[ein:notebook-restart-session-command-km] | ")
;;"Kernel requires restart C-c C-x C-r | "
"/1\\ /2\\ /3\\ [+]") (ein:header-line)))))

View file

@ -7,12 +7,10 @@
(list (ein:testing-codecell-data "code example input")
(ein:testing-markdowncell-data "markdown example input")
(ein:testing-rawcell-data "raw example input")
(ein:testing-htmlcell-data "html example input")
(ein:testing-headingcell-data "heading example input")))
(ein:testing-htmlcell-data "html example input")))
(defun ein:testing-worksheet-new ()
(make-instance 'ein:worksheet
:discard-output-p (cons #'ignore nil)))
(make-instance 'ein:worksheet))
(defun ein:testing-worksheet-to-json (cells &optional metadata)
(let* ((ws-0 (ein:worksheet-from-json (ein:testing-worksheet-new)