1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-27 07:37:33 +00:00

New variable set-message-function to show message at the end of the minibuffer

* doc/lispref/display.texi (Displaying Messages): Document
set-message-function and clear-message-function.

* lisp/minibuffer.el (minibuffer-message-clear-timeout): New defcustom.
(minibuffer-message-timer, minibuffer-message-overlay): New variables.
(set-minibuffer-message, clear-minibuffer-message): New functions.
(set-message-function, clear-message-function): Set variables to
set-minibuffer-message and clear-minibuffer-message respectively.

* src/keyboard.c (read_char): Call clear_message when
Vclear_message_function is a function.

* src/xdisp.c (set_message): Call Vset_message_function when it's a function.
(clear_message): Call Vclear_message_function when it's a function.
(syms_of_xdisp): New variables set-message-function and clear-message-function
(bug#38457).
This commit is contained in:
Juri Linkov 2019-12-22 00:02:10 +02:00
parent 678a71ea2d
commit 485b423e8f
5 changed files with 160 additions and 4 deletions

View File

@ -306,6 +306,35 @@ reformatted, with undesirable results. Instead, use @code{(message
"%s" @var{string})}.
@end defun
@defvar set-message-function
When this variable is non-@code{nil}, @code{message} and related functions
call it as a function with one argument that is the message to show.
When this function returns @code{nil}, the message is displayed in the
echo area as usual. When the function returns a string, the returned
string is displayed in the echo area. When this function returns
other non-@code{nil} values, this means that the message was handled
specially, so the same message is not displayed in the echo area.
See also @code{clear-message-function} that can be used to clear the
message displayed by this function.
The default value is the function that displays the message at the end
of the minibuffer when the minibuffer is active.
@end defvar
@defvar clear-message-function
When this variable is non-@code{nil}, @code{message} and related functions
call it without arguments when their message is @code{nil} or the empty string.
Usually this function is called when the next input event arrives.
The function is called without arguments. It is expected to clear the
message displayed by its counterpart function specified by
@code{set-message-function}.
The default value is the function that clears the message displayed at
the end of the minibuffer when the minibuffer is active.
@end defvar
@defvar inhibit-message
When this variable is non-@code{nil}, @code{message} and related functions
will not use the Echo Area to display messages.

View File

@ -781,6 +781,10 @@ been introduced to allow controlling how the 'M-<' command works in
the minibuffer. If non-nil, point will move to the end of the prompt
(if point is after the end of the prompt).
+++
*** When the minibuffer is active, messages are displayed at the end of
the minibuffer instead of overwriting the minibuffer by the echo area.
---
*** Minibuffer now uses 'minibuffer-message' to display error messages
at the end of the active minibuffer.
@ -2723,6 +2727,10 @@ This function works like 'read-char', but uses 'read-from-minibuffer'
to read a character, so it maintains a history that can be navigated
via usual minibuffer keystrokes 'M-p'/'M-n'.
** New variables 'set-message-function' and 'clear-message-function'
can be used to specify functions to show and clear messages that
normally are displayed in the echo area.
** 'setq-local' can now set an arbitrary number of variables, which
makes the syntax more like 'setq'.

View File

@ -746,6 +746,76 @@ If ARGS are provided, then pass MESSAGE through `format-message'."
(sit-for (or minibuffer-message-timeout 1000000)))
(delete-overlay ol)))))
(defcustom minibuffer-message-clear-timeout nil
"How long to display an echo-area message when the minibuffer is active.
If the value is a number, it should be specified in seconds.
If the value is not a number, such messages never time out,
and the text is displayed until the next input event arrives.
Unlike `minibuffer-message-timeout' used by `minibuffer-message',
this option affects the pair of functions `set-minibuffer-message'
and `clear-minibuffer-message' called automatically via
`set-message-function' and `clear-message-function'."
:type '(choice (const :tag "Never time out" nil)
(integer :tag "Wait for the number of seconds" 2))
:version "27.1")
(defvar minibuffer-message-timer nil)
(defvar minibuffer-message-overlay nil)
(defun set-minibuffer-message (message)
"Temporarily display MESSAGE at the end of the minibuffer.
The text is displayed for `minibuffer-message-clear-timeout' seconds
(if the value is a number), or until the next input event arrives,
whichever comes first.
Unlike `minibuffer-message', this function is called automatically
via `set-message-function'."
(when (and (not noninteractive)
(window-live-p (active-minibuffer-window)))
(with-current-buffer (window-buffer (active-minibuffer-window))
(setq message (if (string-match-p "\\` *\\[.+\\]\\'" message)
;; Make sure we can put-text-property.
(copy-sequence message)
(concat " [" message "]")))
(unless (or (null minibuffer-message-properties)
;; Don't overwrite the face properties the caller has set
(text-properties-at 0 message))
(setq message (apply #'propertize message minibuffer-message-properties)))
(clear-minibuffer-message)
(setq minibuffer-message-overlay
(make-overlay (point-max) (point-max) nil t t))
(unless (zerop (length message))
;; The current C cursor code doesn't know to use the overlay's
;; marker's stickiness to figure out whether to place the cursor
;; before or after the string, so let's spoon-feed it the pos.
(put-text-property 0 1 'cursor t message))
(overlay-put minibuffer-message-overlay 'after-string message)
(when (numberp minibuffer-message-clear-timeout)
(setq minibuffer-message-timer
(run-with-timer minibuffer-message-clear-timeout nil
#'clear-minibuffer-message)))
;; Return `t' telling the caller that the message
;; was handled specially by this function.
t)))
(setq set-message-function 'set-minibuffer-message)
(defun clear-minibuffer-message ()
"Clear minibuffer message.
Intended to be called via `clear-message-function'."
(when (not noninteractive)
(when (timerp minibuffer-message-timer)
(cancel-timer minibuffer-message-timer)
(setq minibuffer-message-timer nil))
(when (overlayp minibuffer-message-overlay)
(delete-overlay minibuffer-message-overlay)
(setq minibuffer-message-overlay nil))))
(setq clear-message-function 'clear-minibuffer-message)
(defun minibuffer-completion-contents ()
"Return the user input in a minibuffer before point as a string.
In Emacs 22, that was what completion commands operated on.

View File

@ -2990,6 +2990,8 @@ read_char (int commandflag, Lisp_Object map,
safe_run_hooks (Qecho_area_clear_hook);
clear_message (1, 0);
}
else if (FUNCTIONP (Vclear_message_function))
clear_message (1, 0);
}
reread_for_input_method:

View File

@ -11706,13 +11706,32 @@ truncate_message_1 (ptrdiff_t nchars, Lisp_Object a2)
static void
set_message (Lisp_Object string)
{
Lisp_Object message = Qnil;
eassert (STRINGP (string));
message_enable_multibyte = STRING_MULTIBYTE (string);
if (FUNCTIONP (Vset_message_function))
{
ptrdiff_t count = SPECPDL_INDEX ();
specbind (Qinhibit_quit, Qt);
message = safe_call1 (Vset_message_function, string);
unbind_to (count, Qnil);
with_echo_area_buffer (0, -1, set_message_1, 0, string);
message_buf_print = false;
help_echo_showing_p = false;
if (STRINGP (message))
{
string = message;
message = Qnil;
}
}
if (NILP (message))
{
message_enable_multibyte = STRING_MULTIBYTE (string);
with_echo_area_buffer (0, -1, set_message_1, 0, string);
message_buf_print = false;
help_echo_showing_p = false;
}
if (STRINGP (Vdebug_on_message)
&& STRINGP (string)
@ -11768,6 +11787,14 @@ clear_message (bool current_p, bool last_displayed_p)
{
echo_area_buffer[0] = Qnil;
message_cleared_p = true;
if (FUNCTIONP (Vclear_message_function))
{
ptrdiff_t count = SPECPDL_INDEX ();
specbind (Qinhibit_quit, Qt);
safe_call (1, Vclear_message_function);
unbind_to (count, Qnil);
}
}
if (last_displayed_p)
@ -34940,6 +34967,26 @@ display table takes effect; in this case, Emacs does not consult
doc: /* If non-nil, debug if a message matching this regexp is displayed. */);
Vdebug_on_message = Qnil;
DEFVAR_LISP ("set-message-function", Vset_message_function,
doc: /* If non-nil, function to show the message.
The function is called with one argument that is the message.
When this function returns nil, the message is displayed in the echo
area as usual. When the function returns a string, the returned
string is displayed in the echo area. When this function returns
other non-nil values, this means that the message was handled
specially, so the same message is not displayed in the echo area.
See also `clear-message-function' that can be used to clear the
message displayed by this function. */);
Vset_message_function = Qnil;
DEFVAR_LISP ("clear-message-function", Vclear_message_function,
doc: /* If non-nil, function to clear message.
Usually this function is called when the next input event arrives.
The function is called without arguments. It is expected to clear the
message displayed by its counterpart function specified by
`set-message-function'. */);
Vclear_message_function = Qnil;
DEFVAR_LISP ("redisplay--all-windows-cause", Vredisplay__all_windows_cause,
doc: /* */);
Vredisplay__all_windows_cause = Fmake_hash_table (0, NULL);