Last active
August 30, 2022 08:48
-
-
Save haji-ali/0f3c2a17e3c4efc7ea4518088a7705b5 to your computer and use it in GitHub Desktop.
Echo messages in minibuffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;;; echo-line.el --- Echo messages in minibuffer -*- lexical-binding:t -*- | |
;; | |
;; Author: Al Haji-Ali <[email protected]> | |
;; Version: 0.1.0 | |
;; Package-Requires: ((emacs "26.1")) | |
;; Keywords: message, echo, gui | |
;; | |
;; This file is not part of GNU Emacs. | |
;; | |
;; This program is free software; you can redistribute it and/or modify | |
;; it under the terms of the GNU General Public License as published by | |
;; the Free Software Foundation, either version 3 of the License, or | |
;; (at your option) any later version. | |
;; | |
;; This program is distributed in the hope that it will be useful, | |
;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
;; GNU General Public License for more details. | |
;; | |
;; You should have received a copy of the GNU General Public License | |
;; along with this program. If not, see <http://www.gnu.org/licenses/>. | |
;; | |
;;; Commentary: | |
;; Based on gist by | |
;; https://gist.github.com/rougier/096323d35ae3af5c8d0740dbb297f3e5 | |
;; | |
;; Example usage: | |
;; | |
;; (require 'echo-line) | |
;; ;; Enable `display-time-mode` to update the `display-time-string` | |
;; (display-time-mode 1) | |
;; ;; Optionally delete the time string from the mode-line | |
;; (delete 'display-time-string global-mode-string) | |
;; ;; Update the echo-line every time the display-time is updated | |
;; (add-hook 'display-time-hook 'echo-line-update) | |
;; ;; Set the echo-line format | |
;; (setq echo-line-format '((:eval display-time-string))) | |
;; (echo-line-mode) | |
(require 'subr-x) | |
;;; Code: | |
(defface echo-line-face | |
'((t :height 0.83 | |
:overline t)) | |
"Default face used for the echo line.") | |
(defcustom echo-line-format nil | |
"Template for displaying echo line in the minibuffer. | |
See `mode-line-format' for more info" | |
:type 'sexp) | |
(defvar echo-line--current nil | |
"The current string to display on the next update.") | |
(defcustom echo-line-text-scale-factor 0.83 | |
"Scale factor to determine the size of character in the echo-line. | |
This is in relation to a character form the minibuffer.") | |
(defun echo-line-update () | |
"Update the echo-line." | |
;; Make sure that we don't run in a TRAMP buffer | |
(let ((default-directory "~/")) | |
;; Prevent accidental modification of the current buffer | |
(with-temp-buffer | |
(setq echo-line--current | |
(format-mode-line echo-line-format)) | |
;; Apply face while retaining set faces | |
(add-face-text-property 0 (length echo-line--current) | |
'echo-line-face t echo-line--current))) | |
(echo-line--re-echo)) | |
(defun echo-line--process-message (raw-msg max-width) | |
"Process RAW-MSG to be displayed with the echo-line. | |
MAX-WIDTH is the maximum width for a message." | |
(let* ((msg (if-let ((index (text-property-any 0 (length raw-msg) | |
'echo-message-start t raw-msg))) | |
(substring raw-msg 0 index) | |
raw-msg)) | |
(lines (if (string-match "\n\\([^\n]*\\)\\'" msg) | |
;; Extract last line | |
(cons (substring msg 0 (match-beginning 1)) | |
(substring msg (match-beginning 1))) | |
(cons "" msg))) | |
(last-line (truncate-string-to-width | |
(cdr lines) | |
max-width | |
nil nil "…"))) | |
(concat (car lines) last-line))) | |
(defun echo-line--message@advice (orig-fun &rest args) | |
"Message advice that add the echoed string to the message. | |
This advice displays the regular message in the echo area and | |
adds a specific text on the right part of the echo area. | |
Argument ORIG-FUN is `message`. | |
Optional argument ARGS are the functions arguments." | |
(if (or (string-empty-p echo-line--current) (active-minibuffer-window)) | |
;; Regular log and display when minibuffer is active | |
(apply orig-fun args) | |
;; Enhanced display | |
(let* ((right-col-width (* echo-line-text-scale-factor | |
(string-width echo-line--current))) | |
(raw-msg (if (and args (car args)) | |
(apply 'format-message args) | |
"")) | |
(msg (echo-line--process-message | |
raw-msg | |
(- (frame-width) right-col-width))) | |
(full (concat msg | |
(propertize " " | |
'echo-message-start t | |
'display `((space | |
:align-to (- (+ right | |
right-fringe | |
right-margin) | |
,right-col-width)))) | |
echo-line--current))) | |
;; Log actual message without echo | |
(when (and (not (string-empty-p raw-msg)) message-log-max) | |
(let ((inhibit-message t)) | |
(funcall orig-fun "%s" raw-msg))) | |
;; Display enhanced message without log | |
(let ((message-truncate-lines t) (message-log-max nil)) | |
(funcall orig-fun "%s" full)) | |
;; Set current message explicitly.. Not really necessary. | |
(setq current-message raw-msg)))) | |
(defun echo-line--re-echo () | |
"Re-echo the current message to the echo-area." | |
(let ((message-log-max nil) | |
(msg (current-message))) | |
(if msg | |
(message "%s" msg) | |
(message nil)))) | |
(define-minor-mode echo-line-mode | |
"Enables `echo-line-mode' globally." | |
:require 'echo-line | |
:init-value nil | |
:global t | |
(if (and echo-line-mode (display-graphic-p)) | |
(progn | |
(advice-add 'message :around #'echo-line--message@advice) | |
(add-hook 'post-command-hook #'echo-line--re-echo) | |
(echo-line-update)) | |
(advice-remove 'message #'echo-line--message@advice) | |
(remove-hook 'post-command-hook #'echo-line--re-echo))) | |
(provide 'echo-line) | |
;;; echo-line.el ends here |
@overideal, thanks for bringing echo-bar
to my attention. I somehow didn't know about it!
If anything, it seems to be the superior option compared to the above snippet. I switched to it just now and will test it out over the coming days/weeks.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey, nice snippet. Do you know how this compares to https://github.com/qaiviq/echo-bar.el? Is it worth making this a proper package so that more people can find it?