;;; jao-minibuffer.el --- using the minibuffer to report status -*- lexical-binding: t; -*- ;; Copyright (C) 2020, 2021, 2022 jao ;; Author: jao ;; Keywords: extensions ;; 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 . ;;; Commentary: ;; Simple asynchronous display of information in the minibuffer. ;;; Code: (defvar jao-minibuffer-info ()) (defvar jao-minibuffer-msg-info '("")) (defvar jao-minibuffer-align-right t) (defvar jao-minibuffer-right-margin (if window-system 0 2)) (defvar jao-minibuffer-maximized-frames-p t) (defvar jao-minibuffer-frame-width nil) (defvar jao-minibuffer-active-buffer-line-color "azure4") (defvar jao-minibuffer-inactive-buffer-line-color "grey25") (defconst jao-minibuffer--name " *Minibuf-0*") (defun jao-minibuffer--trim (s w) (if (< (string-width (or s "")) w) (format (format "%%%ds" (if jao-minibuffer-align-right w (- w))) s) (substring s 0 w))) (defun jao-minibuffer--width () (cond ((numberp jao-minibuffer-frame-width) jao-minibuffer-frame-width) (jao-minibuffer-maximized-frames-p (frame-width)) (t (min (frame-width) (window-width (minibuffer-window)))))) (defun jao-minibuffer--format-info (&optional info) (let* ((info (or info jao-minibuffer-info)) (info (if jao-minibuffer-align-right info (reverse info)))) (mapconcat #'string-trim (seq-remove #'string-blank-p (mapcar 'format-mode-line info)) " "))) (defun jao-minibuffer--aligned (w) (let* ((msg (jao-minibuffer--format-info)) (msg (cond (jao-minibuffer-align-right (string-trim msg)) (t (string-trim-left msg))))) (unless (string-empty-p msg) (let ((msg (propertize msg :minibuffer-message t)) (w (- (jao-minibuffer--width) w jao-minibuffer-right-margin))) (if (> w 0) (jao-minibuffer--trim msg w) ""))))) (defun jao-minibuffer--insert (msg) (let ((hack (derived-mode-p 'pdf-view-mode 'doc-view-mode))) (with-current-buffer jao-minibuffer--name (delete-region (point-min) (point-max)) (insert msg) (when hack (other-window 1) (other-window -1))))) (defun jao-minibuffer--strip-prev (msg) (if-let ((n (text-property-any 0 (length msg) :minibuffer-message t msg))) (string-trim (substring msg 0 n)) msg)) (defun jao-minibuffer--prefix (msgs) (when-let (p (string-join (butlast msgs) "\n")) (unless (string-blank-p p) (concat p "\n")))) (defun jao-minibuffer--format-msg (msg) (let* ((msgs (mapcar #'jao-minibuffer--strip-prev (split-string msg "\n"))) (prefix (jao-minibuffer--prefix msgs)) (msg (car (last msgs))) (w (string-width msg))) (if jao-minibuffer-align-right (concat prefix msg (jao-minibuffer--aligned w)) (concat prefix (jao-minibuffer--aligned (+ 3 w)) " " msg)))) (defun jao-minibuffer--set-message (msg) (when jao-minibuffer-mode (jao-minibuffer--format-msg (or msg "")))) (setq set-message-function #'jao-minibuffer--set-message) (defun jao-minibuffer--add-variable (list-name variable-name &optional order) (let ((v `(:eval ,variable-name))) (set list-name (remove v (symbol-value list-name))) (add-to-ordered-list list-name v order))) ;;;###autoload (defun jao-minibuffer-add-variable (variable-name &optional order) (jao-minibuffer--add-variable 'jao-minibuffer-info variable-name order)) ;;;###autoload (defun jao-minibuffer-add-msg-variable (variable-name &optional order) (jao-minibuffer--add-variable 'jao-minibuffer-msg-info variable-name order)) ;;;###autoload (defun jao-minibuffer-remove-variable (variable-name) (let ((v `(:eval ,variable-name))) (setq jao-minibuffer-info (remove v jao-minibuffer-info)) (setq jao-minibuffer-msg-info (remove v jao-minibuffer-info)))) ;;;###autoload (define-minor-mode jao-minibuffer-mode "Show minibuffer status" :global t :lighter "" :group 'jao (if jao-minibuffer-mode (progn (advice-add 'select-window :after #'jao-minibuffer-refresh) (advice-add 'force-mode-line-update :after #'jao-minibuffer-refresh) (setq clear-message-function #'jao-minibuffer-refresh) (jao-minibuffer-refresh)) (advice-remove 'select-window #'jao-minibuffer-refresh) (advice-remove 'force-mode-line-update #'jao-minibuffer-refresh) (setq clear-message-function nil) (jao-minibuffer--insert ""))) ;;;###autoload (defun jao-minibuffer-refresh (&rest _ignore) (interactive) (when jao-minibuffer-mode (let ((jao-minibuffer-mode nil) (msg (when jao-minibuffer-msg-info (jao-minibuffer--format-info jao-minibuffer-msg-info)))) (jao-minibuffer--insert (jao-minibuffer--format-msg (or msg "")))))) (provide 'jao-minibuffer) ;;; jao-minibuffer.el ends here