Function: y-or-n-p

y-or-n-p is a byte-compiled function defined in subr.el.gz.

Signature

(y-or-n-p PROMPT)

Documentation

Ask user a "y or n" question.

Return t if answer is "y" and nil if it is "n".

PROMPT is the string to display to ask the question; y-or-n-p adds "(y or n) " to it. If PROMPT is a non-empty string, and it ends with a non-space character, a space character will be appended to it.

If you bind the variable help-form to a non-nil value while calling this function, then pressing help-char causes it to evaluate help-form and display the result. PROMPT is also updated to show help-char like "(y, n or C-h) ", where help-char is automatically bound to help-form-show.

No confirmation of the answer is requested; a single character is enough. SPC also means yes, and DEL means no.

To be precise, this function translates user input into responses by consulting the bindings in query-replace-map; see the documentation of that variable for more information. In this case, the useful bindings are act, skip, recenter, scroll-up, scroll-down, and quit. An act response means yes, and a skip response means no. A quit response means to invoke abort-recursive-edit. If the user enters recenter, scroll-up, or scroll-down responses, perform the requested window recentering or scrolling and ask again.

If dialog boxes are supported, this function will use a dialog box if use-dialog-box is non-nil and the last input event was produced by a mouse, or by some window-system gesture, or via a menu.

By default, this function uses the minibuffer to read the key. If y-or-n-p-use-read-key is non-nil, read-key is used instead (which means that the user can't change buffers (and the like) while y-or-n-p is running).

View in manual

Probably introduced at or before Emacs version 19.23.

Source Code

;; Defined in /usr/src/emacs/lisp/subr.el.gz
(defun y-or-n-p (prompt)
  "Ask user a \"y or n\" question.
Return t if answer is \"y\" and nil if it is \"n\".

PROMPT is the string to display to ask the question; `y-or-n-p'
adds \"(y or n) \" to it.  If PROMPT is a non-empty string, and
it ends with a non-space character, a space character will be
appended to it.

If you bind the variable `help-form' to a non-nil value
while calling this function, then pressing `help-char'
causes it to evaluate `help-form' and display the result.
PROMPT is also updated to show `help-char' like \"(y, n or C-h) \",
where `help-char' is automatically bound to `help-form-show'.

No confirmation of the answer is requested; a single character is
enough.  SPC also means yes, and DEL means no.

To be precise, this function translates user input into responses
by consulting the bindings in `query-replace-map'; see the
documentation of that variable for more information.  In this
case, the useful bindings are `act', `skip', `recenter',
`scroll-up', `scroll-down', and `quit'.
An `act' response means yes, and a `skip' response means no.
A `quit' response means to invoke `abort-recursive-edit'.
If the user enters `recenter', `scroll-up', or `scroll-down'
responses, perform the requested window recentering or scrolling
and ask again.

If dialog boxes are supported, this function will use a dialog box
if `use-dialog-box' is non-nil and the last input event was produced
by a mouse, or by some window-system gesture, or via a menu.

By default, this function uses the minibuffer to read the key.
If `y-or-n-p-use-read-key' is non-nil, `read-key' is used
instead (which means that the user can't change buffers (and the
like) while `y-or-n-p' is running)."
  (let ((answer 'recenter)
	(padded (lambda (prompt &optional dialog)
		  (let ((l (length prompt)))
		    (concat prompt
			    (if (or (zerop l) (eq ?\s (aref prompt (1- l))))
				"" " ")
			    (if dialog ""
                              ;; Don't clobber caller's match data.
                              (save-match-data
                                (substitute-command-keys
                                 (if help-form
                                     (format "(\\`y', \\`n' or \\`%s') "
                                             (key-description
                                              (vector help-char)))
                                   "(\\`y' or \\`n') "))))))))
        ;; Preserve the actual command that eventually called
        ;; `y-or-n-p' (otherwise `repeat' will be repeating
        ;; `exit-minibuffer').
        (real-this-command real-this-command))
    (cond
     (noninteractive
      (setq prompt (funcall padded prompt))
      (let ((temp-prompt prompt))
	(while (not (memq answer '(act skip)))
	  (let ((str (read-string temp-prompt)))
	    (cond ((member str '("y" "Y")) (setq answer 'act))
		  ((member str '("n" "N")) (setq answer 'skip))
		  ((and (member str '("h" "H")) help-form) (print help-form))
		  (t (setq temp-prompt (concat "Please answer y or n.  "
					       prompt))))))))
     ((use-dialog-box-p)
      (setq prompt (funcall padded prompt t)
	    answer (x-popup-dialog t `(,prompt ("Yes" . act) ("No" . skip)))))
     (y-or-n-p-use-read-key
      ;; ¡Beware! when I tried to edebug this code, Emacs got into a weird state
      ;; where all the keys were unbound (i.e. it somehow got triggered
      ;; within read-key, apparently).  I had to kill it.
      (setq prompt (funcall padded prompt))
      (while
          (let* ((scroll-actions '(recenter scroll-up scroll-down
                                            scroll-other-window scroll-other-window-down))
                 (key
                  (let ((cursor-in-echo-area t))
                    (when minibuffer-auto-raise
                      (raise-frame (window-frame (minibuffer-window))))
                    (read-key (propertize (if (memq answer scroll-actions)
                                              prompt
                                            (concat "Please answer y or n.  "
                                                    prompt))
                                          'face 'minibuffer-prompt)))))
            (setq answer (lookup-key query-replace-map (vector key) t))
            (cond
             ((memq answer '(skip act)) nil)
             ((eq answer 'recenter)
              (recenter) t)
             ((eq answer 'scroll-up)
              (ignore-errors (scroll-up-command)) t)
             ((eq answer 'scroll-down)
              (ignore-errors (scroll-down-command)) t)
             ((eq answer 'scroll-other-window)
              (ignore-errors (scroll-other-window)) t)
             ((eq answer 'scroll-other-window-down)
              (ignore-errors (scroll-other-window-down)) t)
             ((or (memq answer '(exit-prefix quit)) (eq key ?\e))
              (signal 'quit nil) t)
             (t t)))
        (ding)
        (discard-input)))
     (t
      (setq prompt (funcall padded prompt))
      (let* ((enable-recursive-minibuffers t)
             (msg help-form)
             ;; Disable text conversion so that real Y or N events are
             ;; sent.
             (overriding-text-conversion-style nil)
             (keymap (let ((map (make-composed-keymap
                                 y-or-n-p-map query-replace-map)))
                       (when help-form
                         ;; Create a new map before modifying
                         (setq map (copy-keymap map))
                         (define-key map (vector help-char)
                           (lambda ()
                             (interactive)
                             (let ((help-form msg)) ; lexically bound msg
                               (help-form-show)))))
                       map))
             ;; Protect this-command when called from pre-command-hook (bug#45029)
             (this-command this-command)
             (str (progn
                    ;; If the minibuffer is already active, the
                    ;; selected window might not change.  Disable
                    ;; text conversion by hand.
                    (when (fboundp 'set-text-conversion-style)
                      (set-text-conversion-style text-conversion-style))
                    (read-from-minibuffer
                     prompt nil keymap nil
                     (or y-or-n-p-history-variable t)))))
        (setq answer (if (member str '("y" "Y")) 'act 'skip)))))
    (let ((ret (eq answer 'act)))
      (unless noninteractive
        (message "%s%c" prompt (if ret ?y ?n)))
      ret)))