Merge branch 'worksheet-move'

* Add commands ein:notebook-worksheet-move-prev/next
  to reorder worksheet list.

* Simple tab is added to header-line.
This commit is contained in:
Takafumi Arakaki 2012-09-02 06:35:38 +02:00
commit ad333957c9
5 changed files with 169 additions and 11 deletions

View file

@ -474,7 +474,12 @@ This is equivalent to do ``C-c`` in the console program."
(with-current-buffer (ein:worksheet-buffer ws)
(ein:notebook-mode)
;; Now that major-mode is set, set buffer local variables:
(ein:notification-setup (current-buffer) (ein:$notebook-events notebook))
(ein:notification-setup
(current-buffer)
(ein:$notebook-events notebook)
(lambda () (ein:$notebook-worksheets ein:%notebook%))
(lambda () ein:%worksheet%)
#'ein:worksheet-name)
(ein:notebook-setup-kill-buffer-hook)
(setq ein:%notebook% notebook)))
@ -823,6 +828,22 @@ When used as a lisp function, delete worksheet WS from NOTEBOOk."
(let ((ein:notebook-kill-buffer-ask nil))
(kill-buffer (ein:worksheet-buffer ws))))
(defun ein:notebook-worksheet-move-prev (notebook ws)
"Switch the current worksheet with the previous one."
(interactive (list (ein:notebook--get-nb-or-error)
(ein:worksheet--get-ws-or-error)))
(assert (ein:worksheet-p ws) nil "Not worksheet.")
(setf (ein:$notebook-worksheets notebook)
(ein:list-move-left (ein:$notebook-worksheets notebook) ws)))
(defun ein:notebook-worksheet-move-next (notebook ws)
"Switch the current worksheet with the previous one."
(interactive (list (ein:notebook--get-nb-or-error)
(ein:worksheet--get-ws-or-error)))
(assert (ein:worksheet-p ws) nil "Not worksheet.")
(setf (ein:$notebook-worksheets notebook)
(ein:list-move-right (ein:$notebook-worksheets notebook) ws)))
;;; Scratch sheet
@ -1008,6 +1029,8 @@ Do not use `python-mode'. Use plain mode when MuMaMo is not installed::
(define-key map (kbd "C-c !") 'ein:worksheet-rename-sheet)
(define-key map (kbd "C-c {") 'ein:notebook-worksheet-open-prev-or-last)
(define-key map (kbd "C-c }") 'ein:notebook-worksheet-open-next-or-first)
(define-key map (kbd "C-c M-{") 'ein:notebook-worksheet-move-prev)
(define-key map (kbd "C-c M-}") 'ein:notebook-worksheet-move-next)
(define-key map (kbd "C-c +") 'ein:notebook-worksheet-insert-next)
(define-key map (kbd "C-c M-+") 'ein:notebook-worksheet-insert-prev)
(define-key map (kbd "C-c -") 'ein:notebook-worksheet-delete)
@ -1092,6 +1115,8 @@ Do not use `python-mode'. Use plain mode when MuMaMo is not installed::
("Insert previous worksheet"
ein:notebook-worksheet-insert-prev)
("Delete worksheet" ein:notebook-worksheet-delete)
("Move worksheet left" ein:notebook-worksheet-move-prev)
("Move worksheet right" ein:notebook-worksheet-move-next)
))
"---"
,@(ein:generate-menu

View file

@ -47,8 +47,14 @@
(s2m :initarg :s2m))
"Hold status and it's string representation (message).")
(defclass ein:notification-tab ()
((get-list :initarg :get-list :type function)
(get-current :initarg :get-current :type function)
(get-name :initarg :get-name :type function)))
(defclass ein:notification ()
((buffer :initarg :buffer :type buffer :document "Notebook buffer")
(tab :initarg :tab :type ein:notification-tab)
(notebook
:initarg :notebook
:initform
@ -90,6 +96,13 @@ where NS is `:kernel' or `:notebook' slot of NOTIFICATION."
st ; = event-type
#'ein:notification--callback
(cons ns st))))
(ein:events-on events
'notebook_saved.Notebook
#'ein:notification--fadeout-callback
(list (oref notification :notebook)
"Notebook is saved"
'notebook_saved.Notebook
nil))
(ein:events-on events
'status_restarting.Kernel
#'ein:notification--fadeout-callback
@ -104,6 +117,8 @@ where NS is `:kernel' or `:notebook' slot of NOTIFICATION."
(ein:notification-status-set ns status)))
(defun ein:notification--fadeout-callback (packed data)
;; FIXME: I can simplify this.
;; Do not pass around message, for exmaple.
(let ((ns (nth 0 packed))
(message (nth 1 packed))
(status (nth 2 packed))
@ -119,17 +134,60 @@ where NS is `:kernel' or `:notebook' slot of NOTIFICATION."
(force-mode-line-update))))
packed)))
(defun ein:notification-setup (buffer events)
(defun ein:notification-setup (buffer events get-list get-current get-name)
"Setup a new notification widget in the BUFFER.
This function saves the new notification widget instance in the
local variable of the BUFFER"
local variable of the BUFFER.
Other arguments GET-LIST, GET-CURRENT and GET-NAME are used to
draw tabs for worksheets. GET-LIST is a function returns a list
of worksheets. GET-CURRENT is a function returns the current
worksheet. GET-NAME is a function returns a name of the
worksheet given as its argument."
(with-current-buffer buffer
(setq ein:%notification%
(ein:notification "NotificationWidget" :buffer buffer))
(setq header-line-format ein:header-line-format)
(ein:notification-bind-events ein:%notification% events)
(oset ein:%notification% :tab
(make-instance 'ein:notification-tab
:get-list get-list
:get-current get-current
:get-name get-name))
ein:%notification%))
;;; Tabs
(defface ein:notification-tab-selected
'((t :inherit (header-line match)))
"Face for headline selected tab."
:group 'ein)
(defface ein:notification-tab-normal
'((t :inherit (header-line)))
"Face for headline selected tab."
:group 'ein)
(defmethod ein:notification-tab-create-line ((tab ein:notification-tab))
(let ((list (funcall (oref tab :get-list)))
(current (funcall (oref tab :get-current)))
(get-name (oref tab :get-name)))
(ein:join-str
" "
(loop for i from 1
for elem in list
if (eq elem current)
collect (propertize
(or (ein:and-let* ((name (funcall get-name elem)))
(format "[%d: %s]" i name))
(format "[%d]" i))
'face 'ein:notification-tab-selected)
else
collect (propertize
(format " %d " i)
'face 'ein:notification-tab-normal)))))
;;; Header line
@ -141,7 +199,9 @@ local variable of the BUFFER"
(ein:filter
'identity
(list (oref (oref ein:%notification% :notebook) :message)
(oref (oref ein:%notification% :kernel) :message))))))
(oref (oref ein:%notification% :kernel) :message)
(ein:notification-tab-create-line
(oref ein:%notification% :tab)))))))
(defun ein:header-line-setup-maybe ()
"Setup `header-line-format' for mumamo.

View file

@ -341,6 +341,39 @@ Elements are compared using the function TEST (default: `eq')."
return (progn (push new (cdr rest)) list)
finally do (error "PIVOT %S is not in LIST %S" pivot list))))
(defun* ein:list-move-left (list elem &key (test #'eq))
"Move ELEM in LIST left. TEST is used to compare elements"
(macrolet ((== (a b) `(funcall test ,a ,b)))
(cond
((== (car list) elem)
(append (cdr list) (list (car list))))
(t
(loop for rest on list
when (== (cadr rest) elem)
return (let ((prev (car rest)))
(setf (car rest) elem)
(setf (cadr rest) prev)
list)
finally do (error "ELEM %S is not in LIST %S" elem list))))))
(defun* ein:list-move-right (list elem &key (test #'eq))
"Move ELEM in LIST right. TEST is used to compare elements"
(loop with first = t
for rest on list
when (funcall test (car rest) elem)
return (if (cdr rest)
(let ((next (cadr rest)))
(setf (car rest) next)
(setf (cadr rest) elem)
list)
(if first
list
(setcdr rest-1 nil)
(cons elem list)))
finally do (error "ELEM %S is not in LIST %S" elem list)
for rest-1 = rest
do (setq first nil)))
(defun ein:get-value (obj)
"Get value from obj if it is a variable or function."
(cond

View file

@ -3,33 +3,53 @@
(require 'ein-notification)
(ert-deftest ein-header-line-kernel-status-busy ()
(defun ein:testing-notification-tab-mock ()
(make-instance 'ein:notification-tab
:get-list (lambda () '(a b c))
:get-current (lambda () 'a)
:get-name #'ignore))
(ert-deftest ein:header-line-normal ()
(let* ((ein:%notification% (ein:notification "NotificationTest"))
(kernel (oref ein:%notification% :kernel)))
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(should (equal (ein:header-line)
"IP[y]: [1] 2 3 "))))
(ert-deftest ein:header-line-kernel-status-busy ()
(let* ((ein:%notification% (ein:notification "NotificationTest"))
(kernel (oref ein:%notification% :kernel)))
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(ein:notification-status-set kernel
'status_busy.Kernel)
(should (equal (ein:header-line) "IP[y]: Kernel is busy..."))))
(should (equal (ein:header-line)
"IP[y]: Kernel is busy... | [1] 2 3 "))))
(ert-deftest ein-header-line-notebook-status-busy ()
(ert-deftest ein:header-line-notebook-status-busy ()
(let* ((ein:%notification% (ein:notification "NotificationTest"))
(notebook (oref ein:%notification% :notebook)))
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(ein:notification-status-set notebook
'notebook_saved.Notebook)
(should (equal (ein:header-line) "IP[y]: Notebook is saved"))))
(should (equal (ein:header-line)
"IP[y]: Notebook is saved | [1] 2 3 "))))
(ert-deftest ein-header-line-notebook-complex ()
(ert-deftest ein:header-line-notebook-complex ()
(let* ((ein:%notification% (ein:notification "NotificationTest"))
(kernel (oref ein:%notification% :kernel))
(notebook (oref ein:%notification% :notebook)))
(oset ein:%notification% :tab (ein:testing-notification-tab-mock))
(ein:notification-status-set kernel
'status_dead.Kernel)
(ein:notification-status-set notebook
'notebook_saving.Notebook)
(should (equal
(ein:header-line)
"IP[y]: Saving Notebook... | Kernel is dead. Need restart."))))
(concat "IP[y]: Saving Notebook... | "
"Kernel is dead. Need restart. | "
"[1] 2 3 ")))))
(ert-deftest ein-notification-and-events ()
(ert-deftest ein:notification-and-events ()
(let* ((notification (ein:notification "NotificationTest"))
(kernel (oref notification :kernel))
(notebook (oref notification :notebook))

View file

@ -95,3 +95,23 @@ def func():
(should (equal (ein:list-insert-before '(a b c) 'b 'X) '(a X b c)))
(should (equal (ein:list-insert-before '(a b c) 'c 'X) '(a b X c)))
(should-error (ein:list-insert-before '(a b c) 'd 'X)))
(ert-deftest ein:list-move-left ()
(should (equal (ein:list-move-left '(a) 'a) '(a)))
(should (equal (ein:list-move-left '(a b) 'a) '(b a)))
(should (equal (ein:list-move-left '(a b) 'b) '(b a)))
(should (equal (ein:list-move-left '(a b c d) 'a) '(b c d a)))
(should (equal (ein:list-move-left '(a b c d) 'b) '(b a c d)))
(should (equal (ein:list-move-left '(a b c d) 'c) '(a c b d)))
(should (equal (ein:list-move-left '(a b c d) 'd) '(a b d c)))
(should-error (ein:list-move-left '(a b c d) 'X)))
(ert-deftest ein:list-move-right ()
(should (equal (ein:list-move-right '(a) 'a) '(a)))
(should (equal (ein:list-move-right '(a b) 'a) '(b a)))
(should (equal (ein:list-move-right '(a b) 'b) '(b a)))
(should (equal (ein:list-move-right '(a b c d) 'a) '(b a c d)))
(should (equal (ein:list-move-right '(a b c d) 'b) '(a c b d)))
(should (equal (ein:list-move-right '(a b c d) 'c) '(a b d c)))
(should (equal (ein:list-move-right '(a b c d) 'd) '(d a b c)))
(should-error (ein:list-move-right '(a b c d) 'X)))