diff --git a/doc/lispref/help.texi b/doc/lispref/help.texi index 2fa54e3b66b..90406df9c19 100644 --- a/doc/lispref/help.texi +++ b/doc/lispref/help.texi @@ -676,8 +676,9 @@ If this variable is non-@code{nil}, its value is a form to evaluate whenever the character @code{help-char} is read. If evaluating the form produces a string, that string is displayed. -A command that calls @code{read-event}, @code{read-char-choice}, or -@code{read-char} probably should bind @code{help-form} to a +A command that calls @code{read-event}, @code{read-char-choice}, +@code{read-char}, @code{read-char-from-minibuffer}, or +@code{y-or-n-p} probably should bind @code{help-form} to a non-@code{nil} expression while it does input. (The time when you should not do this is when @kbd{C-h} has some other meaning.) Evaluating this expression should result in a string that explains diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi index b6a3434d15e..f1cfd29ef14 100644 --- a/doc/lispref/minibuf.texi +++ b/doc/lispref/minibuf.texi @@ -2109,6 +2109,11 @@ special responses @code{recenter}, @code{scroll-up}, @kbd{C-v}, @kbd{M-v}, @kbd{C-M-v} and @kbd{C-M-S-v} in @code{query-replace-map}), this function performs the specified window recentering or scrolling operation, and poses the question again. + +If you bind @code{help-form} (@pxref{Help Functions}) to +a non-@code{nil} value while calling @code{y-or-n-p}, then pressing +@code{help-char} causes it to evaluate @code{help-form} and display +the result. @code{help-char} is automatically added to @var{prompt}. @end defun @defun y-or-n-p-with-timeout prompt seconds default @@ -2317,6 +2322,11 @@ character. Optionally, it ignores any input that is not a member of @var{chars}, a list of accepted characters. The @var{history} argument specifies the history list symbol to use; if it is omitted or @code{nil}, this function doesn't use the history. + +If you bind @code{help-form} (@pxref{Help Functions}) to +a non-@code{nil} value while calling @code{read-char-from-minibuffer}, +then pressing @code{help-char} causes it to evaluate @code{help-form} +and display the result. @end defun @node Reading a Password diff --git a/etc/NEWS b/etc/NEWS index 0cfca39c80f..9361cff3869 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1773,6 +1773,12 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el. * Lisp Changes in Emacs 28.1 ++++ +** 'read-char-from-minibuffer' and 'y-or-n-p' support 'help-form'. +If you bind 'help-form' to a non-nil value while calling these functions, +then pressing 'C-h' (help-char) causes the function to evaluate 'help-form' +and display the result. + +++ ** 'set-window-configuration' now takes an optional 'dont-set-frame' parameter which, when non-nil, instructs the function not to select diff --git a/lisp/files.el b/lisp/files.el index 3565b7f5710..49c9e5d18d4 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -2310,53 +2310,52 @@ the various files." ;; hexl-mode or image-mode. (memq major-mode '(hexl-mode image-mode))) (if (buffer-modified-p) - (if (y-or-n-p - (format - (if rawfile - "The file %s is already visited normally, + (if (let ((help-form + (format-message + (if rawfile "\ +The file %s is already visited normally, and you have edited the buffer. Now you have asked to visit it literally, meaning no coding system handling, format conversion, or local variables. -Emacs can visit a file in only one way at a time. - -Do you want to save the file, and visit it literally instead? " - "The file %s is already visited literally, +Emacs can visit a file in only one way at a time." + "\ +The file %s is already visited literally, meaning no coding system handling, format conversion, or local variables. You have edited the buffer. Now you have asked to visit the file normally, -but Emacs can visit a file in only one way at a time. - -Do you want to save the file, and visit it normally instead? ") - (file-name-nondirectory filename))) +but Emacs can visit a file in only one way at a time.") + (file-name-nondirectory filename)))) + (y-or-n-p + (if rawfile "\ +Do you want to save the file, and visit it literally instead? " "\ +Do you want to save the file, and visit it normally instead? "))) (progn (save-buffer) (find-file-noselect-1 buf filename nowarn rawfile truename number)) (if (y-or-n-p - (format - (if rawfile - "\ -Do you want to discard your changes, and visit the file literally now? " - "\ -Do you want to discard your changes, and visit the file normally now? "))) + (if rawfile "\ +Do you want to discard your changes, and visit the file literally now? " "\ +Do you want to discard your changes, and visit the file normally now? ")) (find-file-noselect-1 buf filename nowarn rawfile truename number) (error (if rawfile "File already visited non-literally" "File already visited literally")))) - (if (y-or-n-p - (format - (if rawfile - "The file %s is already visited normally. + (if (let ((help-form + (format-message + (if rawfile "\ +The file %s is already visited normally. You have asked to visit it literally, meaning no coding system decoding, format conversion, or local variables. -But Emacs can visit a file in only one way at a time. - -Do you want to revisit the file literally now? " - "The file %s is already visited literally, +But Emacs can visit a file in only one way at a time." + "\ +The file %s is already visited literally, meaning no coding system decoding, format conversion, or local variables. You have asked to visit it normally, -but Emacs can visit a file in only one way at a time. - -Do you want to revisit the file normally now? ") - (file-name-nondirectory filename))) +but Emacs can visit a file in only one way at a time.") + (file-name-nondirectory filename)))) + (y-or-n-p + (if rawfile "\ +Do you want to revisit the file literally now? " "\ +Do you want to revisit the file normally now? "))) (find-file-noselect-1 buf filename nowarn rawfile truename number) (error (if rawfile "File already visited non-literally" diff --git a/lisp/subr.el b/lisp/subr.el index 6e9f66fe97b..1fb0f9ab7e6 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2606,7 +2606,11 @@ This function is used by the `interactive' code letter `n'." Any input that is not one of CHARS is ignored. If optional argument INHIBIT-KEYBOARD-QUIT is non-nil, ignore -keyboard-quit events while waiting for a valid input." +keyboard-quit events while waiting for a valid input. + +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." (unless (consp chars) (error "Called `read-char-choice' without valid char choices")) (let (char done show-help (helpbuf " *Char Help*")) @@ -2767,8 +2771,11 @@ Optional argument HISTORY, if non-nil, should be a symbol that specifies the history list variable to use for navigating in input history using `M-p' and `M-n', with `RET' to select a character from history. -If the caller has set `help-form', there is no need to explicitly add -`help-char' to chars. It's bound automatically to `help-form-show'." +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. +There is no need to explicitly add `help-char' to CHARS; +`help-char' is bound automatically to `help-form-show'." (let* ((empty-history '()) (map (if (consp chars) (or (gethash (list help-form (cons help-char chars)) @@ -2825,7 +2832,7 @@ If the caller has set `help-form', there is no need to explicitly add (define-key map [remap skip] 'y-or-n-p-insert-n) - (dolist (symbol '(help backup undo undo-all edit edit-replacement + (dolist (symbol '(backup undo undo-all edit edit-replacement delete-and-edit ignore self-insert-command)) (define-key map (vector 'remap symbol) 'y-or-n-p-insert-other)) @@ -2880,6 +2887,12 @@ Return t if answer is \"y\" and nil if it is \"n\". PROMPT is the string to display to ask the question. It should end in a space; `y-or-n-p' adds \"(y or n) \" 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. @@ -2902,7 +2915,13 @@ is nil and `use-dialog-box' is non-nil." (concat prompt (if (or (zerop l) (eq ?\s (aref prompt (1- l)))) "" " ") - (if dialog "" "(y or n) ")))))) + (if dialog "" + (if help-form + (format "(y, n or %s) " + (key-description + (vector help-char))) + "(y or n) " + ))))))) (cond (noninteractive (setq prompt (funcall padded prompt)) @@ -2911,6 +2930,7 @@ is nil and `use-dialog-box' is non-nil." (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)))))))) ((and (display-popup-menus-p) @@ -2923,10 +2943,20 @@ is nil and `use-dialog-box' is non-nil." (setq prompt (funcall padded prompt)) (let* ((empty-history '()) (enable-recursive-minibuffers t) + (msg help-form) + (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)) (str (read-from-minibuffer - prompt nil - (make-composed-keymap y-or-n-p-map query-replace-map) - nil + prompt nil keymap nil (or y-or-n-p-history-variable 'empty-history)))) (setq answer (if (member str '("y" "Y")) 'act 'skip))))) (let ((ret (eq answer 'act)))