diff options
| -rw-r--r-- | modules/ai-vterm.el | 74 | ||||
| -rw-r--r-- | tests/test-ai-vterm--f9-in-vterm.el | 13 | ||||
| -rw-r--r-- | tests/test-ai-vterm--pick-buffer-candidates.el | 80 |
3 files changed, 18 insertions, 149 deletions
diff --git a/modules/ai-vterm.el b/modules/ai-vterm.el index 975374f6..108a73ca 100644 --- a/modules/ai-vterm.el +++ b/modules/ai-vterm.el @@ -32,10 +32,10 @@ ;; picker, even when an agent buffer is currently displayed. ;; Used when the user wants to start a new project session ;; instead of toggling the current one. -;; - M-F9 `cj/ai-vterm-pick-buffer' -- pick from the alive agent -;; buffers (no project candidates, no creation). When an agent -;; buffer is currently displayed, the picked buffer replaces it -;; in that window so orientation and size are preserved. +;; - M-F9 `cj/toggle-gptel' -- toggle gptel's *AI-Assistant* window. +;; Lives outside this module (defined in `modules/ai-config.el') +;; but the binding is grouped with the other F9-family launchers +;; here so the dispatch shape is visible in one place. ;; ;; Existing windmove (Shift-arrows) handles code <-> agent focus ;; toggling. Buffer-move (C-M-arrows) handles side-swap. Neither @@ -595,27 +595,6 @@ without firing real `display-buffer' or `quit-window' calls." (buffers (cons 'redisplay-recent (car buffers))) (t '(pick-project)))))))) -(defun cj/--ai-vterm-pick-buffer-candidates (buffers shown-buffer) - "Build the M-F9 picker alist. - -BUFFERS is an MRU-ordered list of alive AI-vterm buffers. -SHOWN-BUFFER is the AI-vterm buffer currently displayed in this frame, -or nil. - -When SHOWN-BUFFER is one of BUFFERS, it sorts last with a -\" [shown]\" suffix so the default `completing-read' selection lands -on a non-shown candidate (i.e. RET picks \"the other one\"). When -SHOWN-BUFFER is not in BUFFERS (a stale window state), every entry is -treated as non-shown. - -Each cell is (DISPLAY-NAME . BUFFER)." - (let ((non-shown (seq-remove (lambda (b) (eq b shown-buffer)) buffers)) - (shown (when (memq shown-buffer buffers) shown-buffer))) - (append - (mapcar (lambda (b) (cons (buffer-name b) b)) non-shown) - (when shown - (list (cons (format "%s [shown]" (buffer-name shown)) shown)))))) - (defun cj/ai-vterm-pick-project (&optional arg) "Pick an AI-agent project and open or reuse its vterm. @@ -638,41 +617,6 @@ buffer is currently displayed." (when win (select-window win)))) buf)) -(defun cj/ai-vterm-pick-buffer () - "Pick from the alive AI-vterm buffers; switch to the chosen one. - -When an AI-vterm buffer is currently displayed in this frame, the -picked buffer replaces it in the same window via `set-window-buffer'. -Orientation and size are preserved so the user's split layout doesn't -change. When no AI-vterm buffer is displayed, default placement -applies via `display-buffer'. - -The currently-displayed buffer (if any) is sorted last in the picker -with a \" [shown]\" suffix; the default selection lands on a -non-shown candidate so RET means \"give me the other one\". - -Signals `user-error' when no AI-vterm buffers exist. - -Bound to M-F9." - (interactive) - (let ((buffers (cj/--ai-vterm-agent-buffers))) - (unless buffers - (user-error "No agent buffers")) - (let* ((shown-win (cj/--ai-vterm-displayed-agent-window)) - (shown-buf (and shown-win (window-buffer shown-win))) - (alist (cj/--ai-vterm-pick-buffer-candidates buffers shown-buf)) - (chosen (completing-read "AI vterm buffer: " alist nil t)) - (buf (cdr (assoc chosen alist)))) - (cond - ((and shown-win (window-live-p shown-win)) - (set-window-buffer shown-win buf) - (select-window shown-win)) - (t - (display-buffer buf) - (let ((w (get-buffer-window buf))) - (when w (select-window w))))) - buf))) - (defun cj/ai-vterm (&optional arg) "Smart F9 dispatch for the AI-vterm launcher. @@ -687,9 +631,9 @@ Behavior depends on the current state: With prefix ARG, display the buffer without selecting its window when a buffer is being shown (no effect on the toggle-off branch). -See `cj/ai-vterm-pick-project' (C-F9) to force the project picker -and `cj/ai-vterm-pick-buffer' (M-F9) to switch among existing -AI-vterm buffers without touching the project list." +See `cj/ai-vterm-pick-project' (C-F9) to force the project picker. +M-F9 toggles gptel's *AI-Assistant* window (`cj/toggle-gptel', +defined in `modules/ai-config.el')." (interactive "P") (pcase (cj/--ai-vterm-dispatch) (`(toggle-off . ,win) @@ -738,7 +682,7 @@ AI-vterm buffers without touching the project list." (keymap-global-set "<f9>" #'cj/ai-vterm) (keymap-global-set "C-<f9>" #'cj/ai-vterm-pick-project) -(keymap-global-set "M-<f9>" #'cj/ai-vterm-pick-buffer) +(keymap-global-set "M-<f9>" #'cj/toggle-gptel) ;; vterm binds <f1>..<f12> to `vterm--self-insert', so a plain <f9> typed ;; while point is inside an agent buffer gets sent to the terminal program @@ -749,7 +693,7 @@ AI-vterm buffers without touching the project list." (with-eval-after-load 'vterm (keymap-set vterm-mode-map "<f9>" #'cj/ai-vterm) (keymap-set vterm-mode-map "C-<f9>" #'cj/ai-vterm-pick-project) - (keymap-set vterm-mode-map "M-<f9>" #'cj/ai-vterm-pick-buffer)) + (keymap-set vterm-mode-map "M-<f9>" #'cj/toggle-gptel)) ;; ---------- emacsclient: keep opened files off the agent vterm ---------- ;; diff --git a/tests/test-ai-vterm--f9-in-vterm.el b/tests/test-ai-vterm--f9-in-vterm.el index 1355bd6a..ff8939c8 100644 --- a/tests/test-ai-vterm--f9-in-vterm.el +++ b/tests/test-ai-vterm--f9-in-vterm.el @@ -24,19 +24,24 @@ (should (eq (keymap-lookup vterm-mode-map "<f9>") #'cj/ai-vterm))) (ert-deftest test-ai-vterm-f9-family-bound-in-vterm-mode-map () - "Normal: the C-/M- F9 variants are bound in `vterm-mode-map' too." + "Normal: the C-/M- F9 variants are bound in `vterm-mode-map' too. +`M-<f9>' toggles gptel's *AI-Assistant* window (rebound here from +the old `cj/ai-vterm-pick-buffer' command, which was removed)." (should (eq (keymap-lookup vterm-mode-map "C-<f9>") #'cj/ai-vterm-pick-project)) - (should (eq (keymap-lookup vterm-mode-map "M-<f9>") #'cj/ai-vterm-pick-buffer))) + (should (eq (keymap-lookup vterm-mode-map "M-<f9>") #'cj/toggle-gptel))) (ert-deftest test-ai-vterm-f9-not-self-insert-in-vterm () "Boundary: vterm's default <f9> -> `vterm--self-insert' was overridden." (should-not (eq (keymap-lookup vterm-mode-map "<f9>") 'vterm--self-insert))) (ert-deftest test-ai-vterm-f9-still-bound-globally () - "Normal: the global F9 family bindings are intact." + "Normal: the global F9 family bindings are intact. +`<f9>' toggles the ai-vterm agent window; `C-<f9>' picks a project +agent; `M-<f9>' toggles gptel's *AI-Assistant* window (rebound from +the retired `cj/ai-vterm-pick-buffer')." (should (eq (lookup-key (current-global-map) (kbd "<f9>")) #'cj/ai-vterm)) (should (eq (lookup-key (current-global-map) (kbd "C-<f9>")) #'cj/ai-vterm-pick-project)) - (should (eq (lookup-key (current-global-map) (kbd "M-<f9>")) #'cj/ai-vterm-pick-buffer))) + (should (eq (lookup-key (current-global-map) (kbd "M-<f9>")) #'cj/toggle-gptel))) (provide 'test-ai-vterm--f9-in-vterm) ;;; test-ai-vterm--f9-in-vterm.el ends here diff --git a/tests/test-ai-vterm--pick-buffer-candidates.el b/tests/test-ai-vterm--pick-buffer-candidates.el deleted file mode 100644 index c32039de..00000000 --- a/tests/test-ai-vterm--pick-buffer-candidates.el +++ /dev/null @@ -1,80 +0,0 @@ -;;; test-ai-vterm--pick-buffer-candidates.el --- Tests for the M-F9 candidate builder -*- lexical-binding: t; -*- - -;;; Commentary: -;; The candidate builder is a pure function: given an MRU list of -;; alive AI-vterm buffers and the currently-displayed buffer (or -;; nil), it returns an alist of (DISPLAY-NAME . BUFFER) cells. -;; -;; Sort rule: non-shown buffers come first in their input order, -;; then the shown buffer (if it's in the list) appears last with a -;; \" [shown]\" suffix. The intent is that the default `completing- -;; read' selection lands on a non-shown candidate so RET means -;; \"give me the other one\". - -;;; 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 'testutil-vterm-buffers) - -(ert-deftest test-ai-vterm--pick-buffer-candidates-empty-buffers () - "Boundary: empty buffer list -> empty alist regardless of shown." - (cj/test--kill-agent-buffers) - (should (null (cj/--ai-vterm-pick-buffer-candidates nil nil))) - (should (null (cj/--ai-vterm-pick-buffer-candidates nil 'sentinel)))) - -(ert-deftest test-ai-vterm--pick-buffer-candidates-shown-nil () - "Normal: shown is nil -> straight alist in input order, no marker." - (cj/test--kill-agent-buffers) - (let ((b1 (get-buffer-create "agent [a]")) - (b2 (get-buffer-create "agent [b]"))) - (unwind-protect - (let ((result (cj/--ai-vterm-pick-buffer-candidates (list b1 b2) nil))) - (should (equal result `(("agent [a]" . ,b1) - ("agent [b]" . ,b2))))) - (kill-buffer b1) - (kill-buffer b2)))) - -(ert-deftest test-ai-vterm--pick-buffer-candidates-shown-promotes-non-shown () - "Normal: shown buffer sorts last with [shown] suffix; others first." - (cj/test--kill-agent-buffers) - (let ((b1 (get-buffer-create "agent [a]")) - (b2 (get-buffer-create "agent [b]")) - (b3 (get-buffer-create "agent [c]"))) - (unwind-protect - (let ((result (cj/--ai-vterm-pick-buffer-candidates - (list b1 b2 b3) b1))) - (should (equal result - `(("agent [b]" . ,b2) - ("agent [c]" . ,b3) - ("agent [a] [shown]" . ,b1))))) - (kill-buffer b1) - (kill-buffer b2) - (kill-buffer b3)))) - -(ert-deftest test-ai-vterm--pick-buffer-candidates-shown-only-buffer () - "Boundary: shown is the only entry -> single cell with [shown] marker." - (cj/test--kill-agent-buffers) - (let ((b1 (get-buffer-create "agent [a]"))) - (unwind-protect - (let ((result (cj/--ai-vterm-pick-buffer-candidates (list b1) b1))) - (should (equal result `(("agent [a] [shown]" . ,b1))))) - (kill-buffer b1)))) - -(ert-deftest test-ai-vterm--pick-buffer-candidates-shown-not-in-buffers () - "Boundary: stale shown buffer not in list -> all cells are non-shown." - (cj/test--kill-agent-buffers) - (let ((b1 (get-buffer-create "agent [a]")) - (b-stale (get-buffer-create "agent [stale]"))) - (unwind-protect - (let ((result (cj/--ai-vterm-pick-buffer-candidates - (list b1) b-stale))) - (should (equal result `(("agent [a]" . ,b1))))) - (kill-buffer b1) - (kill-buffer b-stale)))) - -(provide 'test-ai-vterm--pick-buffer-candidates) -;;; test-ai-vterm--pick-buffer-candidates.el ends here |
