aboutsummaryrefslogtreecommitdiff
path: root/modules/auto-dim-config.el
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-05 05:28:58 -0500
committerCraig Jennings <c@cjennings.net>2026-06-05 05:28:58 -0500
commitebdf9e466b0e1f86e9b7d76650ac32408273e7a7 (patch)
treedab9b453f3a93c324b5388b3843502a088c7ed46 /modules/auto-dim-config.el
parentc094b2e4e64530379a9cb273303308a9affcabf6 (diff)
downloaddotemacs-ebdf9e466b0e1f86e9b7d76650ac32408273e7a7.tar.gz
dotemacs-ebdf9e466b0e1f86e9b7d76650ac32408273e7a7.zip
feat(term): replace vterm with ghostel as the terminal engine
I swapped the terminal engine from vterm to ghostel (libghostty-vt) everywhere. term-config replaces vterm-config (the F12 terminal, the C-; x menu, tmux history capture), and ai-term replaces ai-vterm (the F9 Claude-agent launcher). ghostel renders the agent TUI without vterm's flicker under heavy streaming, and one engine now covers every terminal workflow. Two behavior changes fall out of the swap. F9 launches in a terminal frame now: ghostel renders in TTY frames, so the old GUI-only guard is gone. Terminal windows no longer dim when unfocused: ghostel resolves its palette into the native module per-terminal, so there's no per-window color hook to dim through the way vterm had. auto-dim drops its vterm color-advice path, the dashboard Terminal button launches ghostel, and the vterm and vterm-toggle packages are removed. The tmux pane-history and copy-mode machinery carried over unchanged. It keys on the pty tty, which ghostel exposes.
Diffstat (limited to 'modules/auto-dim-config.el')
-rw-r--r--modules/auto-dim-config.el186
1 files changed, 7 insertions, 179 deletions
diff --git a/modules/auto-dim-config.el b/modules/auto-dim-config.el
index ebda92c2..c0e6e7a1 100644
--- a/modules/auto-dim-config.el
+++ b/modules/auto-dim-config.el
@@ -18,179 +18,16 @@
;; debounce). The dimmed faces (auto-dim-other-buffers and
;; auto-dim-other-buffers-hide) live in the active theme
;; (themes/dupre-faces.el) so they track theme switches.
+;;
+;; Terminal buffers (ghostel) do not participate in window dimming: ghostel
+;; bakes its color palette into the native module per-terminal, not per-window,
+;; so there is no per-window color hook to dim through (the vterm engine had
+;; one via `vterm--get-color', which this module used to advise). See the
+;; terminal-migration follow-up task in todo.org for revisiting this.
;;; Code:
-(require 'cl-lib)
-(require 'color)
-
(declare-function auto-dim-other-buffers-mode "auto-dim-other-buffers")
-(declare-function adob--update "auto-dim-other-buffers")
-(declare-function vterm--get-color "vterm")
-(declare-function vterm--invalidate "vterm")
-(declare-function vterm--set-size "vterm")
-(declare-function vterm--get-margin-width "vterm")
-(defvar vterm-min-window-width)
-(defvar vterm--term)
-
-(defvar cj/auto-dim--last-selected-window nil
- "Most recent selected window seen by `cj/auto-dim--refresh-vterm-on-command'.")
-
-(defvar cj/auto-dim--vterm-refresh-timer nil
- "Timer used to defer vterm redraws until after auto-dim updates.")
-
-(defcustom cj/auto-dim-vterm-foreground-blend 0.45
- "Blend amount for dimmed vterm foreground colors.
-
-0 keeps the original vterm color; 1 uses the
-`auto-dim-other-buffers' foreground color."
- :type 'number
- :group 'auto-dim-other-buffers)
-
-(defcustom cj/auto-dim-vterm-background-blend 0.7
- "Blend amount for dimmed vterm background colors.
-
-0 keeps the original vterm color; 1 uses the
-`auto-dim-other-buffers' background color."
- :type 'number
- :group 'auto-dim-other-buffers)
-
-(defun cj/auto-dim--vterm-buffer-dimmed-p ()
- "Return non-nil when the current vterm buffer should render dimmed.
-
-Vterm resolves terminal colors to concrete color strings while redrawing the
-buffer, so this integration is buffer-level. If the same vterm buffer is shown
-in multiple windows and any one of those windows is selected/undimmed, keep the
-buffer bright."
- (and (eq major-mode 'vterm-mode)
- (let ((windows (get-buffer-window-list (current-buffer) nil 'visible)))
- (and windows
- (not (catch 'undimmed
- (dolist (window windows)
- (unless (window-parameter window 'adob--dim)
- (throw 'undimmed t)))))))))
-
-(defun cj/auto-dim--face-color (face attribute fallback-face)
- "Return FACE ATTRIBUTE, falling back to FALLBACK-FACE."
- (let ((color (face-attribute face attribute nil 'default)))
- (if (or (null color) (eq color 'unspecified))
- (face-attribute fallback-face attribute nil 'default)
- color)))
-
-(defun cj/auto-dim--color-rgb (color)
- "Return COLOR as a list of RGB floats, or nil if COLOR is unknown."
- (cond
- ((and (stringp color)
- (string-match
- "\\`#\\([[:xdigit:]]\\{2\\}\\)\\([[:xdigit:]]\\{2\\}\\)\\([[:xdigit:]]\\{2\\}\\)\\'"
- color))
- (mapcar (lambda (index)
- (/ (string-to-number (match-string index color) 16) 255.0))
- '(1 2 3)))
- ((and (stringp color)
- (string-match
- "\\`#\\([[:xdigit:]]\\)\\([[:xdigit:]]\\)\\([[:xdigit:]]\\)\\'"
- color))
- (mapcar (lambda (index)
- (/ (* 17 (string-to-number (match-string index color) 16)) 255.0))
- '(1 2 3)))
- (t
- (ignore-errors
- (mapcar (lambda (component) (/ component 65535.0))
- (color-values color))))))
-
-(defun cj/auto-dim--blend-color (color target amount)
- "Blend COLOR toward TARGET by AMOUNT and return a hex color string."
- (if-let* ((rgb (cj/auto-dim--color-rgb color))
- (target-rgb (cj/auto-dim--color-rgb target)))
- (apply #'color-rgb-to-hex
- (append
- (cl-mapcar
- (lambda (source dest)
- (+ (* source (- 1 amount)) (* dest amount)))
- rgb target-rgb)
- '(2)))
- color))
-
-(defun cj/auto-dim--vterm-dim-color (color foreground-p)
- "Return dimmed vterm COLOR.
-
-When FOREGROUND-P is non-nil, blend toward the dimmed foreground face; otherwise
-blend toward the dimmed background face."
- (let* ((attribute (if foreground-p :foreground :background))
- (target (cj/auto-dim--face-color 'auto-dim-other-buffers attribute 'default))
- (amount (if foreground-p
- cj/auto-dim-vterm-foreground-blend
- cj/auto-dim-vterm-background-blend)))
- (cj/auto-dim--blend-color color target amount)))
-
-(defun cj/auto-dim--vterm-get-color (orig-fun index &rest args)
- "Advise vterm color lookup ORIG-FUN for dimmed windows.
-
-INDEX and ARGS are passed through to `vterm--get-color'."
- (let ((color (apply orig-fun index args)))
- (if (and color (cj/auto-dim--vterm-buffer-dimmed-p))
- (cj/auto-dim--vterm-dim-color color (memq :foreground args))
- color)))
-
-(defun cj/auto-dim--refresh-vterm-windows (&optional frame)
- "Refresh visible vterm buffers in FRAME after dim state changes."
- (when (or (fboundp 'vterm--set-size) (fboundp 'vterm--invalidate))
- (dolist (window (window-list frame 'no-minibuf))
- (with-current-buffer (window-buffer window)
- (when (eq major-mode 'vterm-mode)
- (let ((inhibit-read-only t))
- (if (and (bound-and-true-p vterm--term)
- (window-live-p window)
- (fboundp 'vterm--get-margin-width))
- (let* ((height (max 2 (window-body-height window)))
- (min-width (if (boundp 'vterm-min-window-width)
- vterm-min-window-width
- 80))
- (width (max min-width
- (- (window-body-width window)
- (vterm--get-margin-width)))))
- ;; `vterm--redraw' only repaints rows libvterm marked dirty.
- ;; A resize marks the whole terminal grid dirty, so briefly
- ;; nudge height and restore it to force a full repaint after
- ;; dim-state changes.
- (vterm--set-size vterm--term (1+ height) width)
- (vterm--set-size vterm--term height width))
- (when (fboundp 'vterm--invalidate)
- (vterm--invalidate)))))))))
-
-(defun cj/auto-dim--refresh-vterm-after-auto-dim (&optional frame)
- "Update auto-dim state, then refresh visible vterm buffers in FRAME."
- (setq cj/auto-dim--vterm-refresh-timer nil)
- (when (fboundp 'adob--update)
- (adob--update))
- (cj/auto-dim--refresh-vterm-windows frame))
-
-(defun cj/auto-dim--schedule-vterm-refresh (&optional frame)
- "Schedule a deferred vterm refresh for FRAME.
-
-The delay lets selection-changing commands finish before we recompute
-auto-dim state and invalidate vterm."
- (when cj/auto-dim--vterm-refresh-timer
- (cancel-timer cj/auto-dim--vterm-refresh-timer))
- (setq cj/auto-dim--vterm-refresh-timer
- (run-with-timer 0 nil #'cj/auto-dim--refresh-vterm-after-auto-dim frame)))
-
-(defun cj/auto-dim--refresh-vterm-on-command ()
- "Refresh visible vterm buffers when selected window changes.
-
-`window-selection-change-functions' does not catch every selection path used by
-windmove/Shift-arrow focus changes in this config, so this post-command hook is
-the fallback that makes vterm repaint after auto-dim changes window state."
- (let ((window (selected-window)))
- (unless (eq window cj/auto-dim--last-selected-window)
- (setq cj/auto-dim--last-selected-window window)
- (cj/auto-dim--schedule-vterm-refresh))))
-
-(defun cj/auto-dim--after-select-window (&rest _)
- "Schedule vterm refresh after `select-window'."
- (setq cj/auto-dim--last-selected-window (selected-window))
- (cj/auto-dim--schedule-vterm-refresh))
(defun cj/auto-dim--never-dim-dashboard-p (buffer)
"Return non-nil when BUFFER is the dashboard, so it stays lit.
@@ -212,7 +49,7 @@ focus cue on a split-displayed dashboard, accepted as a fair trade."
:custom
;; Dim only non-selected windows within Emacs, not the whole frame when
;; Emacs loses focus -- on Hyprland focus moves to other apps constantly,
- ;; and the ai-vterm agents live in their own windows.
+ ;; and the ai-term agents live in their own windows.
(auto-dim-other-buffers-dim-on-focus-out nil)
(auto-dim-other-buffers-dim-on-switch-to-minibuffer t)
:config
@@ -259,14 +96,5 @@ focus cue on a split-displayed dashboard, accepted as a fair trade."
#'cj/auto-dim--never-dim-dashboard-p)
(auto-dim-other-buffers-mode 1))
-(with-eval-after-load 'vterm
- (unless (advice-member-p #'cj/auto-dim--vterm-get-color #'vterm--get-color)
- (advice-add #'vterm--get-color :around #'cj/auto-dim--vterm-get-color))
- (unless (advice-member-p #'cj/auto-dim--after-select-window #'select-window)
- (advice-add #'select-window :after #'cj/auto-dim--after-select-window))
- (add-hook 'window-selection-change-functions
- #'cj/auto-dim--schedule-vterm-refresh)
- (add-hook 'post-command-hook #'cj/auto-dim--refresh-vterm-on-command))
-
(provide 'auto-dim-config)
;;; auto-dim-config.el ends here