jao-minibuffer.el 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. ;;; jao-minibuffer.el --- using the minibuffer to report status -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2020, 2021, 2022, 2024 jao
  3. ;; Author: jao <mail@jao.io>
  4. ;; Keywords: extensions
  5. ;; This program is free software; you can redistribute it and/or modify
  6. ;; it under the terms of the GNU General Public License as published by
  7. ;; the Free Software Foundation, either version 3 of the License, or
  8. ;; (at your option) any later version.
  9. ;; This program is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ;; GNU General Public License for more details.
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. ;;; Commentary:
  16. ;; Simple asynchronous display of information in the minibuffer.
  17. ;;; Code:
  18. (defvar jao-minibuffer-info ())
  19. (defvar jao-minibuffer-msg-info '(""))
  20. (defvar jao-minibuffer-align-right t)
  21. (defvar jao-minibuffer-adaptive-alignment t)
  22. (defvar jao-minibuffer-right-margin (if window-system 0 1))
  23. (defvar jao-minibuffer-maximized-frames-p t)
  24. (defvar jao-minibuffer-frame-width nil)
  25. (defvar jao-minibuffer-active-buffer-line-color "azure4")
  26. (defvar jao-minibuffer-inactive-buffer-line-color "grey25")
  27. (defvar jao-minibuffer-inhibit nil)
  28. (defconst jao-minibuffer--name " *Minibuf-0*")
  29. (defun jao-minibuffer--trim (s w)
  30. (if (< (string-width (or s "")) w)
  31. (format (format "%%%ds" (if jao-minibuffer-align-right w (- w))) s)
  32. (substring s 0 (min w (length s)))))
  33. (defun jao-minibuffer--width ()
  34. (cond ((numberp jao-minibuffer-frame-width) jao-minibuffer-frame-width)
  35. (jao-minibuffer-maximized-frames-p (frame-width))
  36. (t (min (frame-width) (window-width (minibuffer-window))))))
  37. (defun jao-minibuffer--format-info (&optional info)
  38. (let* ((info (or info jao-minibuffer-info))
  39. (info (if jao-minibuffer-align-right info (reverse info))))
  40. (mapconcat #'string-trim
  41. (seq-remove #'string-blank-p (mapcar 'format-mode-line info))
  42. " ")))
  43. (defun jao-minibuffer--aligned (w)
  44. (let* ((msg (jao-minibuffer--format-info))
  45. (msg (cond (jao-minibuffer-align-right (string-trim msg))
  46. (t (string-trim-left msg)))))
  47. (unless (string-empty-p msg)
  48. (let ((msg (propertize msg 'minibuffer-message t))
  49. (w (- (jao-minibuffer--width) w jao-minibuffer-right-margin)))
  50. (if (> w 0) (jao-minibuffer--trim msg w) "")))))
  51. (defun jao-minibuffer--insert (msg)
  52. (with-current-buffer jao-minibuffer--name
  53. (delete-region (point-min) (point-max))
  54. (insert msg)))
  55. (defun jao-minibuffer--strip-prev (msg)
  56. (if-let ((n (text-property-any 0 (length msg) 'minibuffer-message t msg)))
  57. (string-trim (substring msg 0 n))
  58. msg))
  59. (defun jao-minibuffer--prefix (msgs)
  60. (when-let (p (string-join (butlast msgs) "\n"))
  61. (unless (string-blank-p p) (concat p "\n"))))
  62. (defun jao-minibuffer--format-msg (msg)
  63. (let* ((msgs (mapcar #'jao-minibuffer--strip-prev (split-string msg "\n" t)))
  64. (msgs (cl-remove-if (lambda (s) (get-text-property 0 'invisible s)) msgs))
  65. (prefix (jao-minibuffer--prefix msgs))
  66. (msg (or (car (last msgs)) ""))
  67. (w (string-width msg)))
  68. (if jao-minibuffer-align-right
  69. (concat prefix msg (jao-minibuffer--aligned w))
  70. (concat prefix (jao-minibuffer--aligned (+ 3 w)) " " msg))))
  71. (defun jao-minibuffer--set-message (msg)
  72. (when jao-minibuffer-mode
  73. (or (and (string= jao-minibuffer--name (or (buffer-name) "")) msg)
  74. jao-minibuffer-inhibit
  75. (let* ((info (and jao-minibuffer-msg-info
  76. (jao-minibuffer--format-info jao-minibuffer-msg-info)))
  77. (info (or (and info msg (propertize info 'face 'jao-themes-dimm))
  78. info))
  79. (sep (if msg " - " ""))
  80. (pref (when info
  81. (let ((len (+ (length info) (length sep))))
  82. (format (format "\n%%%ds" len) ""))))
  83. (msg (if (and msg pref)
  84. (replace-regexp-in-string "\n" pref msg)
  85. msg))
  86. (left (if jao-minibuffer-align-right info (or msg "")))
  87. (right (if jao-minibuffer-align-right (or msg "") info))
  88. (msg (or (if info (format "%s%s%s" left sep right) msg) "")))
  89. (if cursor-in-echo-area msg (jao-minibuffer--format-msg msg))))))
  90. (defun jao-minibuffer--clear-message ()
  91. (let ((jao-minibuffer-inhibit nil))
  92. (or (jao-minibuffer--insert (jao-minibuffer--set-message nil)) t)))
  93. (setq set-message-function #'jao-minibuffer--set-message)
  94. (defun jao-minibuffer--add-variable (list-name variable-name &optional order)
  95. (let ((v `(:eval ,variable-name)))
  96. (set list-name (remove v (symbol-value list-name)))
  97. (add-to-ordered-list list-name v order)))
  98. (defun jao-minibuffer--adjust-alignment (&rest _)
  99. (when jao-minibuffer-adaptive-alignment
  100. (setq jao-minibuffer-align-right
  101. (< (or (car (window-absolute-pixel-edges)) 0)
  102. (/ (or (cadr (assoc 'outer-size (frame-geometry))) 0) 2))))
  103. (jao-minibuffer-refresh))
  104. (defun jao-minibuffer-add-variable (variable-name &optional order)
  105. (jao-minibuffer--add-variable 'jao-minibuffer-info variable-name order))
  106. (defun jao-minibuffer-add-msg-variable (variable-name &optional order)
  107. (jao-minibuffer--add-variable 'jao-minibuffer-msg-info variable-name order))
  108. (defun jao-minibuffer-remove-variable (variable-name)
  109. (let ((v `(:eval ,variable-name)))
  110. (setq jao-minibuffer-info (remove v jao-minibuffer-info))
  111. (setq jao-minibuffer-msg-info (remove v jao-minibuffer-msg-info))))
  112. (define-minor-mode jao-minibuffer-mode
  113. "Show minibuffer status"
  114. :global t :lighter "" :group 'jao
  115. (if jao-minibuffer-mode
  116. (progn ;; (advice-add 'select-window :after #'jao-minibuffer-refresh)
  117. (advice-add 'select-window :after #'jao-minibuffer--adjust-alignment)
  118. (advice-add 'force-mode-line-update :after #'jao-minibuffer-refresh)
  119. (setq clear-message-function #'jao-minibuffer--clear-message)
  120. (jao-minibuffer-refresh))
  121. (advice-remove 'select-window #'jao-minibuffer-refresh)
  122. (advice-remove 'force-mode-line-update #'jao-minibuffer-refresh)
  123. (setq clear-message-function nil)
  124. (jao-minibuffer--insert "")))
  125. (defun jao-minibuffer-refresh (&rest _ignore)
  126. (interactive)
  127. (when jao-minibuffer-mode
  128. (let ((jao-minibuffer-mode nil)
  129. (msg (when jao-minibuffer-msg-info
  130. (jao-minibuffer--format-info jao-minibuffer-msg-info))))
  131. (jao-minibuffer--insert (jao-minibuffer--format-msg (or msg ""))))))
  132. (defun jao-minibuffer-toggle-adaptive-alignment ()
  133. (interactive)
  134. (setq jao-minibuffer-adaptive-alignment
  135. (not jao-minibuffer-adaptive-alignment))
  136. (jao-minibuffer-refresh))
  137. (provide 'jao-minibuffer)
  138. ;;; jao-minibuffer.el ends here