test undo in combination with worksheet-execute-all-cells

This commit is contained in:
dickmao 2020-02-08 17:35:49 -05:00
parent b478940c9f
commit caa760f9d7
8 changed files with 103 additions and 227 deletions

View file

@ -29,11 +29,12 @@ README.rst: README.in.rst lisp/ein-notebook.el
(describe-minor-mode \"ein:notebook-mode\") \
(with-current-buffer \"*Help*\" (princ (buffer-string))))" 2>/dev/null \
| tools/readme-sed.sh "KEYS NOTEBOOK" README.in.rst "key.*binding" > README.rst0
perl -ne "s/^(\s*)\S+.*CI VERSION.*$$/\$${1}$(TEST_VERSION)/; print" README.rst0 > README.rst1
perl -ne "s/^((\s*)C-c C-c(\s+).*)$$/\$${1}\n\$${2}C-u C-c C-c \$${3}ein:worksheet-execute-all-cells/; print" README.rst0 > README.rst1
perl -ne "s/^(\s*)\S+.*CI VERSION.*$$/\$${1}$(TEST_VERSION)/; print" README.rst1 > README.rst0
grep ';;' lisp/ein.el \
| awk '/;;;\s*Commentary/{within=1;next}/;;;\s*/{within=0}within' \
| sed -e 's/^\s*;;*\s*//g' \
| tools/readme-sed.sh "COMMENTARY" README.rst1 > README.rst
| tools/readme-sed.sh "COMMENTARY" README.rst0 > README.rst
rm README.rst0 README.rst1
.PHONY: autoloads

View file

@ -142,8 +142,8 @@ Keymap (C-h m)
<C-down> ein:worksheet-goto-next-input-km
<C-up> ein:worksheet-goto-prev-input-km
<M-S-return> ein:worksheet-execute-cell-and-insert-below-km
<M-down> ein:worksheet-move-cell-down-km
<M-up> ein:worksheet-move-cell-up-km
<M-down> ein:worksheet-not-move-cell-down-km
<M-up> ein:worksheet-not-move-cell-up-km
C-x C-s ein:notebook-save-notebook-command-km
C-x C-w ein:notebook-rename-command-km
@ -155,6 +155,7 @@ Keymap (C-h m)
C-c C-a ein:worksheet-insert-cell-above-km
C-c C-b ein:worksheet-insert-cell-below-km
C-c C-c ein:worksheet-execute-cell-km
C-u C-c C-c ein:worksheet-execute-all-cells
C-c C-e ein:worksheet-toggle-output-km
C-c C-f ein:file-open-km
C-c C-h ein:pytools-request-help-km
@ -192,7 +193,6 @@ Keymap (C-h m)
C-c C-S-l ein:worksheet-clear-all-output-km
C-c C-# ein:notebook-close-km
C-c C-$ ein:tb-show-km
C-c C-' ein:worksheet-turn-on-autoexec-km
C-c C-/ ein:notebook-scratchsheet-open-km
C-c C-; ein:shared-output-show-code-cell-at-point-km
C-c <down> ein:worksheet-move-cell-down-km

View file

@ -223,6 +223,36 @@ Scenario: Undo needs to at least work for reopened notebooks
And I undo again
Then the cursor should be at point "124"
@undo
Scenario: Execute all cells, mod some cells, get outputs, undo mods
Given I enable "ein:worksheet-enable-undo"
Given new python notebook
When I type "from time import sleep"
And I press "RET"
And I type "sleep(3)"
And I press "C-c C-b"
And I type "sleep(1)"
And I press "RET"
And I type "import math"
And I press "RET"
And I type "2*math.asin(1)"
And I press "C-c C-b"
And I press "C-c C-t"
And I type "mark"
And I call "ein:worksheet-execute-all-cells-above"
And I press "C-c C-b"
And I type "undo"
And I press "C-<up>"
And I press "C-<up>"
And I type "surprise"
And I wait for buffer to say "3.14159"
And I press "C-/"
Then the cursor should be at point "51"
And I undo again
Then the cursor should be at point "139"
And I undo again
Then the cursor should be at point "125"
@undo
Scenario: Toggling between markdown and codecell does not break undo
Given I enable "ein:worksheet-enable-undo"
@ -244,112 +274,3 @@ Scenario: Toggling between markdown and codecell does not break undo
And I wait for cell to execute
And I press "C-/"
Then the cursor should be at point "62"
@timestamp
Scenario: Undo (kind of) needs to work when someone explicitly requires ein-timestamp
Given I start the server configured "\n"
Given I enable "ein:worksheet-enable-undo"
Given old notebook "undo.ipynb"
And I type "howdy"
And I press "RET"
And I press "C-<down>"
And I press "C-<down>"
And I type "rowdy"
And I press "RET"
And I press "C-<up>"
And I press "C-<up>"
And I press "C-c C-k"
And I type "bowdy"
And I press "RET"
And I press "C-c C-y"
And I press "C-/"
Then the cursor should be at point "15"
And I press "C-/"
And I press "C-n"
And I press "C-n"
And I press "C-c C-s"
And I press "C-/"
And I undo again
And I undo again
And I undo again
And I undo again
Then the cursor should be at point "20"
And I undo again
Then the cursor should be at point "88"
And I press "C-<down>"
And I press "C-k"
And I press "C-k"
And I press "C-k"
And I type "1.618"
And I wait for cell to execute
And I press "C-<up>"
And I press "C-c C-m"
And I press "C-n"
And I press "C-n"
And I press "C-c C-s"
And I press "C-/"
And I undo again
And I undo again
And I undo again
Then the cursor should be at point "124"
@timestamp
Scenario: Kill yank doesn't break undo
Given I enable "ein:worksheet-enable-undo"
Given new python notebook
When I type "import math"
And I press "M-RET"
And I type "[i for i in [1,2]]"
And I press "M-RET"
And I type "math.log(math.exp(1.0))"
And I wait for cell to execute
And I press "C-<up>"
And I press "C-<up>"
And I press "C-c C-k"
And I press "C-<down>"
And I press "C-c C-y"
And I press "C-/"
Then the cursor should be at point "117"
@timestamp
Scenario: Split and merge don't break undo
Given I enable "ein:worksheet-enable-undo"
Given new python notebook
When I type "print("hello")"
And I press "C-c C-b"
And I type "1111"
And I press "RET"
And I press "RET"
And I press "RET"
And I type "2222"
And I press "RET"
And I type "3333"
And I press "C-c C-b"
And I type "4444"
And I press "C-<up>"
And I press "C-n"
And I press "C-c C-s"
And I wait for cell to execute
And I press "C-<up>"
And I wait for cell to execute
And I press "C-<up>"
And I wait for cell to execute
And I press "C-/"
And I press "C-<up>"
And I type "5555"
And I press "RET"
And I type "6666"
And I wait for cell to execute
And I press "C-/"
And I undo again
And I undo again
And I undo again
And I undo again
Then the cursor should be at point "156"
And I press "C-c C-m"
And I press "C-c C-m"
And I press "C-/"
And I undo again
And I undo again
And I undo again
Then the cursor should be at point "93"

View file

@ -151,12 +151,6 @@ To view full output, use `ein:notebook-show-in-shared-output'."
(const :tag "Show all traceback" nil))
:group 'ein)
(defcustom ein:cell-autoexec-prompt ""
"String shown in the cell prompt when the auto-execution flag
is on."
:type 'string
:group 'ein)
(defcustom ein:truncate-long-cell-output nil
"When nil do not truncate cells with long outputs. When set to
a number will limit the number of lines in a cell output."
@ -471,9 +465,7 @@ Return language name as a string or `nil' when not defined.
Called from ewoc pretty printer via `ein:cell-pp'."
;; Newline is inserted in `ein:cell-insert-input'.
(ein:insert-read-only
(concat
(format "In [%s]:" (or (ein:oref-safe cell 'input-prompt-number) " "))
(when (slot-value cell 'autoexec) " %s" ein:cell-autoexec-prompt))
'font-lock-face 'ein:cell-input-prompt))
(cl-defmethod ein:cell-insert-prompt ((cell ein:textcell))
@ -661,25 +653,6 @@ Return language name as a string or `nil' when not defined.
(setf (slot-value cell 'input-prompt-number) number)
(ein:cell-invalidate-prompt cell))
(cl-defmethod ein:cell-set-autoexec ((cell ein:codecell) bool)
"Set auto-execution flag of CELL to BOOL and invalidate the
prompt EWOC node."
(setf (slot-value cell 'autoexec) bool)
(ein:cell-invalidate-prompt cell))
(cl-defmethod ein:cell-autoexec-p ((cell ein:basecell))
"Auto-execution flag set to CELL.
Return `nil' always for non-code cells."
nil)
(cl-defmethod ein:cell-autoexec-p ((cell ein:codecell))
(slot-value cell 'autoexec))
(cl-defmethod ein:cell-toggle-autoexec ((cell ein:codecell))
"Toggle auto-execution flag of CELL to BOOL and invalidate the
prompt EWOC node."
(ein:cell-set-autoexec cell (not (ein:cell-autoexec-p cell))))
(cl-defmethod ein:cell-goto ((cell ein:basecell) &optional relpos prop)
"Go to the input area of the given CELL.
RELPOS is the position relative to the input area. Default is 0.

View file

@ -260,13 +260,7 @@ Implementation note:
Typed `:input-prompt-number' becomes a problem when reading a
notebook that saved "*". So don't add `:type'!")
(collapsed :initarg :collapsed :initform nil :type boolean)
(running :initarg :running :initform nil :type boolean)
(autoexec :initarg :autoexec :initform nil :type boolean
:documentation "Auto-execution flag.
This cell is executed when the connected buffer is saved,
provided that (1) this flag is `t' and (2) corresponding
auto-execution mode flag in the connected buffer is `t'.")))
(running :initarg :running :initform nil :type boolean)))
(defclass ein:textcell (ein:basecell)
((cell-type :initarg :cell-type :initform "text")

View file

@ -461,14 +461,6 @@ This is equivalent to do ``C-c`` in the console program."
(interactive)
(ein:kernel-interrupt (ein:$notebook-kernel ein:%notebook%)))
;; autoexec
(defun ein:notebook-execute-autoexec-cells (notebook)
"Execute cells of which auto-execution flag is on."
(interactive (list (or ein:%notebook% (error "Not in notebook buffer!"))))
(mapc #'ein:worksheet-execute-autoexec-cells
(ein:$notebook-worksheets notebook)))
(define-obsolete-function-alias
'ein:notebook-eval-string
'ein:shared-output-eval-string "0.1.2")
@ -1169,7 +1161,6 @@ Tried add-function: the &rest from :around is an emacs-25 compilation issue."
(ein:notebook--define-key map (kbd "M-RET") ein:worksheet-execute-cell-and-goto-next)
(ein:notebook--define-key map (kbd "<M-S-return>")
ein:worksheet-execute-cell-and-insert-below)
(ein:notebook--define-key map (kbd "C-c C-'") ein:worksheet-turn-on-autoexec)
(ein:notebook--define-key map "\C-c\C-e" ein:worksheet-toggle-output)
(ein:notebook--define-key map "\C-c\C-v" ein:worksheet-set-output-visibility-all)
(ein:notebook--define-key map "\C-c\C-l" ein:worksheet-clear-output)
@ -1191,8 +1182,8 @@ Tried add-function: the &rest from :around is an emacs-25 compilation issue."
(ein:notebook--define-key map (kbd "C-<down>") ein:worksheet-goto-next-input)
(ein:notebook--define-key map (kbd "C-c <up>") ein:worksheet-move-cell-up)
(ein:notebook--define-key map (kbd "C-c <down>") ein:worksheet-move-cell-down)
(ein:notebook--define-key map (kbd "M-<up>") ein:worksheet-move-cell-up)
(ein:notebook--define-key map (kbd "M-<down>") ein:worksheet-move-cell-down)
(ein:notebook--define-key map (kbd "M-<up>") ein:worksheet-not-move-cell-up)
(ein:notebook--define-key map (kbd "M-<down>") ein:worksheet-not-move-cell-down)
(ein:notebook--define-key map "\C-c\C-h" ein:pytools-request-help)
(ein:notebook--define-key map (kbd "C-c C-$") ein:tb-show)
(ein:notebook--define-key map "\C-c\C-x" nil)

View file

@ -56,9 +56,7 @@
Called from ewoc pretty printer via `ein:cell-pp'."
;; Newline is inserted in `ein:cell-insert-input'.
(ein:insert-read-only
(concat
(format "In [%s]" (or (ein:oref-safe cell 'input-prompt-number) " "))
(when (slot-value cell 'autoexec) " %s" ein:cell-autoexec-prompt))
'font-lock-face 'ein:cell-input-prompt))
(cl-defmethod ein:cell-execute ((cell ein:shared-output-cell) kernel code

View file

@ -33,6 +33,7 @@
(require 'ein-utils)
(require 'ein-cell)
(require 'ein-kill-ring)
(require 'warnings)
(require 'poly-ein)
;;; Configuration
@ -40,6 +41,11 @@
;; (define-obsolete-variable-alias
;; 'ein:notebook-enable-undo 'ein:worksheet-enable-undo "0.2.0")
(defcustom ein:worksheet-warn-obsolesced-keybinding t
"Warn of keybindings we arbitrarily obsolesce."
:type 'boolean
:group 'ein)
(defcustom ein:worksheet-enable-undo t
"When non-`nil', allow undo of cell inputs only (as opposed to
whole-cell operations such as killing, moving, executing cells).
@ -948,6 +954,26 @@ It is set in `ein:notebook-multilang-mode'."
(poly-ein-fontify-buffer (ein:worksheet--get-buffer ein:%worksheet%))))
(message "No %s cell" (if up "previous" "next"))))
(defun ein:worksheet-not-move-cell (which)
(when ein:worksheet-warn-obsolesced-keybinding
(ein:display-warning-once
(mapconcat #'identity
'("M-<up> and M-<down> no longer move cells."
"Use C-c <up> and C-c <down>."
"Custom set variable `ein:worksheet-warn-obsolesced-keybinding' to disable this warning.") "\n")
warning-minimum-level))
(call-interactively (cl-some #'identity
(mapcar (lambda (pair) (lookup-key (cdr pair) which))
(cdr minor-mode-map-alist)))))
(defun ein:worksheet-not-move-cell-up (&rest _args)
(interactive)
(ein:worksheet-not-move-cell (kbd "M-<up>")))
(defun ein:worksheet-not-move-cell-down (&rest _args)
(interactive)
(ein:worksheet-not-move-cell (kbd "M-<down>")))
(defun ein:worksheet-move-cell-up (ws cell)
(interactive (list (ein:worksheet--get-ws-or-error)
(ein:worksheet-get-current-cell)))
@ -1021,18 +1047,24 @@ Do not clear input prompts when the prefix argument is given."
(mapc (lambda (cell) (setf (slot-value cell 'kernel) (slot-value ws 'kernel)))
(seq-filter #'ein:codecell-p (ein:worksheet-get-cells ws))))
(defun ein:worksheet-execute-cell (ws cell)
(defun ein:worksheet-execute-cell (ws cell &optional batch)
"Execute code type CELL."
(interactive (list (ein:worksheet--get-ws-or-error)
(ein:worksheet-get-current-cell
:cell-p #'ein:codecell-p)))
(interactive `(,(ein:worksheet--get-ws-or-error)
,(ein:worksheet-get-current-cell)
,(when current-prefix-arg
(prog1 (read-char-choice "[RET]all [a]bove [b]elow: " (list ?\r ?a ?b))
(message "")))))
(ein:kernel-when-ready (slot-value ws 'kernel)
(apply-partially
(lambda (ws* cell* kernel)
(ein:cell-execute cell*)
(lambda (ws* cell* batch* _kernel)
(cl-case batch*
(?\r (ein:worksheet-execute-all-cells ws*))
(?a (ein:worksheet-execute-all-cells ws* :above cell*))
(?b (ein:worksheet-execute-all-cells ws* :below cell*))
(t (ein:cell-execute cell*)
(oset ws* :dirty t)
(ein:worksheet--unshift-undo-list cell*))
ws cell))
(ein:worksheet--unshift-undo-list cell*))))
ws cell batch))
cell)
(defun ein:worksheet-execute-cell-and-goto-next (ws cell &optional insert)
@ -1060,13 +1092,16 @@ cell bellow."
"Execute all cells in the current worksheet buffer.
If :above or :below specified, execute above/below the current cell."
(interactive (list (ein:worksheet--get-ws-or-error)))
(let* ((all (seq-filter #'ein:codecell-p (ein:worksheet-get-cells ws)))
(current-id (aif (ein:worksheet-get-current-cell) (slot-value it 'cell-id)))
(not-matching (apply-partially (lambda (my other)
(let ((all (ein:worksheet-get-cells ws)))
(mapc (apply-partially #'ein:worksheet-execute-cell ws)
(seq-filter
#'ein:codecell-p
(aif (or above below)
(-when-let* ((current-id (slot-value it 'cell-id))
(not-matching (apply-partially
(lambda (my other)
(not (string= (slot-value other 'cell-id) my)))
current-id)))
(mapc #'ein:cell-execute
(if (or above below)
(append (when (and current-id above)
(aif (seq-take-while not-matching all)
it
@ -1074,20 +1109,20 @@ If :above or :below specified, execute above/below the current cell."
(ein:log 'info
"ein:worksheet-execute-all-cells: no cells above current"))))
(when (and current-id below)
(seq-drop-while not-matching all)))
all))))
(seq-drop-while not-matching all))))
all)))))
(defun ein:worksheet-execute-all-cells-above (ws)
"Execute all cells above the current cell (exclusively) in the
current worksheet buffer."
(interactive (list (ein:worksheet--get-ws-or-error)))
(ein:worksheet-execute-all-cells ws :above t))
(ein:worksheet-execute-all-cells ws :above (ein:worksheet-get-current-cell)))
(defun ein:worksheet-execute-all-cells-below (ws)
"Execute all cells below the current cell (inclusively) in the
current worksheet buffer."
(interactive (list (ein:worksheet--get-ws-or-error)))
(ein:worksheet-execute-all-cells ws :below t))
(ein:worksheet-execute-all-cells ws :below (ein:worksheet-get-current-cell)))
;;; Metadata
@ -1144,43 +1179,6 @@ current worksheet buffer."
(indent-rigidly
beg end (- (ein:find-leftmost-column beg end)))))
;;; Auto-execution
(defun ein:worksheet-toggle-autoexec (cell)
"Toggle auto-execution flag of the cell at point."
(interactive (list (ein:worksheet-get-current-cell #'ein:codecell-p)))
(ein:cell-toggle-autoexec cell))
(defun ein:worksheet-turn-on-autoexec (cells &optional off)
"Turn on auto-execution flag of the cells in region or cell at point.
When the prefix argument is given, turn off the flag instead. Questionable."
(interactive
(list (ein:worksheet-get-cells-in-region-or-at-point
:cell-p #'ein:codecell-p)
current-prefix-arg))
(mapc (lambda (c) (ein:cell-set-autoexec c (not off))) cells)
(ein:log 'info "Turn %s auto-execution flag of %s cells."
(if off "off" "on")
(length cells)))
(defun ein:worksheet-execute-autoexec-cells (ws)
"Execute cells of which auto-execution flag is on.
This function internally sets current buffer to the worksheet
buffer, so you don't need to set current buffer to call this
function."
(interactive (list (ein:worksheet--get-ws-or-error)))
(ein:with-live-buffer (ein:worksheet-buffer ws)
(ein:kernel-when-ready
(slot-value ws 'kernel)
(apply-partially
(lambda (ws buffer kernel)
(with-current-buffer buffer
(let ((buffer-undo-list t))
(mapc #'ein:cell-execute
(seq-filter #'ein:cell-autoexec-p
(ein:worksheet-get-cells ws))))))
ws (current-buffer)))))
;;; Workarounds
(defadvice fill-paragraph (around ein:worksheet-fill-paragraph activate)