aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/minibuf.texi36
-rw-r--r--etc/NEWS3
-rw-r--r--lisp/subr.el103
3 files changed, 87 insertions, 55 deletions
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index 49add3f7a79..41c87ce0eea 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -2020,29 +2020,27 @@ uses keyboard input. You can force use either of the mouse or of keyboard
2020input by binding @code{last-nonmenu-event} to a suitable value around 2020input by binding @code{last-nonmenu-event} to a suitable value around
2021the call. 2021the call.
2022 2022
2023 Strictly speaking, @code{yes-or-no-p} uses the minibuffer and 2023 Both @code{yes-or-no-p} and @code{y-or-n-p} use the minibuffer.
2024@code{y-or-n-p} does not; but it seems best to describe them together.
2025 2024
2026@defun y-or-n-p prompt 2025@defun y-or-n-p prompt
2027This function asks the user a question, expecting input in the echo 2026This function asks the user a question, expecting input in the minibuffer.
2028area. It returns @code{t} if the user types @kbd{y}, @code{nil} if the 2027It returns @code{t} if the user types @kbd{y}, @code{nil} if the user
2029user types @kbd{n}. This function also accepts @key{SPC} to mean yes 2028types @kbd{n}. This function also accepts @key{SPC} to mean yes and
2030and @key{DEL} to mean no. It accepts @kbd{C-]} to quit, like 2029@key{DEL} to mean no. It accepts @kbd{C-]} and @kbd{C-g} to quit,
2031@kbd{C-g}, because the question might look like a minibuffer and for 2030because the question uses the minibuffer and for that reason the user
2032that reason the user might try to use @kbd{C-]} to get out. The answer 2031might try to use @kbd{C-]} to get out. The answer is a single
2033is a single character, with no @key{RET} needed to terminate it. Upper 2032character, with no @key{RET} needed to terminate it. Upper and lower
2034and lower case are equivalent. 2033case are equivalent.
2035 2034
2036``Asking the question'' means printing @var{prompt} in the echo area, 2035``Asking the question'' means printing @var{prompt} in the minibuffer,
2037followed by the string @w{@samp{(y or n) }}. If the input is not one of 2036followed by the string @w{@samp{(y or n) }}. If the input is not one of
2038the expected answers (@kbd{y}, @kbd{n}, @kbd{@key{SPC}}, 2037the expected answers (@kbd{y}, @kbd{n}, @kbd{@key{SPC}},
2039@kbd{@key{DEL}}, or something that quits), the function responds 2038@kbd{@key{DEL}}, or something that quits), the function responds
2040@samp{Please answer y or n.}, and repeats the request. 2039@samp{Please answer y or n.}, and repeats the request.
2041 2040
2042This function does not actually use the minibuffer, since it does not 2041This function actually uses the minibuffer, but does not allow editing
2043allow editing of the answer. It actually uses the echo area (@pxref{The 2042of the answer. The cursor moves to the minibuffer while the question
2044Echo Area}), which uses the same screen space as the minibuffer. The 2043is being asked.
2045cursor moves to the echo area while the question is being asked.
2046 2044
2047The answers and their meanings, even @samp{y} and @samp{n}, are not 2045The answers and their meanings, even @samp{y} and @samp{n}, are not
2048hardwired, and are specified by the keymap @code{query-replace-map} 2046hardwired, and are specified by the keymap @code{query-replace-map}
@@ -2053,10 +2051,6 @@ special responses @code{recenter}, @code{scroll-up},
2053@kbd{C-v}, @kbd{M-v}, @kbd{C-M-v} and @kbd{C-M-S-v} in 2051@kbd{C-v}, @kbd{M-v}, @kbd{C-M-v} and @kbd{C-M-S-v} in
2054@code{query-replace-map}), this function performs the specified window 2052@code{query-replace-map}), this function performs the specified window
2055recentering or scrolling operation, and poses the question again. 2053recentering or scrolling operation, and poses the question again.
2056
2057@noindent
2058We show successive lines of echo area messages, but only one actually
2059appears on the screen at a time.
2060@end defun 2054@end defun
2061 2055
2062@defun y-or-n-p-with-timeout prompt seconds default 2056@defun y-or-n-p-with-timeout prompt seconds default
@@ -2072,7 +2066,7 @@ minibuffer. It returns @code{t} if the user enters @samp{yes},
2072@code{nil} if the user types @samp{no}. The user must type @key{RET} to 2066@code{nil} if the user types @samp{no}. The user must type @key{RET} to
2073finalize the response. Upper and lower case are equivalent. 2067finalize the response. Upper and lower case are equivalent.
2074 2068
2075@code{yes-or-no-p} starts by displaying @var{prompt} in the echo area, 2069@code{yes-or-no-p} starts by displaying @var{prompt} in the minibuffer,
2076followed by @w{@samp{(yes or no) }}. The user must type one of the 2070followed by @w{@samp{(yes or no) }}. The user must type one of the
2077expected responses; otherwise, the function responds @samp{Please answer 2071expected responses; otherwise, the function responds @samp{Please answer
2078yes or no.}, waits about two seconds and repeats the request. 2072yes or no.}, waits about two seconds and repeats the request.
diff --git a/etc/NEWS b/etc/NEWS
index 4e6a70f6931..f2685a1bfd8 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -723,6 +723,9 @@ the minibuffer. If non-nil, point will move to the end of the prompt
723*** Minibuffer now uses 'minibuffer-message' to display error messages 723*** Minibuffer now uses 'minibuffer-message' to display error messages
724at the end of the active minibuffer. 724at the end of the active minibuffer.
725 725
726+++
727*** 'y-or-n-p' now uses the minibuffer to read 'y' or 'n' answer.
728
726** map.el 729** map.el
727*** Now also understands plists. 730*** Now also understands plists.
728*** Now defined via generic functions that can be extended via 'cl-defmethod'. 731*** Now defined via generic functions that can be extended via 'cl-defmethod'.
diff --git a/lisp/subr.el b/lisp/subr.el
index 85e7187fb6b..8ac2f868c01 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2668,6 +2668,66 @@ floating point support."
2668;; Behind display-popup-menus-p test. 2668;; Behind display-popup-menus-p test.
2669(declare-function x-popup-dialog "menu.c" (position contents &optional header)) 2669(declare-function x-popup-dialog "menu.c" (position contents &optional header))
2670 2670
2671(defvar y-or-n-p-history-variable nil
2672 "History list symbol to add `y-or-n-p' answers to.")
2673
2674(defvar y-or-n-p-map
2675 (let ((map (make-sparse-keymap)))
2676 (set-keymap-parent map minibuffer-local-map)
2677
2678 (dolist (symbol '(act act-and-show act-and-exit automatic))
2679 (define-key map (vector 'remap symbol) 'y-or-n-p-insert-y))
2680
2681 (define-key map [remap skip] 'y-or-n-p-insert-n)
2682
2683 (dolist (symbol '(help backup undo undo-all edit edit-replacement
2684 delete-and-edit ignore self-insert-command))
2685 (define-key map (vector 'remap symbol) 'y-or-n-p-insert-other))
2686
2687 (define-key map [remap recenter] 'minibuffer-recenter-top-bottom)
2688 (define-key map [remap scroll-up] 'minibuffer-scroll-up-command)
2689 (define-key map [remap scroll-down] 'minibuffer-scroll-down-command)
2690 (define-key map [remap scroll-other-window] 'minibuffer-scroll-other-window)
2691 (define-key map [remap scroll-other-window-down] 'minibuffer-scroll-other-window-down)
2692
2693 (define-key map [escape] 'abort-recursive-edit)
2694 (dolist (symbol '(quit exit exit-prefix))
2695 (define-key map (vector 'remap symbol) 'abort-recursive-edit))
2696
2697 ;; FIXME: try catch-all instead of explicit bindings:
2698 ;; (define-key map [remap t] 'y-or-n-p-insert-other)
2699
2700 map)
2701 "Keymap that defines additional bindings for `y-or-n-p' answers.")
2702
2703(defun y-or-n-p-insert-y ()
2704 "Insert the answer \"y\" and exit the minibuffer of `y-or-n-p'.
2705Discard all previous input before inserting and exiting the minibuffer."
2706 (interactive)
2707 (delete-minibuffer-contents)
2708 (insert "y")
2709 (exit-minibuffer))
2710
2711(defun y-or-n-p-insert-n ()
2712 "Insert the answer \"n\" and exit the minibuffer of `y-or-n-p'.
2713Discard all previous input before inserting and exiting the minibuffer."
2714 (interactive)
2715 (delete-minibuffer-contents)
2716 (insert "n")
2717 (exit-minibuffer))
2718
2719(defun y-or-n-p-insert-other ()
2720 "Handle inserting of other answers in the minibuffer of `y-or-n-p'.
2721Display an error on trying to insert a disallowed character.
2722Also discard all previous input in the minibuffer."
2723 (interactive)
2724 (delete-minibuffer-contents)
2725 (ding)
2726 (minibuffer-message "Please answer y or n")
2727 (sit-for 2))
2728
2729(defvar empty-history)
2730
2671(defun y-or-n-p (prompt) 2731(defun y-or-n-p (prompt)
2672 "Ask user a \"y or n\" question. 2732 "Ask user a \"y or n\" question.
2673Return t if answer is \"y\" and nil if it is \"n\". 2733Return t if answer is \"y\" and nil if it is \"n\".
@@ -2683,16 +2743,13 @@ documentation of that variable for more information. In this
2683case, the useful bindings are `act', `skip', `recenter', 2743case, the useful bindings are `act', `skip', `recenter',
2684`scroll-up', `scroll-down', and `quit'. 2744`scroll-up', `scroll-down', and `quit'.
2685An `act' response means yes, and a `skip' response means no. 2745An `act' response means yes, and a `skip' response means no.
2686A `quit' response means to invoke `keyboard-quit'. 2746A `quit' response means to invoke `abort-recursive-edit'.
2687If the user enters `recenter', `scroll-up', or `scroll-down' 2747If the user enters `recenter', `scroll-up', or `scroll-down'
2688responses, perform the requested window recentering or scrolling 2748responses, perform the requested window recentering or scrolling
2689and ask again. 2749and ask again.
2690 2750
2691Under a windowing system a dialog box will be used if `last-nonmenu-event' 2751Under a windowing system a dialog box will be used if `last-nonmenu-event'
2692is nil and `use-dialog-box' is non-nil." 2752is nil and `use-dialog-box' is non-nil."
2693 ;; ¡Beware! when I tried to edebug this code, Emacs got into a weird state
2694 ;; where all the keys were unbound (i.e. it somehow got triggered
2695 ;; within read-key, apparently). I had to kill it.
2696 (let ((answer 'recenter) 2753 (let ((answer 'recenter)
2697 (padded (lambda (prompt &optional dialog) 2754 (padded (lambda (prompt &optional dialog)
2698 (let ((l (length prompt))) 2755 (let ((l (length prompt)))
@@ -2718,36 +2775,14 @@ is nil and `use-dialog-box' is non-nil."
2718 answer (x-popup-dialog t `(,prompt ("Yes" . act) ("No" . skip))))) 2775 answer (x-popup-dialog t `(,prompt ("Yes" . act) ("No" . skip)))))
2719 (t 2776 (t
2720 (setq prompt (funcall padded prompt)) 2777 (setq prompt (funcall padded prompt))
2721 (while 2778 (discard-input)
2722 (let* ((scroll-actions '(recenter scroll-up scroll-down 2779 (let* ((empty-history '())
2723 scroll-other-window scroll-other-window-down)) 2780 (str (read-from-minibuffer
2724 (key 2781 prompt nil
2725 (let ((cursor-in-echo-area t)) 2782 (make-composed-keymap y-or-n-p-map query-replace-map)
2726 (when minibuffer-auto-raise 2783 nil
2727 (raise-frame (window-frame (minibuffer-window)))) 2784 (or y-or-n-p-history-variable 'empty-history))))
2728 (read-key (propertize (if (memq answer scroll-actions) 2785 (setq answer (if (member str '("y" "Y")) 'act 'skip)))))
2729 prompt
2730 (concat "Please answer y or n. "
2731 prompt))
2732 'face 'minibuffer-prompt)))))
2733 (setq answer (lookup-key query-replace-map (vector key) t))
2734 (cond
2735 ((memq answer '(skip act)) nil)
2736 ((eq answer 'recenter)
2737 (recenter) t)
2738 ((eq answer 'scroll-up)
2739 (ignore-errors (scroll-up-command)) t)
2740 ((eq answer 'scroll-down)
2741 (ignore-errors (scroll-down-command)) t)
2742 ((eq answer 'scroll-other-window)
2743 (ignore-errors (scroll-other-window)) t)
2744 ((eq answer 'scroll-other-window-down)
2745 (ignore-errors (scroll-other-window-down)) t)
2746 ((or (memq answer '(exit-prefix quit)) (eq key ?\e))
2747 (signal 'quit nil) t)
2748 (t t)))
2749 (ding)
2750 (discard-input))))
2751 (let ((ret (eq answer 'act))) 2786 (let ((ret (eq answer 'act)))
2752 (unless noninteractive 2787 (unless noninteractive
2753 (message "%s%c" prompt (if ret ?y ?n))) 2788 (message "%s%c" prompt (if ret ?y ?n)))