diff options
| -rw-r--r-- | doc/lispref/minibuf.texi | 36 | ||||
| -rw-r--r-- | etc/NEWS | 3 | ||||
| -rw-r--r-- | lisp/subr.el | 103 |
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 | |||
| 2020 | input by binding @code{last-nonmenu-event} to a suitable value around | 2020 | input by binding @code{last-nonmenu-event} to a suitable value around |
| 2021 | the call. | 2021 | the 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 |
| 2027 | This function asks the user a question, expecting input in the echo | 2026 | This function asks the user a question, expecting input in the minibuffer. |
| 2028 | area. It returns @code{t} if the user types @kbd{y}, @code{nil} if the | 2027 | It returns @code{t} if the user types @kbd{y}, @code{nil} if the user |
| 2029 | user types @kbd{n}. This function also accepts @key{SPC} to mean yes | 2028 | types @kbd{n}. This function also accepts @key{SPC} to mean yes and |
| 2030 | and @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 | 2030 | because the question uses the minibuffer and for that reason the user |
| 2032 | that reason the user might try to use @kbd{C-]} to get out. The answer | 2031 | might try to use @kbd{C-]} to get out. The answer is a single |
| 2033 | is a single character, with no @key{RET} needed to terminate it. Upper | 2032 | character, with no @key{RET} needed to terminate it. Upper and lower |
| 2034 | and lower case are equivalent. | 2033 | case 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, |
| 2037 | followed by the string @w{@samp{(y or n) }}. If the input is not one of | 2036 | followed by the string @w{@samp{(y or n) }}. If the input is not one of |
| 2038 | the expected answers (@kbd{y}, @kbd{n}, @kbd{@key{SPC}}, | 2037 | the 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 | ||
| 2042 | This function does not actually use the minibuffer, since it does not | 2041 | This function actually uses the minibuffer, but does not allow editing |
| 2043 | allow editing of the answer. It actually uses the echo area (@pxref{The | 2042 | of the answer. The cursor moves to the minibuffer while the question |
| 2044 | Echo Area}), which uses the same screen space as the minibuffer. The | 2043 | is being asked. |
| 2045 | cursor moves to the echo area while the question is being asked. | ||
| 2046 | 2044 | ||
| 2047 | The answers and their meanings, even @samp{y} and @samp{n}, are not | 2045 | The answers and their meanings, even @samp{y} and @samp{n}, are not |
| 2048 | hardwired, and are specified by the keymap @code{query-replace-map} | 2046 | hardwired, 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 |
| 2055 | recentering or scrolling operation, and poses the question again. | 2053 | recentering or scrolling operation, and poses the question again. |
| 2056 | |||
| 2057 | @noindent | ||
| 2058 | We show successive lines of echo area messages, but only one actually | ||
| 2059 | appears 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 |
| 2073 | finalize the response. Upper and lower case are equivalent. | 2067 | finalize 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, |
| 2076 | followed by @w{@samp{(yes or no) }}. The user must type one of the | 2070 | followed by @w{@samp{(yes or no) }}. The user must type one of the |
| 2077 | expected responses; otherwise, the function responds @samp{Please answer | 2071 | expected responses; otherwise, the function responds @samp{Please answer |
| 2078 | yes or no.}, waits about two seconds and repeats the request. | 2072 | yes or no.}, waits about two seconds and repeats the request. |
| @@ -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 |
| 724 | at the end of the active minibuffer. | 724 | at 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'. | ||
| 2705 | Discard 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'. | ||
| 2713 | Discard 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'. | ||
| 2721 | Display an error on trying to insert a disallowed character. | ||
| 2722 | Also 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. |
| 2673 | Return t if answer is \"y\" and nil if it is \"n\". | 2733 | Return t if answer is \"y\" and nil if it is \"n\". |
| @@ -2683,16 +2743,13 @@ documentation of that variable for more information. In this | |||
| 2683 | case, the useful bindings are `act', `skip', `recenter', | 2743 | case, the useful bindings are `act', `skip', `recenter', |
| 2684 | `scroll-up', `scroll-down', and `quit'. | 2744 | `scroll-up', `scroll-down', and `quit'. |
| 2685 | An `act' response means yes, and a `skip' response means no. | 2745 | An `act' response means yes, and a `skip' response means no. |
| 2686 | A `quit' response means to invoke `keyboard-quit'. | 2746 | A `quit' response means to invoke `abort-recursive-edit'. |
| 2687 | If the user enters `recenter', `scroll-up', or `scroll-down' | 2747 | If the user enters `recenter', `scroll-up', or `scroll-down' |
| 2688 | responses, perform the requested window recentering or scrolling | 2748 | responses, perform the requested window recentering or scrolling |
| 2689 | and ask again. | 2749 | and ask again. |
| 2690 | 2750 | ||
| 2691 | Under a windowing system a dialog box will be used if `last-nonmenu-event' | 2751 | Under a windowing system a dialog box will be used if `last-nonmenu-event' |
| 2692 | is nil and `use-dialog-box' is non-nil." | 2752 | is 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))) |