* egg/wnn.el (wnn-accept-charset-alist): XEmacs uses sisheng
[elisp/tamago.git] / menudiag.el
index 50d50b8..0e6498c 100644 (file)
@@ -50,7 +50,7 @@
 ;;
 
 (defgroup menudiag nil
-  "Input Translation System of Tamagotchy"
+  "Input Translation System of Tamago 4."
   :group 'egg)
 
 (defcustom menudiag-select-without-return nil
     (while (<= ch ?Z)
       (define-key map (char-to-string ch) 'menudiag-goto-item)
       (setq ch (1+ ch)))
-    (define-key map "\C-a" 'menudiag-beginning-of-line)
-    (define-key map "\C-e" 'menudiag-end-of-line)
-    (define-key map "\M-<" 'menudiag-beginning-of-items)
-    (define-key map "\M->" 'menudiag-end-of-items)
-    (define-key map "\C-f" 'menudiag-forward-item)
-    (define-key map "\C-b" 'menudiag-backward-item)
-    (define-key map "\C-n" 'menudiag-next-line)
-    (define-key map "\C-p" 'menudiag-previous-line)
-    (define-key map "\C-]" 'menudiag-exit)
-    (define-key map "\C-g" 'menudiag-exit-one-level)
-    (define-key map "\C-l" 'menudiag-redraw)
-    (define-key map "\C-m" 'menudiag-select-this-item)
-    (define-key map "?"    'menudiag-list-other-window)
+    (setq ch ?\C-0)
+    (while (<= ch ?\C-9)
+      (define-key map (vector ch) 'digit-argument)
+      (setq ch (1+ ch)))
+    (define-key map [?\C--]  'negative-argument)
+    (define-key map [?\C-u]  'universal-argument)
+    (define-key map " "      'menudiag-forward-item)
+    (define-key map "\C-a"   'menudiag-beginning-of-line)
+    (define-key map "\C-e"   'menudiag-end-of-line)
+    (define-key map "\M-<"   'menudiag-beginning-of-items)
+    (define-key map "\M->"   'menudiag-end-of-items)
+    (define-key map "\C-f"   'menudiag-forward-item)
+    (define-key map "\C-b"   'menudiag-backward-item)
+    (define-key map "\C-n"   'menudiag-next-line)
+    (define-key map "\C-p"   'menudiag-previous-line)
+    (define-key map "\C-]"   'menudiag-exit)
+    (define-key map "\C-g"   'menudiag-exit-one-level)
+    (define-key map "\C-l"   'menudiag-redraw)
+    (define-key map "\C-m"   'menudiag-select-this-item)
+    (define-key map "\M-v"   'menudiag-list-other-window)
+    (define-key map "?"      'menudiag-list-other-window)
     (define-key map [return] 'menudiag-select-this-item)
-    (define-key map [left] 'menudiag-backward-item)
-    (define-key map [right] 'menudiag-forward-item)
-    (define-key map [up] 'menudiag-previous-line)
-    (define-key map [down] 'menudiag-next-line)
-    (define-key map [menudiag-continuation] 'menudiag-follow-continuation)
-    (define-key map [t] 'undefined)
+    (define-key map [left]   'menudiag-backward-item)
+    (define-key map [right]  'menudiag-forward-item)
+    (define-key map [up]     'menudiag-previous-line)
+    (define-key map [down]   'menudiag-next-line)
+    (define-key map [exit]   'menudiag-exit)
+    (define-key map [t]      'undefined)
     map)
   "Keymap for MENU.")
 
 (defsubst menudiag-item-width (item)
   (+ 4 (string-width (menudiag-item-string item))))
 
-(defvar menudiag-window-conf nil)
-
 (defun menudiag-make-selection-list (item-list line-width)
   (let ((l nil)
        (line nil)
        (reverse (cons (reverse line) l))
       (reverse l))))
 
+(defvar menudiag-show-all nil)
+(make-variable-buffer-local 'menudiag-show-all)
+
+(defvar menudiag-continuation nil)
+(make-variable-buffer-local 'menudiag-continuation)
+
+(defvar menudiag-return-contin nil)
+(make-variable-buffer-local 'menudiag-return-contin)
+
+(defvar menudiag-value nil)
+(make-variable-buffer-local 'menudiag-value)
+
+(defvar menudiag-done nil)
+(make-variable-buffer-local 'menudiag-done)
+
 ;; Entry function
-(defun menudiag-select (menu &optional menudiag-continuation return-contin)
-  (let ((enable-recursive-minibuffers t)
-       value done)
-    (setq menudiag-window-conf nil)
-    (if menudiag-continuation
-       (setq unread-command-events (cons 'menudiag-continuation
-                                         unread-command-events)))
-    (if (not return-contin)
-       (setq value t))
-    (menudiag-select-internal menu)
-    (if (eq done t)
-       value
+(defun menudiag-select (menu &optional list-all continuation return-contin)
+  (let ((enable-recursive-minibuffers t))
+    (setq menudiag-return-contin return-contin)
+    (menudiag-select-internal menu list-all continuation)
+    (if (eq menudiag-done t)
+       menudiag-value
       (signal 'quit ""))))
 
-;; Entry function
-(defun menudiag-get-value (continuation)
-  (menudiag-item-value (nth (1- (length continuation)) continuation)))
+(defvar menudiag-line nil)
+(make-variable-buffer-local 'menudiag-line)
+
+(defvar menudiag-linepos 0)
+(make-variable-buffer-local 'menudiag-linepos)
+
+(defvar menudiag-pos-in-line 0)
+(make-variable-buffer-local 'menudiag-pos-in-line)
 
 (defun menudiag-follow-continuation ()
+  (let* ((item (car menudiag-continuation))
+        (value (menudiag-item-value item))
+        (pos (menudiag-search-item item)))
+    (unless pos
+      (error "no such item: %s" (menudiag-item-string item)))
+    (menudiag-goto-line (car pos))
+    (menudiag-goto-item-internal (cdr pos))
+    (when (menudiag-menu-p value)
+      (menudiag-select-internal value
+                               menudiag-show-all
+                               (cdr menudiag-continuation))
+      (menudiag-redraw)
+      (when menudiag-done
+       (when menudiag-return-contin
+         (setq menudiag-value (cons item menudiag-value)))
+       (setq unread-command-events (cons 'exit unread-command-events))))))
+
+(defvar menudiag-minibuffer-list nil)
+(defvar menudiag-variable-alist nil)
+
+(defmacro menudiag-send-variables (&rest args)
+  `(setq menudiag-variable-alist
+        (list ,@(mapcar (lambda (var) `(cons ',var ,var)) args))))
+
+(defmacro menudiag-send-variables-with-value (&rest args)
+  `(setq menudiag-variable-alist
+        ,(let ((alist (list 'list)))
+           (while args
+             (nconc alist `((cons ',(car args) ,(cadr args))))
+             (setq args (cddr args)))
+           alist)))
+
+(defun menudiag-receive-variables ()
+  (while menudiag-variable-alist
+    (set (caar menudiag-variable-alist) (cdar menudiag-variable-alist))
+    (setq menudiag-variable-alist (cdr menudiag-variable-alist))))
+
+(defvar menudiag-minibuf-prompt nil)
+(make-variable-buffer-local 'menudiag-minibuf-prompt)
+
+(defvar menudiag-current-items nil)
+(make-variable-buffer-local 'menudiag-current-items)
+
+(defvar menudiag-selection-list nil)
+(make-variable-buffer-local 'menudiag-selection-list)
+
+(defun menudiag-minibuffer-hook ()
   (interactive)
-  (let ((item (car menudiag-continuation)))
-    (setq menudiag-continuation (cdr menudiag-continuation))
-    (if menudiag-continuation
-       (setq unread-command-events (cons 'menudiag-continuation
-                                         unread-command-events)))
-    (if (eq item 'menudiag-list-all)
-       (menudiag-list-other-window)
-      (let ((in-loop t))
-       (while in-loop
-         (if (eq item (nth pos-in-line line))
-             (setq in-loop nil)
-           (menudiag-forward-item)
-           (if (and (= linepos 0) (= pos-in-line 0))
-               (error "no such item: %s" (menudiag-item-string item))))))
-      (let ((v (menudiag-item-value item)))
-       (if (menudiag-menu-p v)
-           (unwind-protect
-               (progn
-                 (menudiag-select-internal v)
-                 (menudiag-redraw))
-             (if (consp value)
-                 (setq value (cons item value)))
-             (if done (menudiag-exit-minibuffer))))))))
-
-(defun menudiag-select-internal (menu)
-  (let* ((minibuf-prompt (nth 1 menu))
-        (current-items (nth 2 menu))
-        (selection-list
-         (menudiag-make-selection-list current-items
-                                       (- (window-width (minibuffer-window))
-                                          (string-width minibuf-prompt))))
-        (line (car selection-list))
-        (minibuf-contents
-         (menudiag-make-menu-formatted-string line)))
-    (let ((linepos 0)
-         (pos-in-line 0))
-      (read-from-minibuffer minibuf-prompt
-                           (cons minibuf-contents 3)
-                           menudiag-mode-map))))
+  (remove-hook 'minibuffer-setup-hook 'menudiag-minibuffer-hook)
+  (setq menudiag-minibuffer-list (cons (current-buffer)
+                                      menudiag-minibuffer-list))
+  (buffer-disable-undo)
+  (menudiag-receive-variables)
+  (menudiag-beginning-of-items)
+  (when menudiag-continuation
+    (menudiag-follow-continuation))
+  (when (and menudiag-show-all (null menudiag-done))
+    (menudiag-list-other-window)))
+
+(defun menudiag-select-internal (menu all &optional continuation)
+  (menudiag-send-variables-with-value
+   menudiag-value          menudiag-value
+   menudiag-continuation   continuation
+   menudiag-return-contin  menudiag-return-contin
+   menudiag-show-all       all
+   menudiag-minibuf-prompt (cadr menu)
+   menudiag-current-items  (car (cddr menu))
+   menudiag-selection-list (menudiag-make-selection-list 
+                           (car (cddr menu))
+                           (- (window-width (minibuffer-window))
+                              (string-width (cadr menu)))))
+  (add-hook 'minibuffer-setup-hook 'menudiag-minibuffer-hook)
+  (unwind-protect
+      (progn
+       (read-from-minibuffer "" "" menudiag-mode-map)
+       (menudiag-receive-variables))
+    (setq menudiag-minibuffer-list (cdr menudiag-minibuffer-list))
+    (remove-hook 'minibuffer-setup-hook 'menudiag-minibuffer-hook)
+    ;; for egg's point-enterd/left hooks
+    (save-excursion
+      (goto-char (point-min)))))
 
 (defun menudiag-make-menu-formatted-string (item-list)
   (let ((i -1))
     char))
 
 ;; Character --> ITEM No
-(defun menudiag-char-to-item-num (char)
+(defun menudiag-char-to-item-num (ch)
   (let ((num))
     (cond ((and (<= ?0 ch) (<= ch ?9))
            (setq num (- ch ?0)))
           (t (setq num 1000)))
     num))
 
+(defun menudiag-check-current-menu ()
+  (or (eq (current-buffer) (car menudiag-minibuffer-list))
+      (error "menudiag: not current menu")))
+
 (defun menudiag-goto-item ()
   (interactive)
+  (menudiag-check-current-menu)
   (let ((ch last-command-char)
        (n 0))
     (setq n (menudiag-char-to-item-num ch))
-    (if (>= n (length line))
+    (if (>= n (length menudiag-line))
        (error "No such item")
       (menudiag-goto-item-internal n)
       (if menudiag-select-without-return
          (menudiag-select-this-item)))))
 
 (defun menudiag-goto-item-internal (n)
-  (let ((old-pos-in-line pos-in-line)
-       (p 3)
+  (let ((p (+ (length menudiag-minibuf-prompt) 3))
        (i 0))
-    (setq pos-in-line n)
-    (while (< i pos-in-line)
-      (setq p (+ p (length (menudiag-item-string (nth i line))) 4))
+    (setq menudiag-pos-in-line n)
+    (while (< i menudiag-pos-in-line)
+      (setq p (+ p (length (menudiag-item-string (nth i menudiag-line))) 4))
       (setq i (1+ i)))
     (goto-char p)))
 
 (defun menudiag-beginning-of-items ()
   (interactive)
+  (menudiag-check-current-menu)
   (menudiag-goto-line 0)
   (menudiag-beginning-of-line))
 
 (defun menudiag-end-of-items ()
   (interactive)
-  (menudiag-goto-line (1- (length selection-list)))
+  (menudiag-check-current-menu)
+  (menudiag-goto-line (1- (length menudiag-selection-list)))
   (menudiag-end-of-line))
 
 (defun menudiag-beginning-of-line ()
   (interactive)
+  (menudiag-check-current-menu)
   (menudiag-goto-item-internal 0))
 
 (defun menudiag-end-of-line ()
   (interactive)
-  (menudiag-goto-item-internal (1- (length line))))
+  (menudiag-check-current-menu)
+  (menudiag-goto-item-internal (1- (length menudiag-line))))
 
 ;; Should retain compatibility.  Must.
 ;;
 ;;    (insert (menudiag-make-menu-formatted-string line))))
 ;;
 
-(defun menudiag-forward-item ()
-  (interactive)
-  (if (< pos-in-line (1- (length line)))
-      (menudiag-goto-item-internal (1+ pos-in-line))
-    (if (>= linepos (1- (length selection-list)))
-       (menudiag-goto-line 0)
-      (menudiag-goto-line (1+ linepos)))
-    (menudiag-beginning-of-line)))
-
-(defun menudiag-backward-item ()
-  (interactive)
-  (if (< 0 pos-in-line)
-      (menudiag-goto-item-internal (1- pos-in-line))
-    (if (< linepos 1)
-        (menudiag-goto-line (1- (length selection-list)))
-      (menudiag-goto-line (1- linepos)))
-    (menudiag-end-of-line)))
+(defun menudiag-forward-item (n)
+  (interactive "p")
+  (menudiag-forward-item-internal n))
+
+(defun menudiag-backward-item (n)
+  (interactive "p")
+  (menudiag-forward-item-internal (- n)))
+
+(defun menudiag-forward-item-internal (n)
+  (menudiag-check-current-menu)
+  (setq n (+ n menudiag-pos-in-line))
+  (while (< n 0)
+    (menudiag-goto-line (1- menudiag-linepos))
+    (setq n (+ n (length menudiag-line))))
+  (while (>= n (length menudiag-line))
+    (setq n (- n (length menudiag-line)))
+    (menudiag-goto-line (1+ menudiag-linepos)))
+  (menudiag-goto-item-internal n))
 
 (defun menudiag-goto-line (n)
-  (cond
-   ((>= n (length selection-list))
-    (setq n 0))
-   ((< n 0)
-    (setq n (1- (length selection-list)))))
-  (setq line (nth n selection-list)
-        linepos n)
-  (delete-region (point-min) (point-max))
-  (insert (menudiag-make-menu-formatted-string line)))
-
-(defun menudiag-next-line ()
-  (interactive)
-  (menudiag-goto-line (1+ linepos))
-  (if (< pos-in-line (length line))
-      (menudiag-goto-item-internal pos-in-line)
-    (menudiag-end-of-line)))
-
-(defun menudiag-previous-line ()
-  (interactive)
-  (menudiag-goto-line (1- linepos))
-  (if (< pos-in-line (length line))
-      (menudiag-goto-item-internal pos-in-line)
+  (let ((len (length menudiag-selection-list)))
+    (when (< n 0)
+      (setq n (+ (% n len) len)))
+    (when (>= n len)
+      (setq n (% n len)))
+    (setq menudiag-line (nth n menudiag-selection-list)
+         menudiag-linepos n)
+    (let ((inhibit-read-only t))
+      (erase-buffer)
+      (insert menudiag-minibuf-prompt
+             (menudiag-make-menu-formatted-string menudiag-line))
+      (set-text-properties (point-min) (point-max) '(read-only t)))))
+
+(defun menudiag-next-line (n)
+  (interactive "p")
+  (menudiag-next-line-internal n))
+
+(defun menudiag-previous-line (n)
+  (interactive "p")
+  (menudiag-next-line-internal (- n)))
+
+(defun menudiag-next-line-internal (n)
+  (menudiag-check-current-menu)
+  (menudiag-goto-line (+ menudiag-linepos n))
+  (if (< menudiag-pos-in-line (length menudiag-line))
+      (menudiag-goto-item-internal menudiag-pos-in-line)
     (menudiag-end-of-line)))
 
 (defun menudiag-redraw ()
   (interactive)
-  (menudiag-goto-line linepos)
-  (menudiag-goto-item-internal pos-in-line))
+  (menudiag-check-current-menu)
+  (menudiag-goto-line menudiag-linepos)
+  (menudiag-goto-item-internal menudiag-pos-in-line))
 
 (defun menudiag-exit-one-level ()
   (interactive)
+  (menudiag-check-current-menu)
   (menudiag-exit-minibuffer))
 
 (defun menudiag-exit ()
   (interactive)
-  (setq done 'quit)
+  (menudiag-check-current-menu)
+  (unless menudiag-done
+    (setq menudiag-done 'quit))
   (menudiag-exit-minibuffer))
 
-(defun menudiag-select-this-item ()
+(defun menudiag-select-this-item (&optional all)
   (interactive)
-  (let* ((item (nth pos-in-line line))
+  (menudiag-check-current-menu)
+  (let* ((item (nth menudiag-pos-in-line menudiag-line))
         (v (menudiag-item-value item)))
     (if (menudiag-menu-p v)
-       (unwind-protect
-           (progn
-             (menudiag-restore-window)
-             (menudiag-select-internal v)
-             (menudiag-redraw))
-         (if (consp value)
-             (setq value (cons item value)))
-         (if done (menudiag-exit-minibuffer)))
-      (if (eq value t)
-         (setq value (menudiag-item-value item))
-       (setq value (cons item nil)))
-      (setq done t)
+       (progn
+         (menudiag-restore-window)
+         (menudiag-select-internal v all)
+         (menudiag-redraw)
+         (cond (menudiag-done
+                (when menudiag-return-contin
+                  (setq menudiag-value (cons item menudiag-value)))
+                (menudiag-exit-minibuffer))
+               (all
+                (menudiag-list-other-window))))
+      (setq menudiag-value (if menudiag-return-contin
+                              (list item)
+                            (menudiag-item-value item))
+           menudiag-done t)
       (menudiag-exit-minibuffer))))
+
+(defun menudiag-search-item (item)
+  (let ((selection-list menudiag-selection-list)
+       (line 0)
+       rest)
+    (while (and selection-list
+               (null (setq rest (memq item (car selection-list)))))
+      (setq selection-list (cdr selection-list)
+           line (1+ line)))
+    (and selection-list
+        (cons line (- (length (car selection-list)) (length rest))))))
 \f
 (defconst menudiag-selection-map
-  (let ((map (make-sparse-keymap)))
-    (define-key map [right]   'next-completion)
-    (define-key map [left]    'previous-completion)
-    (define-key map "\r"      'menudiag-choose-item)
-    (define-key map [mouse-2] 'menudiag-mouse-choose-item)
-    map))
+  (let ((map (make-sparse-keymap))
+       (ch ?0))
+    (while (<= ch ?9)
+      (define-key map (char-to-string ch) 'menudiag-selection-goto)
+      (setq ch (1+ ch)))
+    (define-key map "q"            'menudiag-retun-to-minibuf)
+    (define-key map "\C-b"         'previous-completion)
+    (define-key map "\M-b"         'previous-completion)
+    (define-key map "\C-f"         'next-completion)
+    (define-key map "\M-f"         'next-completion)
+    (define-key map " "            'next-completion)
+    (define-key map "\C-g"         'menudiag-selection-exit-one-level)
+    (define-key map "\C-m"         'menudiag-choose-item)
+    (define-key map "\C-]"         'menudiag-selection-exit)
+    (define-key map "\177"         'menudiag-selection-goto-delete)
+    (define-key map [delete]       'menudiag-selection-goto-delete)
+    (define-key map [backspace]    'menudiag-selection-goto-delete)
+    (define-key map [right]        'next-completion)
+    (define-key map [left]         'previous-completion)
+    (define-key map [return]       'menudiag-choose-item)
+    (define-key map [mouse-2]      'menudiag-mouse-choose-item)
+    map)
+  "keymap for menu selection mode")
+
+(defvar menudiag-window-conf nil)
+(make-variable-buffer-local 'menudiag-window-conf)
 
 (defvar menudiag-selection-buffer nil)
 (make-variable-buffer-local 'menudiag-selection-buffer)
-(put 'menudiag-selection-buffer 'permanent-local t)
 
 (defvar menudiag-selection-main-buffer nil)
 (make-variable-buffer-local 'menudiag-selection-main-buffer)
-(put 'menudiag-selection-main-buffer 'permanent-local t)
 
 (defun menudiag-selection-mode ()
-  (interactive)
   (kill-all-local-variables)
   (make-local-variable 'inhibit-read-only)
   (setq buffer-read-only t
        inhibit-read-only nil)
+  (make-local-hook 'post-command-hook)
+  (add-hook 'post-command-hook 'menudiag-selection-align-to-item nil t)
   (use-local-map menudiag-selection-map)
   (setq mode-name "Menudiag Selection")
   (setq major-mode 'menudiag-selection-mode))
 
-(defun menudiag-max-item-width (item-list)
-  (let ((max 0))
-    (while item-list
-      (setq max (max max (menudiag-item-width (car item-list)))
-           item-list (cdr item-list)))
-    max))
+(defun menudiag-max-item-width (items)
+  (apply 'max (mapcar 'menudiag-item-width items)))
 
 (defun menudiag-buffer-show-function ()
-  (let* ((items current-items)
-        (digits (length (concat (length items))))
-        (columns (max 1 (/ (window-width (minibuffer-window))
+  (menudiag-receive-variables)
+  (let* ((items menudiag-current-items)
+        (digits (length (number-to-string (length items))))
+        (form (concat "%" (number-to-string digits) "d. %s"))
+        (columns (max 1 (/ (window-width (selected-window))
                            (+ digits (menudiag-max-item-width items)))))
-        (width (/ (window-width (minibuffer-window)) columns))
-        (col 0) (n 0) str)
+        (width (/ (window-width (selected-window)) columns))
+        (col 0) (n 0) str p)
     (insert " ")
     (while items
       (setq p (point)
-           str (format (concat "%" digits "d. %s")
-                       n (menudiag-item-string (car items))))
+           str (format form n (menudiag-item-string (car items))))
       (insert str)
       (set-text-properties p (point) '(mouse-face highlight))
       (setq col (1+ col)
 
 (defun menudiag-buffer-name (prompt)
   (let ((len (1- (length prompt))))
-    (if (= (aref prompt len) ?:) (substring prompt 0 len) prompt)))
+    (generate-new-buffer-name
+     (if (= (aref prompt len) ?:) (substring prompt 0 len) prompt))))
 
 (defun menudiag-list-other-window ()
   (interactive)
-  (let ((temp-buffer-show-hook 'menudiag-buffer-show-function)
-       (main-buf (current-buffer)))
-    (setq menudiag-window-conf (current-window-configuration))
-    (with-output-to-temp-buffer (menudiag-buffer-name minibuf-prompt)
-      (setq menudiag-selection-buffer standard-output))
-    (set-buffer menudiag-selection-buffer)
-    (setq menudiag-selection-main-buffer main-buf)))
+  (menudiag-check-current-menu)
+  (let ((window (and menudiag-selection-buffer
+                    (get-buffer-window menudiag-selection-buffer))))
+    (if window
+       (select-window window)
+      (let ((temp-buffer-show-hook 'menudiag-buffer-show-function)
+           (main-buf (current-buffer))
+           (selection-list menudiag-selection-list)
+           (linepos menudiag-linepos)
+           (n (1+ menudiag-pos-in-line)))
+       (setq menudiag-window-conf (current-window-configuration))
+       (menudiag-send-variables menudiag-current-items)
+       (with-output-to-temp-buffer
+           (menudiag-buffer-name menudiag-minibuf-prompt)
+         (setq menudiag-selection-buffer standard-output))
+       (switch-to-buffer-other-window menudiag-selection-buffer)
+       (setq menudiag-selection-main-buffer main-buf
+             menudiag-selection-list selection-list)
+       (while (> linepos 0)
+         (setq linepos (1- linepos)
+               n (+ n (length (car selection-list)))
+               selection-list (cdr selection-list)))
+       (next-completion n)))))
+
+(defun menudiag-check-current-menu-list ()
+  (or (eq menudiag-selection-main-buffer (car menudiag-minibuffer-list))
+      (error "menudiag: not current menu list")))
 
 (defun menudiag-choose-item ()
   (interactive)
-  (let ((org-buf menudiag-selection-main-buffer)
-       (sel-buf (current-buffer))
-       (item-list selection-list)
-       (l 0)
-       tmp-buf n)
-    (with-temp-buffer
-      (setq tmp-buf (current-buffer))
-      (set-buffer sel-buf)
-      (setq completion-reference-buffer tmp-buf)
-      (choose-completion)
-      (set-buffer tmp-buf)
-      (setq n (string-to-int (buffer-string))))
-    (pop-to-buffer org-buf)
-    (while (and item-list (>= (- n (length (car item-list))) 0))
-      (setq l (1+ l)
-           n (- n (length (car item-list)))
-           item-list (cdr item-list)))
-    (menudiag-goto-line l)
-    (menudiag-goto-item-internal n)
-    (menudiag-select-this-item)))
+  (menudiag-choose-item-internal nil))
 
 (defun menudiag-mouse-choose-item (event)
   (interactive "e")
-  (set-buffer (window-buffer (car (nth 1 event))))
+  (set-buffer (window-buffer (caadr event)))
+  (menudiag-choose-item-internal event))
+
+(defun menudiag-choose-item-internal (event)
+  (menudiag-check-current-menu-list)
   (let ((org-buf menudiag-selection-main-buffer)
        (sel-buf (current-buffer))
-       (item-list selection-list)
+       (item-list menudiag-selection-list)
        (l 0)
        tmp-buf n)
     (with-temp-buffer
       (setq tmp-buf (current-buffer))
       (set-buffer sel-buf)
       (setq completion-reference-buffer tmp-buf)
-      (mouse-choose-completion event)
+      (if event
+         (mouse-choose-completion event)
+       (choose-completion))
       (set-buffer tmp-buf)
       (setq n (string-to-int (buffer-string))))
     (pop-to-buffer org-buf)
-    (while (and item-list (>= (- n (length (car item-list))) 0))
+    (while (and item-list (>= n (length (car item-list))))
       (setq l (1+ l)
            n (- n (length (car item-list)))
            item-list (cdr item-list)))
     (menudiag-goto-line l)
     (menudiag-goto-item-internal n)
-    (menudiag-select-this-item)))
+    (menudiag-select-this-item t)))
+
+(defvar menudiag-goto-number-list nil)
+(make-variable-buffer-local 'menudiag-goto-number-list)
+
+(defvar menudiag-original-point nil)
+(make-variable-buffer-local' menudiag-original-point)
+
+(defun menudiag-selection-goto ()
+  (interactive)
+  (unless (eq last-command 'menudiag-selection-goto)
+    (setq menudiag-goto-number-list nil
+         menudiag-original-point (point)))
+  (setq menudiag-goto-number-list (cons (- last-command-char ?0)
+                                       menudiag-goto-number-list))
+  (menudiag-selection-goto-internal))
+
+(defun menudiag-selection-goto-internal ()
+  (let* ((list menudiag-goto-number-list)
+        (n (menudiag-selection-item-number list))
+        (len (save-excursion
+               (set-buffer menudiag-selection-main-buffer)
+               (length menudiag-current-items))))
+    (setq this-command 'menudiag-selection-goto)
+    (if (>= n len)
+       (progn
+         (ding)
+         (setq menudiag-goto-number-list (cdr list)))
+    (goto-char (point-min))
+    (next-completion (1+ n)))))
+
+(defun menudiag-selection-item-number (list)
+  (let ((n 0)
+       (exp 1))
+    (while list
+      (setq n (+ (* (car list) exp) n)
+           exp (* 10 exp)
+           list (cdr list)))
+    n))
+
+(defun menudiag-selection-goto-delete (n)
+  (interactive "p")
+  (if (null (eq last-command 'menudiag-selection-goto))
+      (ding)
+    (setq menudiag-goto-number-list (nthcdr n menudiag-goto-number-list))
+    (if (null menudiag-goto-number-list)
+       (goto-char menudiag-original-point)
+      (menudiag-selection-goto-internal))))
+
+(defun menudiag-selection-align-to-item ()
+  (cond ((bolp)
+        (next-completion 1))
+       ((get-text-property (1- (point)) 'mouse-face)
+        (goto-char (previous-single-property-change (point) 'mouse-face)))))
 
 (defun menudiag-restore-window ()
-  (if menudiag-window-conf
-      (progn
-       (set-window-configuration menudiag-window-conf)
-       (setq menudiag-window-conf nil)
-       (kill-buffer menudiag-selection-buffer))))
+  (when menudiag-window-conf
+    (set-window-configuration menudiag-window-conf)
+    (kill-buffer menudiag-selection-buffer)))
 
 (defun menudiag-exit-minibuffer ()
-  (and menudiag-window-conf (menudiag-restore-window))
+  (menudiag-restore-window)
+  (menudiag-send-variables menudiag-done menudiag-value)
+  (buffer-enable-undo)
   (exit-minibuffer))
 
+(defun menudiag-retun-to-minibuf ()
+  (interactive)
+  (menudiag-check-current-menu-list)
+  (unless (minibuffer-window-active-p (minibuffer-window))
+    (set-minibuffer-window (minibuffer-window)))
+  (let ((window (get-buffer-window menudiag-selection-main-buffer)))
+    (if window
+       (select-window window)
+      (error "menudiag: cannot find minibuffer"))))
+
+(defun menudiag-selection-exit-one-level ()
+  (interactive)
+  (set-buffer menudiag-selection-main-buffer)
+  (menudiag-exit-one-level))
+
+(defun menudiag-selection-exit ()
+  (interactive)
+  (set-buffer menudiag-selection-main-buffer)
+  (menudiag-exit))
+
 (provide 'menudiag)
 ;;; menudiag.el ends here.