;;;; chime.el --- Chime -*- lexical-binding: t -*- ;; Copyright (C) 2025-2026 Tyler Triplett ;; License: GNU GPL 3.0 or later <https://www.gnu.org/licenses/gpl-3.0.html> ;; This 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. ;;; Commentary: ;; Ring a chime, not a bell. ;; I would like a different solution, one that doesn't 'set-face-attribute'. ;; I cannot figure out a way to do it, as face-remap does not work well with ;; telephone-line. ;;; Code: (defvar chime-other-modeline nil) (defface chime-mode-line-face '((t (:foreground "black" :background "white"))) "Chime visual bell face." :group 'chime) (defun chime--get-attrs (f) "Return all attributes in F." (mapcar (lambda (attr) (cons attr (face-attribute f attr nil 'default))) '(:foreground :background :underline :overline :strike-through :box))) (defun chime--set-face!->fn (from to) "Map FROM attributes to TO, and return a way to remove them." (let ((old (chime--get-attrs to)) (attrs (seq-filter #'cdr (chime--get-attrs from)))) (mapc (lambda (attr) (set-face-attribute to nil (car attr) (cdr attr))) attrs) (lambda () (mapc (lambda (attr) (set-face-attribute to nil (car attr) (cdr attr))) old)))) (defvar chime--lock nil) (defun chime--mode-line-faces (m) "Return a list of faces corresponding with a modeline M." (append '(mode-line mode-line-active) (cond ((eq m 'telephone-line) '(telephone-line-evil telephone-line-evil-normal telephone-line-evil-insert telephone-line-evil-visual telephone-line-evil-emacs telephone-line-evil-operator telephone-line-evil-motion telephone-line-evil-replace telephone-line-accent-active))))) (defun chime--ring () "Performes the visual bell." (unless chime--lock (setq chime--lock t) (let* ((mode-line-faces (chime--mode-line-faces chime-other-modeline)) (cookie (mapcar (lambda (f) (chime--set-face!->fn 'chime-mode-line-face f)) mode-line-faces))) (force-mode-line-update) (run-with-timer 0.1 nil (lambda () (mapc #'funcall cookie) (force-mode-line-update) (setq chime--lock nil)))))) (defun chime--ring-toggle! () "When V set the \='ring-bell-function'." (if chime-mode (setq ring-bell-function #'chime--ring visible-bell t) (setq ring-bell-function nil))) (defgroup chime nil "Chime visual bell." :group 'convenience :prefix "chime-") ;;;###autoload (define-minor-mode chime-mode "Chime visual bell." :global t :group 'chime (chime--ring-toggle!)) (provide 'chime) ;;; chime.el ends here