Handle help-form in y-or-n-p and use this in find-file-noselect (bug#5423)

* doc/lispref/help.texi (Help Functions): Mention help-form for
read-char-from-minibuffer and y-or-n-p.

* doc/lispref/minibuf.texi (Yes-or-No Queries): Mention help-form
for y-or-n-p.
(Multiple Queries): Mention help-form for read-char-from-minibuffer.

* lisp/files.el (find-file-noselect): Let-bind multi-line help text
to help-form for y-or-n-p.

* lisp/subr.el (read-char-choice): Mention help-form in docstring.
(read-char-from-minibuffer): Mention help-form in docstring.
(y-or-n-p-map): Remove handling of 'help'.
(y-or-n-p): Mention help-form in docstring.
When help-form is non-nil: add help-char to 'prompt', and bind
help-char to help-form-show in composed-keymap.
This commit is contained in:
Juri Linkov 2020-11-21 21:49:46 +02:00
parent 789ee3e1d5
commit 0a8cd01162
5 changed files with 86 additions and 40 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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"

View file

@ -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)))