aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-25 22:45:22 -0400
committerCraig Jennings <c@cjennings.net>2026-06-25 22:45:22 -0400
commitcbd38d881d723f04aab748740977916707f24034 (patch)
treeede1ff4d56489ce6acf4f188a2f091b4cb4dfa0c
parent0b74f6241a2d0736572f1e0653c1f96e89756f56 (diff)
downloaddotemacs-cbd38d881d723f04aab748740977916707f24034.tar.gz
dotemacs-cbd38d881d723f04aab748740977916707f24034.zip
refactor(term): F12 opens eshell-through-EAT, retire eshell-toggle and xterm-color
Point the F12 dock-and-remember toggle at eshell instead of a standalone EAT zsh shell, so the primary terminal is eshell running through EAT (eat-eshell-mode): elisp functions as commands, TRAMP transparency, and EAT rendering visual commands. Drop the eshell-toggle package and its C-<f12> binding, since F12 covers it now. Drop xterm-color from eshell, since EAT handles ANSI color natively and its TERM=xterm-256color fought EAT's own. The toggle's buffer predicate now matches eshell-mode; the toggle tests and fixture are updated.
-rw-r--r--modules/eat-config.el52
-rw-r--r--modules/eshell-config.el34
-rw-r--r--tests/test-term-toggle--buffer-filter.el42
-rw-r--r--tests/testutil-ghostel-buffers.el10
4 files changed, 62 insertions, 76 deletions
diff --git a/modules/eat-config.el b/modules/eat-config.el
index d44fbfba3..7f3eab69f 100644
--- a/modules/eat-config.el
+++ b/modules/eat-config.el
@@ -1,13 +1,18 @@
-;;; eat-config.el --- EAT terminal and the F12 toggle -*- lexical-binding: t; coding: utf-8; -*-
+;;; eat-config.el --- EAT terminal emulator and the F12 eshell toggle -*- lexical-binding: t; coding: utf-8; -*-
;;; Commentary:
;;
-;; EAT (Emulate A Terminal, pure elisp) is the F12 terminal. Because EAT renders
-;; entirely in elisp, its whole palette is real Emacs faces, so it themes from
-;; the theme. This module owns the eat package configuration, the keymap wiring
-;; that lets F12 and C-; reach Emacs from inside a terminal, and the F12
+;; EAT (Emulate A Terminal, pure elisp) is the terminal emulator. Because EAT
+;; renders entirely in elisp, its whole palette is real Emacs faces, so it themes
+;; from the theme. This module owns the eat package configuration, the keymap
+;; wiring that lets F12 and C-; reach Emacs from inside a terminal, and the F12
;; dock-and-remember toggle.
;;
+;; F12 opens eshell, which runs through EAT (eat-eshell-mode, set up in
+;; eshell-config.el): the shell is eshell -- elisp functions as commands, TRAMP
+;; transparency -- and EAT renders its visual commands. eshell-config.el holds
+;; the shell itself; this module holds the emulator and the toggle.
+;;
;; The toggle reuses the geometry-preservation pattern from cj-window-toggle-lib:
;; capture direction + body size at toggle-off, replay them via a custom display
;; action using frame-edge directions and body-relative sizes, so the docked
@@ -19,9 +24,10 @@
(require 'cj-window-toggle-lib)
(declare-function eat "eat" (&optional program arg))
-(defvar eat-buffer-name)
+(declare-function eshell "eshell" (&optional arg))
(defvar eat-mode-map)
(defvar eat-semi-char-mode-map)
+(defvar eshell-buffer-name)
(defvar cj/custom-keymap)
(defun cj/turn-off-chrome-for-term ()
@@ -114,18 +120,14 @@ Positive integer: body-cols (right/left) or total-lines (below/above) -- see
nil means fall back to `cj/term-toggle-window-height' as a fraction.")
(defun cj/--term-toggle-buffer-p (buffer)
- "Return non-nil when BUFFER is the EAT terminal F12 should manage.
+ "Return non-nil when BUFFER is an eshell terminal F12 should manage.
-Qualifies when BUFFER is alive and has `eat-mode' (or its name starts with the
-EAT buffer-name prefix). ai-term's ghostel agent buffers never match -- they
-are managed separately via M-SPC, not F12."
+F12 opens eshell, which runs through EAT via eat-eshell-mode. ai-term's ghostel
+agent buffers are managed separately via M-SPC, not F12."
(and (bufferp buffer)
(buffer-live-p buffer)
(with-current-buffer buffer
- (or (eq major-mode 'eat-mode)
- (string-prefix-p (or (bound-and-true-p eat-buffer-name)
- "*eat*")
- (buffer-name buffer))))))
+ (derived-mode-p 'eshell-mode))))
(defun cj/--term-toggle-buffers ()
"Return live F12-managed terminal buffers in `buffer-list' (MRU) order."
@@ -189,17 +191,15 @@ Returns one of:
(t '(create-new))))))))
(defun cj/term-toggle ()
- "Toggle the EAT terminal buffer.
+ "Toggle the F12 eshell terminal (the primary `*eshell*', run through EAT).
-- If the EAT terminal is displayed in this frame, capture its geometry and
- delete its window (toggle off). Falls back to burying when it is the only
- window in the frame.
-- Otherwise, if the EAT terminal buffer is alive, display it via the
- saved-geometry action.
-- Otherwise, create a new EAT terminal, displaying it through the same
- saved-geometry action.
+- If it is displayed in this frame, capture its geometry and delete its window
+ (toggle off). Falls back to burying when it is the only window in the frame.
+- Otherwise, if it is alive, display it via the saved-geometry action.
+- Otherwise, open eshell, displaying it through the same saved-geometry action.
-ai-term's ghostel agent buffers are managed separately via M-SPC, not F12."
+eshell runs through EAT via eat-eshell-mode, so visual commands render in a real
+terminal. ai-term's ghostel agent buffers are managed separately via M-SPC."
(interactive)
(pcase (cj/--term-toggle-dispatch)
(`(toggle-off . ,win)
@@ -214,10 +214,10 @@ ai-term's ghostel agent buffers are managed separately via M-SPC, not F12."
(when w (select-window w)))
buf)
(`(create-new)
- ;; Create the EAT buffer without stealing the layout, then display it
+ ;; Open the primary eshell without stealing the layout, then display it
;; through the saved-geometry dock rule (same path as show-recent).
- (save-window-excursion (eat))
- (let ((buf (get-buffer (or (bound-and-true-p eat-buffer-name) "*eat*"))))
+ (save-window-excursion (eshell))
+ (let ((buf (get-buffer (or (bound-and-true-p eshell-buffer-name) "*eshell*"))))
(when buf
(display-buffer buf)
(let ((w (get-buffer-window buf)))
diff --git a/modules/eshell-config.el b/modules/eshell-config.el
index 33b900af6..ac583cf70 100644
--- a/modules/eshell-config.el
+++ b/modules/eshell-config.el
@@ -188,35 +188,11 @@ pairs where COMMAND is the `cd' string `eshell/alias' should run."
(require 'eat)
(eat-eshell-mode 1))
-(use-package eshell-toggle
- :custom
- (eshell-toggle-size-fraction 2)
- (eshell-toggle-run-command nil)
- (eshell-toggle-init-function #'eshell-toggle-init-eshell)
- :bind
- ("C-<f12>" . eshell-toggle))
-
-(use-package xterm-color
- :after eshell
- ;; Two hooks. eshell-before-prompt is the real hook name; use-package appends
- ;; "-hook", so writing eshell-before-prompt-hook here registered on a
- ;; nonexistent eshell-before-prompt-hook-hook and never ran. The eshell-mode
- ;; hook scopes TERM=xterm-256color to eshell-spawned processes only (a global
- ;; setenv would leak it to every start-process regardless of terminal).
- :hook
- ((eshell-before-prompt . (lambda ()
- (setq xterm-color-preserve-properties t)))
- (eshell-mode . (lambda ()
- (setq-local process-environment
- (cons "TERM=xterm-256color"
- process-environment)))))
- :config
- ;; Wire xterm-color into eshell's output pipeline (per its README): install
- ;; the filter and drop eshell's own ANSI handler. Without this the escapes are
- ;; never interpreted and TERM=xterm-256color only leaks raw codes.
- (add-to-list 'eshell-preoutput-filter-functions 'xterm-color-filter)
- (setq eshell-output-filter-functions
- (remove 'eshell-handle-ansi-color eshell-output-filter-functions)))
+;; eshell-toggle and xterm-color are retired. F12 opens eshell now (the
+;; dock-and-remember toggle in eat-config.el), and eat-eshell-mode renders
+;; eshell's output through EAT, which handles ANSI color natively -- so
+;; xterm-color's filter and its TERM=xterm-256color override are redundant and
+;; would fight EAT's own TERM=eat-truecolor.
(use-package eshell-syntax-highlighting
:after esh-mode
diff --git a/tests/test-term-toggle--buffer-filter.el b/tests/test-term-toggle--buffer-filter.el
index 4dae0c8d3..6db2ec65c 100644
--- a/tests/test-term-toggle--buffer-filter.el
+++ b/tests/test-term-toggle--buffer-filter.el
@@ -4,9 +4,9 @@
;; Three closely-related helpers determine which terminal buffer F12
;; manages: the predicate `cj/--term-toggle-buffer-p', the list
;; `cj/--term-toggle-buffers', and the per-frame window finder
-;; `cj/--term-toggle-displayed-window'. F12 manages the EAT terminal;
-;; ghostel buffers (including ai-term's agent buffers) are NOT F12-managed --
-;; they live on M-SPC.
+;; `cj/--term-toggle-displayed-window'. F12 opens eshell (run through EAT via
+;; eat-eshell-mode), so it manages eshell-mode buffers. Standalone eat buffers,
+;; ghostel buffers, and ai-term's agent buffers are NOT F12-managed.
;;; Code:
@@ -22,18 +22,18 @@
(cj/test--kill-agent-buffers)
(cj/test--kill-test-term-buffers))
-(ert-deftest test-term-toggle--buffer-p-accepts-eat-mode ()
- "Normal: an eat-mode buffer qualifies as the F12 terminal."
+(ert-deftest test-term-toggle--buffer-p-accepts-eshell-mode ()
+ "Normal: an eshell-mode buffer qualifies as the F12 terminal."
(test-term-toggle--cleanup)
- (let ((buf (cj/test--make-fake-eat-buffer "*test-term-1*")))
+ (let ((buf (cj/test--make-fake-eshell-buffer "*test-term-1*")))
(unwind-protect
(should (cj/--term-toggle-buffer-p buf))
(kill-buffer buf))))
-(ert-deftest test-term-toggle--buffer-p-rejects-ghostel ()
- "Boundary: a ghostel buffer is NOT F12-managed (ghostel is ai-term's, M-SPC)."
+(ert-deftest test-term-toggle--buffer-p-rejects-eat ()
+ "Boundary: a standalone eat buffer is NOT F12-managed (F12 opens eshell)."
(test-term-toggle--cleanup)
- (let ((buf (cj/test--make-fake-ghostel-buffer "*test-term-ghostel*")))
+ (let ((buf (cj/test--make-fake-eat-buffer "*test-term-eat*")))
(unwind-protect
(should-not (cj/--term-toggle-buffer-p buf))
(kill-buffer buf))))
@@ -47,7 +47,7 @@
(kill-buffer buf))))
(ert-deftest test-term-toggle--buffer-p-rejects-non-terminal ()
- "Boundary: a regular buffer (not eat-mode, no terminal name prefix) -> nil."
+ "Boundary: a regular buffer (not eshell-mode) -> nil."
(test-term-toggle--cleanup)
(let ((buf (get-buffer-create "*test-term-regular*")))
(unwind-protect
@@ -57,35 +57,35 @@
(ert-deftest test-term-toggle--buffer-p-rejects-dead-buffer ()
"Boundary: nil and dead buffers -> nil."
(should-not (cj/--term-toggle-buffer-p nil))
- (let ((buf (cj/test--make-fake-eat-buffer "*test-term-dead*")))
+ (let ((buf (cj/test--make-fake-eshell-buffer "*test-term-dead*")))
(kill-buffer buf)
(should-not (cj/--term-toggle-buffer-p buf))))
-(ert-deftest test-term-toggle--buffers-returns-eat-excludes-others ()
- "Normal: returns the EAT terminal but not ghostel/agent buffers."
+(ert-deftest test-term-toggle--buffers-returns-eshell-excludes-others ()
+ "Normal: returns the eshell terminal but not eat/agent buffers."
(test-term-toggle--cleanup)
- (let ((eat (cj/test--make-fake-eat-buffer "*test-term-eat*"))
+ (let ((esh (cj/test--make-fake-eshell-buffer "*test-term-esh*"))
(agent (cj/test--make-fake-ghostel-buffer "agent [for-test]")))
(unwind-protect
(let ((result (cj/--term-toggle-buffers)))
- (should (memq eat result))
+ (should (memq esh result))
(should-not (memq agent result)))
- (kill-buffer eat)
+ (kill-buffer esh)
(kill-buffer agent))))
(ert-deftest test-term-toggle--displayed-window-finds-terminal ()
- "Normal: the EAT terminal in a window -> returns that window."
+ "Normal: the eshell terminal in a window -> returns that window."
(test-term-toggle--cleanup)
- (let ((eat (cj/test--make-fake-eat-buffer "*test-term-shown*")))
+ (let ((esh (cj/test--make-fake-eshell-buffer "*test-term-shown*")))
(unwind-protect
(save-window-excursion
(delete-other-windows)
(let ((win (split-window-right)))
- (set-window-buffer win eat)
+ (set-window-buffer win esh)
(let ((result (cj/--term-toggle-displayed-window)))
(should (windowp result))
- (should (eq (window-buffer result) eat)))))
- (kill-buffer eat))))
+ (should (eq (window-buffer result) esh)))))
+ (kill-buffer esh))))
(ert-deftest test-term-toggle--displayed-window-skips-agent ()
"Boundary: only an agent terminal is displayed -> nil (agent not F12-managed)."
diff --git a/tests/testutil-ghostel-buffers.el b/tests/testutil-ghostel-buffers.el
index 3c8d75d00..8e26efec4 100644
--- a/tests/testutil-ghostel-buffers.el
+++ b/tests/testutil-ghostel-buffers.el
@@ -56,5 +56,15 @@ predicate without the side-effects of `(eat)'."
(setq-local major-mode 'eat-mode))
buf))
+(defun cj/test--make-fake-eshell-buffer (name)
+ "Return a buffer named NAME with `major-mode' set to `eshell-mode'.
+
+Avoids starting a real eshell by setting the mode buffer-locally. Used by the
+F12 toggle tests that need a buffer satisfying the eshell-mode predicate."
+ (let ((buf (get-buffer-create name)))
+ (with-current-buffer buf
+ (setq-local major-mode 'eshell-mode))
+ buf))
+
(provide 'testutil-ghostel-buffers)
;;; testutil-ghostel-buffers.el ends here