diff --git a/README.in.rst b/README.in.rst index f7ae4ec..3d1a915 100644 --- a/README.in.rst +++ b/README.in.rst @@ -70,7 +70,6 @@ How do I... ... display images inline? We find inserting images into emacs disruptive, and so default to spawning an external viewer. To override this, - :: M-x customize-group RET ein @@ -85,11 +84,18 @@ How do I... ... get IDE-like behavior? The official python module for EIN is elpy_, installed separately. Other `program modes`_ for non-python kernels may be installed with varying degrees of EIN compatibility. +... undo? + Cell-level actions like ``C-c C-b`` cannot be undone. + Undo's whilst a cell continues receiving output will actually *redo* the last action. This is due to "`undo boundaries`_" being inserted by the receiving cell, a known EIN bug. + Undo's will not work under ``undo-tree-mode``, a default mode for Doom and Spacemacs, and other packages employing ``evil-mode``. + .. _spacemacs layer: https://github.com/syl20bnr/spacemacs/tree/master/layers/%2Blang/ipython-notebook .. _company-mode: https://github.com/company-mode/company-mode .. _jupyterhub: https://github.com/jupyterhub/jupyterhub .. _elpy: https://melpa.org/#/elpy .. _program modes: https://www.gnu.org/software/emacs/manual/html_node/emacs/Program-Modes.html +.. _undo boundaries: https://www.gnu.org/software/emacs/manual/html_node/elisp/Undo.html + ob-ein ====== Configuration: diff --git a/README.rst b/README.rst index c1b79a7..2224d98 100644 --- a/README.rst +++ b/README.rst @@ -6,8 +6,6 @@ Emacs IPython Notebook (EIN) lets you run Jupyter (formerly IPython) notebooks within Emacs. It channels all the power of Emacs without the idiosyncrasies of in-browser editing. -EIN is not tested on Doom or Spacemacs. There are known issues with both. - Org_ users please find ob-ein_, a jupyter Babel_ backend. EIN was originally written by `[tkf]`_. A jupyter Babel_ backend was first @@ -79,7 +77,6 @@ How do I... ... display images inline? We find inserting images into emacs disruptive, and so default to spawning an external viewer. To override this, - :: M-x customize-group RET ein @@ -94,11 +91,18 @@ How do I... ... get IDE-like behavior? The official python module for EIN is elpy_, installed separately. Other `program modes`_ for non-python kernels may be installed with varying degrees of EIN compatibility. +... undo? + Cell-level actions like ``C-c C-b`` cannot be undone. + Undo's whilst a cell continues receiving output will actually *redo* the last action. This is due to "`undo boundaries`_" being inserted by the receiving cell, a known EIN bug. + Undo's will not work under ``undo-tree-mode``, a default mode for Doom and Spacemacs, and other packages employing ``evil-mode``. + .. _spacemacs layer: https://github.com/syl20bnr/spacemacs/tree/master/layers/%2Blang/ipython-notebook .. _company-mode: https://github.com/company-mode/company-mode .. _jupyterhub: https://github.com/jupyterhub/jupyterhub .. _elpy: https://melpa.org/#/elpy .. _program modes: https://www.gnu.org/software/emacs/manual/html_node/emacs/Program-Modes.html +.. _undo boundaries: https://www.gnu.org/software/emacs/manual/html_node/elisp/Undo.html + ob-ein ====== Configuration: diff --git a/lisp/ein-cell.el b/lisp/ein-cell.el index 6774bc3..ac74ea1 100644 --- a/lisp/ein-cell.el +++ b/lisp/ein-cell.el @@ -72,8 +72,7 @@ (ewoc--node-right node) nil))))) (defun ein:cell--ewoc-invalidate (ewoc &rest nodes) - "Call EWOC's pretty-printer for each element in NODES. -Delete current text first, thus effecting a \"refresh\"." + "Call EWOC's pretty-printer (`ein:worksheet-pp') for each element in NODES." (ewoc--set-buffer-bind-dll-let* ewoc ((pp (ewoc--pretty-printer ewoc))) (save-excursion @@ -792,9 +791,7 @@ If END is non-`nil', return the location of next element." (ein:cell-expand cell) (setf (slot-value cell 'outputs) (append (slot-value cell 'outputs) (list json))) - (let* ((inhibit-read-only t) - (buffer-undo-list t) - (ewoc (slot-value cell 'ewoc)) + (let* ((ewoc (slot-value cell 'ewoc)) (index (1- (ein:cell-num-outputs cell))) (path `(cell output ,index)) (class (ein:cell-output-json-to-class json)) @@ -838,9 +835,7 @@ Called from ewoc pretty printer via `ein:cell-insert-output'." (cl-defmethod ein:cell-append-stream ((cell ein:codecell) json) "Insert stream type output in the buffer. -Called from ewoc pretty printer via `ein:cell-insert-output'." - ;; (unless (plist-get json :stream) - ;; (plist-put json :stream "stdout")) +Called from ewoc pretty printer `ein:worksheet-pp'." (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 @@ -984,9 +979,9 @@ Called from ewoc pretty printer via `ein:cell-insert-output'." (cl-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) + :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))) (cl-defmethod ein:cell--handle-execute-reply ((cell ein:codecell) content metadata) @@ -1035,11 +1030,7 @@ Called from ewoc pretty printer via `ein:cell-insert-output'." (cl-defmethod ein:cell--handle-clear-output ((cell ein:codecell) content _metadata) "Jupyter messaging spec 5.0 no longer has stdout, stderr, or other fields for clear_output" - (ein:cell-clear-output cell - t ;;(plist-get content :stdout) - t ;;(plist-get content :stderr) - t ;;(plist-get content :other)) - ) + (ein:cell-clear-output cell t t t) (ein:events-trigger (slot-value cell 'events) 'maybe_reset_undo.Worksheet cell)) (cl-defmethod ein:cell-has-image-output-p ((cell ein:codecell)) diff --git a/lisp/ein-utils.el b/lisp/ein-utils.el index 8df24bf..a0acf2a 100644 --- a/lisp/ein-utils.el +++ b/lisp/ein-utils.el @@ -297,13 +297,12 @@ See: http://api.jquery.com/jQuery.ajax/" (apply #'propertize string 'read-only t 'front-sticky t properties)) (defun ein:insert-read-only (string &rest properties) - (let ((buffer-undo-list t)) + (let ((buffer-undo-list t) + (start (point))) (insert (apply #'ein:propertize-read-only (ein:maybe-truncate-string-lines string ein:truncate-long-cell-output) - properties)))) - - -;;; String manipulation + properties)) + (comint-carriage-motion start (point)))) (defun ein:maybe-truncate-string-lines (string nlines) "Truncate multi-line `string' to the number of lines specified by `nlines'. If actual diff --git a/lisp/ein-worksheet.el b/lisp/ein-worksheet.el index 3c081b0..329d7c7 100644 --- a/lisp/ein-worksheet.el +++ b/lisp/ein-worksheet.el @@ -173,38 +173,39 @@ Normalize `buffer-undo-list' by removing extraneous details, and update the ein: (defun ein:worksheet--jigger-undo-list (&optional change-cell-id) (cl-assert (listp buffer-undo-list)) - (if (/= (length buffer-undo-list) (length ein:%which-cell%)) - (ein:log 'debug "jig %s to %s: %S %S" (length ein:%which-cell%) (length buffer-undo-list) buffer-undo-list ein:%which-cell%)) - (ein:and-let* ((old-cell-id (car change-cell-id)) - (new-cell-id (cdr change-cell-id)) - (changed-p (not (eq old-cell-id new-cell-id)))) + (when (/= (length buffer-undo-list) (length ein:%which-cell%)) + (ein:log 'debug "jig %s to %s: %S %S" + (length ein:%which-cell%) (length buffer-undo-list) + buffer-undo-list ein:%which-cell%)) + (-when-let* ((old-cell-id (car change-cell-id)) + (new-cell-id (cdr change-cell-id)) + (changed-p (not (eq old-cell-id new-cell-id)))) (setq ein:%which-cell% (-replace old-cell-id new-cell-id ein:%which-cell%))) (let ((fill (- (length buffer-undo-list) (length ein:%which-cell%)))) - (if (> (abs fill) 1) - (progn - (let ((msg (format "Undo failure diagnostic %s %s | %s" - buffer-undo-list ein:%which-cell% fill)) - (pm-allow-post-command-hook nil)) - (setq ein:worksheet-enable-undo nil) - (ein:worksheet-undo-setup ein:%worksheet%) - (when pm/polymode - (dolist (b (eieio-oref pm/polymode '-buffers)) - (when (buffer-live-p b) - (poly-ein-copy-state (ein:worksheet--get-buffer ein:%worksheet%) b)))) - (ein:display-warning msg :error) - (error "ein:worksheet--jigger-undo-list: aborting"))) - (if (< fill 0) - (setq ein:%which-cell% (nthcdr (- fill) ein:%which-cell%)) - (if (> fill 0) - (setq ein:%which-cell% - (nconc (make-list fill (car ein:%which-cell%)) - ein:%which-cell%)))))) + (cond ((> (abs fill) 1) + (let ((msg (format "Undo failure diagnostic %s %s | %s" + buffer-undo-list ein:%which-cell% fill)) + (pm-allow-post-command-hook nil)) + (setq ein:worksheet-enable-undo nil) + (ein:worksheet-undo-setup ein:%worksheet%) + (when pm/polymode + (dolist (b (eieio-oref pm/polymode '-buffers)) + (when (buffer-live-p b) + (poly-ein-copy-state (ein:worksheet--get-buffer ein:%worksheet%) b)))) + (ein:display-warning msg :error) + (error "ein:worksheet--jigger-undo-list: aborting"))) + ((< fill 0) + (setq ein:%which-cell% (nthcdr (- fill) ein:%which-cell%))) + ((> fill 0) + (setq ein:%which-cell% (nconc (make-list fill (car ein:%which-cell%)) + ein:%which-cell%))))) (cl-assert (= (length buffer-undo-list) (length ein:%which-cell%)) t "ein:worksheet--jigger-undo-list %d != %d" (length buffer-undo-list) (length ein:%which-cell%))) (defun ein:worksheet--unshift-undo-list (cell &optional exogenous-input old-cell) - "Adjust `buffer-undo-list' for adding CELL. Unshift in list parlance means prepending to list." + "Adjust `buffer-undo-list' for adding CELL. +Unshift in list parlance means prepending to list." (unless old-cell (setq old-cell cell)) (when buffer-local-enable-undo @@ -453,14 +454,13 @@ Normalize `buffer-undo-list' by removing extraneous details, and update the ein: (ein:log 'info "Worksheet %s is ready" (ein:worksheet-full-name ws)))) (defun ein:worksheet-pp (ewoc-data) + "Consider disabling `buffer-undo-list' here instead of `ein:cell--ewoc-invalidate' +which is probably unnecessarily 'surgical'." (let ((path (ein:$node-path ewoc-data)) (data (ein:$node-data ewoc-data))) (case (car path) (cell (ein:cell-pp (cdr path) data))))) - -;;; Persistance and loading - (cl-defmethod ein:worksheet-from-json ((ws ein:worksheet) data) (destructuring-bind (&key cells metadata &allow-other-keys) data (setf (slot-value ws 'metadata) metadata) diff --git a/lisp/ein.el b/lisp/ein.el index cd835ad..ebf4a14 100644 --- a/lisp/ein.el +++ b/lisp/ein.el @@ -29,8 +29,6 @@ ;; notebooks within Emacs. It channels all the power of Emacs without the ;; idiosyncrasies of in-browser editing. ;; -;; EIN is not tested on Doom or Spacemacs. There are known issues with both. -;; ;; Org_ users please find ob-ein_, a jupyter Babel_ backend. ;; ;; EIN was originally written by `[tkf]`_. A jupyter Babel_ backend was first