emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 485b423: New variable set-message-function to show message at the


From: Juri Linkov
Subject: master 485b423: New variable set-message-function to show message at the end of the minibuffer
Date: Sat, 21 Dec 2019 17:02:18 -0500 (EST)

branch: master
commit 485b423e8f0df2711a850be7f254665f64ab0bdb
Author: Juri Linkov <address@hidden>
Commit: Juri Linkov <address@hidden>

    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).
---
 doc/lispref/display.texi | 29 ++++++++++++++++++++
 etc/NEWS                 |  8 ++++++
 lisp/minibuffer.el       | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/keyboard.c           |  2 ++
 src/xdisp.c              | 55 ++++++++++++++++++++++++++++++++++---
 5 files changed, 160 insertions(+), 4 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 42b049e..0085f3b 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -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.
diff --git a/etc/NEWS b/etc/NEWS
index 678139e..cd835f3 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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'.
 
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 76d8ca4..5dc753f 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -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.
diff --git a/src/keyboard.c b/src/keyboard.c
index 5135fd0..4cf1f64 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -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:
diff --git a/src/xdisp.c b/src/xdisp.c
index 08c6927..8cba5c5 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -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);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]