;;; jao-minibuffer.el --- using the minibuffer to report status -*- lexical-binding: t; -*- ;; Copyright (C) 2020, 2021 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-notification nil) (defvar jao-minibuffer-align-right-p t) (defvar jao-minibuffer-right-margin (if window-system 0 1)) (defvar jao-minibuffer-maximized-frames-p nil) (defvar jao-minibuffer-frame-width nil) (defvar jao-minibuffer-notification-timeout 5) (defvar jao-minibuffer-enabled-p t) (defvar jao-minibuffer-active-buffer-line-color "lightsteelblue3") ;; "lightcyan3" (defvar jao-minibuffer-inactive-buffer-line-color "grey90") (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-p w (- w))) s) (substring s 0 w))) (defun jao-minibuffer--current () (with-current-buffer jao-minibuffer--name (buffer-substring (point-min) (point-max)))) (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 () (mapconcat 'string-trim (seq-filter (lambda (s) (not (string-blank-p s))) (mapcar 'format-mode-line (if jao-minibuffer-align-right-p jao-minibuffer-info (reverse jao-minibuffer-info)))) " ")) (defun jao-minibuffer--aligned (&optional w currentp) (let* ((msg (cond (currentp (jao-minibuffer--current)) (jao-minibuffer-notification (format-mode-line jao-minibuffer-notification)) (t (jao-minibuffer--format-info)))) (msg (if jao-minibuffer-align-right-p (string-trim msg) (string-trim-left msg))) (msg (propertize msg :minibuffer-message t))) (when (not (string-empty-p msg)) (let* ((mw (jao-minibuffer--width)) (w (mod (or w (string-width (or (current-message) ""))) mw)) (w (- mw w jao-minibuffer-right-margin))) (if (> w 0) (jao-minibuffer--trim msg w) ""))))) (defun jao-minibuffer--set-message (msg) (if (bound-and-true-p current-minibuffer-command) msg (let* ((msg (string-trim (replace-regexp-in-string "\n" " " msg))) (msg (if (string-blank-p msg) msg (concat msg " ")))) (if jao-minibuffer-align-right-p (concat msg (jao-minibuffer--aligned (string-width (or msg "")) t)) (concat (jao-minibuffer--aligned (+ 3 (string-width (or msg ""))) t) " " msg))))) (defun jao-minibuffer--insert (msg) (with-current-buffer jao-minibuffer--name (erase-buffer) (insert msg))) (defconst jao-minibuffer--size '(:eval (format "/%d" (line-number-at-pos (point-max))))) (defconst jao-minibuffer--circe '(circe-chat-target (:eval (format " [%d]" (length (circe-channel-nicks)))))) (defvar repeat-in-progress nil) (defvar w3m-current-title nil) (defvar jao-minibuffer--mode-line-format `(" %[" (:eval (cond ((derived-mode-p 'gnus-group-mode 'gnus-article-mode 'gnus-summary-mode) mode-line-buffer-identification) (w3m-current-title) (t "%b"))) "%]" (:propertize ,jao-minibuffer--circe face jao-themes-dimm) " %+ " (repeat-in-progress repeat-echo-mode-line-string) (:propertize mode-name face jao-themes-f00) (:propertize ("" minor-mode-alist (vc-mode vc-mode)) face jao-themes-f11) (:propertize (doc-view-doc-type mode-line-position ("%n L%l" ,jao-minibuffer--size)) face jao-themes-f12) global-mode-string)) ;;;###autoload (defun jao-minibuffer-refresh (&rest _ignore) (interactive) (when jao-minibuffer-enabled-p (let ((jao-minibuffer-enabled-p nil)) (jao-minibuffer--insert (or (jao-minibuffer--aligned) ""))))) ;;;###autoload (defun jao-minibuffer-add-variable (variable-name &optional order) (let ((v `(:eval ,variable-name))) (setq jao-minibuffer-info (remove v jao-minibuffer-info)) (add-to-ordered-list 'jao-minibuffer-info v order))) ;;;###autoload (defun jao-minibuffer-add-mode-line (order) (setq-default mode-line-format '(" ")) (set-face-attribute 'mode-line nil :box nil :height 1 :background jao-minibuffer-active-buffer-line-color) (set-face-attribute 'mode-line-inactive nil :box nil :height 1 :background jao-minibuffer-inactive-buffer-line-color) (advice-add 'force-mode-line-update :after #'jao-minibuffer-refresh) (add-hook 'buffer-list-update-hook #'jao-minibuffer-refresh) (jao-minibuffer-add-variable 'jao-minibuffer--mode-line-format order)) (defvar jao-minibuffer--notification-timer nil) (defun jao-minibuffer--start-notification-timer (timeout) (interactive) (when jao-minibuffer--notification-timer (cancel-timer jao-minibuffer--notification-timer)) (setq jao-minibuffer--notification-timer (run-with-idle-timer (or timeout jao-minibuffer-notification-timeout) nil 'jao-minibuffer-pop-notification))) ;;;###autoload (defun jao-minibuffer-push-notification (msg &optional timeout) (setq jao-minibuffer-notification msg) (jao-minibuffer--start-notification-timer timeout) (jao-minibuffer-refresh)) ;;;###autoload (defun jao-minibuffer-pop-notification () (interactive) (setq jao-minibuffer-notification nil) (jao-minibuffer-refresh)) ;;;###autoload (defun jao-minibuffer-toggle () (interactive) (setq jao-minibuffer-enabled-p (not jao-minibuffer-enabled-p)) (if jao-minibuffer-enabled-p (jao-minibuffer-refresh) (jao-minibuffer--insert ""))) (setq set-message-function #'jao-minibuffer--set-message) (setq clear-message-function #'jao-minibuffer-refresh) (provide 'jao-minibuffer) ;;; jao-minibuffer.el ends here