diff options
| -rw-r--r-- | modules/eat-config.el | 25 | ||||
| -rw-r--r-- | tests/test-term-tmux-history.el | 11 |
2 files changed, 36 insertions, 0 deletions
diff --git a/modules/eat-config.el b/modules/eat-config.el index 317f6a63f..74012b9b6 100644 --- a/modules/eat-config.el +++ b/modules/eat-config.el @@ -48,6 +48,31 @@ but it makes each jump gentler." (setq-local scroll-margin 0) (setq-local auto-window-vscroll nil)) +(defcustom cj/eat-reset-sgr-at-newline t + "When non-nil, EAT resets SGR (color) at each newline. +Claude Code and similar inline TUIs sometimes truncate a colored span without +emitting a reset; the unterminated color then bleeds onto every following line +in the buffer. Injecting a reset before each newline contains it to its own +line. Safe for the common case where programs re-open their color per line; a +program that carries a single color across newlines without re-opening it would +lose that color past the first line, so set this to nil if you hit that." + :type 'boolean + :group 'eat) + +(declare-function eat-term-process-output "eat") + +(defun cj/--eat-reset-sgr-at-newline (args) + "`:filter-args' advice for `eat-term-process-output'. +When `cj/eat-reset-sgr-at-newline' is non-nil, inject an SGR reset before each +newline in the pty OUTPUT so an unterminated color cannot bleed past its line. +ARGS is (TERMINAL OUTPUT)." + (if cj/eat-reset-sgr-at-newline + (list (car args) + (replace-regexp-in-string "\n" "\e[0m\n" (cadr args) t t)) + args)) + +(advice-add 'eat-term-process-output :filter-args #'cj/--eat-reset-sgr-at-newline) + ;; ------------------------------- eat package --------------------------------- (use-package eat diff --git a/tests/test-term-tmux-history.el b/tests/test-term-tmux-history.el index 13e3e1715..a5f5c93cd 100644 --- a/tests/test-term-tmux-history.el +++ b/tests/test-term-tmux-history.el @@ -305,5 +305,16 @@ the EAT window line-scrolls instead of recentering on full-frame redraws." (should (= scroll-margin 0)) (should (null auto-window-vscroll)))) +(ert-deftest test-term-eat-reset-sgr-at-newline () + "Normal: the SGR-reset advice injects a reset before each newline when enabled +\(containing an unterminated color), and passes output through unchanged when +disabled." + (let ((cj/eat-reset-sgr-at-newline t)) + (should (equal (cj/--eat-reset-sgr-at-newline (list (quote term) "a\nb\n")) + (list (quote term) "a\e[0m\nb\e[0m\n")))) + (let ((cj/eat-reset-sgr-at-newline nil)) + (should (equal (cj/--eat-reset-sgr-at-newline (list (quote term) "a\nb\n")) + (list (quote term) "a\nb\n"))))) + (provide 'test-term-tmux-history) ;;; test-term-tmux-history.el ends here |
