diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-11 09:30:53 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-11 09:30:53 -0500 |
| commit | 071fb5e972a08e4072d9177d493928ceb26763f4 (patch) | |
| tree | 19e51f749b9a92fe77ea1f9288d1200a59e8b67f /tests | |
| parent | a70bb985c86aee2b701b40d5c3fae720863cfa4e (diff) | |
| download | dotemacs-071fb5e972a08e4072d9177d493928ceb26763f4.tar.gz dotemacs-071fb5e972a08e4072d9177d493928ceb26763f4.zip | |
feat(ai-vterm): keep emacsclient files out of the agent window
`server-start' leaves `server-window' nil, so `server-switch-buffer' opens an `emacsclient -n' file in the selected window. When I'm typing in the agent vterm, the selected window is the agent window, so "tell the agent to open something" replaced the agent buffer with that file. I wired `server-window' to a function. When the selected window shows an `agent [...]' buffer, it puts the file in a non-agent window instead, splitting one off to the left of the agent when the agent is the only window. emacsclient invocations from anywhere else still go through `pop-to-buffer' unchanged.
`cj/--ai-vterm-non-agent-window' picks the target window. It skips the minibuffer, dedicated windows, and any window already showing an agent buffer.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/test-ai-vterm--server-display.el | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/tests/test-ai-vterm--server-display.el b/tests/test-ai-vterm--server-display.el new file mode 100644 index 00000000..1d0d1001 --- /dev/null +++ b/tests/test-ai-vterm--server-display.el @@ -0,0 +1,127 @@ +;;; test-ai-vterm--server-display.el --- Tests for emacsclient window routing -*- lexical-binding: t; -*- + +;;; Commentary: +;; `cj/--ai-vterm-server-display' is wired as `server-window' so a file +;; opened via `emacsclient -n' (e.g. when Craig tells the agent to open +;; something) doesn't land on top of the agent vterm. When the selected +;; window shows an `agent [...]' buffer, the file goes to a non-agent +;; window instead -- splitting one off the agent if it is the only window. +;; `cj/--ai-vterm-non-agent-window' picks that window. + +;;; Code: + +(require 'ert) + +(add-to-list 'load-path (expand-file-name "modules" user-emacs-directory)) +(add-to-list 'load-path (expand-file-name "tests" user-emacs-directory)) +(require 'ai-vterm) +(require 'server) +(require 'testutil-vterm-buffers) + +(ert-deftest test-ai-vterm--non-agent-window-finds-code-window () + "Normal: agent on the right, code on the left -> returns the code window." + (cj/test--kill-agent-buffers) + (let ((agent (get-buffer-create "agent [proj]")) + (code (get-buffer-create "code.el"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) code) + (let ((right (split-window-right))) + (set-window-buffer right agent) + (let ((found (cj/--ai-vterm-non-agent-window right))) + (should (windowp found)) + (should (eq (window-buffer found) code))))) + (kill-buffer agent) + (kill-buffer code)))) + +(ert-deftest test-ai-vterm--non-agent-window-none-when-only-agent () + "Boundary: the agent window is the only one -> nil." + (cj/test--kill-agent-buffers) + (let ((agent (get-buffer-create "agent [solo]"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) agent) + (should-not (cj/--ai-vterm-non-agent-window (selected-window)))) + (kill-buffer agent)))) + +(ert-deftest test-ai-vterm--non-agent-window-skips-dedicated () + "Boundary: a dedicated non-agent window is not a valid target." + (cj/test--kill-agent-buffers) + (let ((agent (get-buffer-create "agent [proj]")) + (side (get-buffer-create "*dedicated-side*"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) agent) + (let ((w (split-window-right))) + (set-window-buffer w side) + (set-window-dedicated-p w t) + (unwind-protect + (should-not (cj/--ai-vterm-non-agent-window (selected-window))) + (set-window-dedicated-p w nil)))) + (kill-buffer agent) + (kill-buffer side)))) + +(ert-deftest test-ai-vterm--server-display-routes-around-agent () + "Normal: selected window is the agent -> the file lands in the other +window and the agent window keeps the agent buffer." + (cj/test--kill-agent-buffers) + (let ((agent (get-buffer-create "agent [proj]")) + (code (get-buffer-create "code.el")) + (file (get-buffer-create "opened-by-emacsclient.el"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) code) + (let ((agent-win (split-window-right))) + (set-window-buffer agent-win agent) + (select-window agent-win) + (cj/--ai-vterm-server-display file) + (should (eq (window-buffer agent-win) agent)) + (should (get-buffer-window file)) + (should-not (eq (get-buffer-window file) agent-win)))) + (kill-buffer agent) + (kill-buffer code) + (kill-buffer file)))) + +(ert-deftest test-ai-vterm--server-display-splits-when-agent-is-only-window () + "Boundary: the agent is the only window -> a window is split off for the +file; the agent window keeps the agent buffer." + (cj/test--kill-agent-buffers) + (let ((agent (get-buffer-create "agent [solo]")) + (file (get-buffer-create "opened.el"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) agent) + (let ((agent-win (selected-window))) + (cj/--ai-vterm-server-display file) + (should (= 2 (length (window-list (selected-frame) 'never)))) + (should (eq (window-buffer agent-win) agent)) + (should (eq (window-buffer (get-buffer-window file)) file)))) + (kill-buffer agent) + (kill-buffer file)))) + +(ert-deftest test-ai-vterm--server-display-passthrough-when-not-agent () + "Normal: selected window is a regular buffer -> the file is displayed +normally and nothing special happens (no agent window to protect)." + (cj/test--kill-agent-buffers) + (let ((code (get-buffer-create "code.el")) + (file (get-buffer-create "opened.el"))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (set-window-buffer (selected-window) code) + (cj/--ai-vterm-server-display file) + (should (get-buffer-window file))) + (kill-buffer code) + (kill-buffer file)))) + +(ert-deftest test-ai-vterm--server-window-wired-to-helper () + "Normal: the module sets `server-window' to its display function." + (should (eq server-window #'cj/--ai-vterm-server-display))) + +(provide 'test-ai-vterm--server-display) +;;; test-ai-vterm--server-display.el ends here |
