aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/eat-config.el25
-rw-r--r--tests/test-term-tmux-history.el11
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