From 3af2d74f84a5289a0b859f1f2352a8b498c93602 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Mon, 29 Jun 2026 18:25:16 -0400 Subject: fix(org-capture): reap stray popup frames reliably The Super+N quick-capture popup frame is named "org-capture" and was torn down by deleting the selected frame on capture exit. When the daemon's selected frame was something else at finalize (common with multiple frames), the real capture frame survived and lingered, showing whatever buffer was behind it. Reap by frame name across all frames instead, sparing any popup still mid-capture (*Org Select* or a CAPTURE-* buffer), and expose cj/org-capture-reap-popup-frames for manual cleanup. --- tests/test-org-capture-config-popup-window.el | 35 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) (limited to 'tests') diff --git a/tests/test-org-capture-config-popup-window.el b/tests/test-org-capture-config-popup-window.el index 671d55ab9..af96ba012 100644 --- a/tests/test-org-capture-config-popup-window.el +++ b/tests/test-org-capture-config-popup-window.el @@ -110,11 +110,11 @@ deletes the popup frame instead of leaving it orphaned. Components integrated: - cj/quick-capture (real) - org-capture (MOCKED — signals user-error \"Abort\") -- cj/org-capture--delete-popup-frame (MOCKED — records the call)" +- cj/org-capture-reap-popup-frames (MOCKED — records the call)" (let ((deleted 0)) (cl-letf (((symbol-function 'org-capture) (lambda (&rest _) (user-error "Abort"))) - ((symbol-function 'cj/org-capture--delete-popup-frame) + ((symbol-function 'cj/org-capture-reap-popup-frames) (lambda () (cl-incf deleted)))) (cj/quick-capture)) (should (= deleted 1)))) @@ -124,7 +124,7 @@ Components integrated: (let ((deleted 0)) (cl-letf (((symbol-function 'org-capture) (lambda (&rest _) (signal 'quit nil))) - ((symbol-function 'cj/org-capture--delete-popup-frame) + ((symbol-function 'cj/org-capture-reap-popup-frames) (lambda () (cl-incf deleted)))) (cj/quick-capture)) (should (= deleted 1)))) @@ -134,19 +134,32 @@ Components integrated: the finalize hook owns that." (let ((deleted 0)) (cl-letf (((symbol-function 'org-capture) (lambda (&rest _) nil)) - ((symbol-function 'cj/org-capture--delete-popup-frame) + ((symbol-function 'cj/org-capture-reap-popup-frames) (lambda () (cl-incf deleted)))) (cj/quick-capture)) (should (= deleted 0)))) -;;; cj/org-capture--popup-frame-p +;;; cj/org-capture--frame-reapable-p -(ert-deftest test-org-capture-config-popup-frame-p () - "Normal/Boundary: true only when the selected frame is named \"org-capture\"." - (cl-letf (((symbol-function 'frame-parameter) (lambda (&rest _) "org-capture"))) - (should (cj/org-capture--popup-frame-p))) - (cl-letf (((symbol-function 'frame-parameter) (lambda (&rest _) "emacs"))) - (should-not (cj/org-capture--popup-frame-p)))) +(ert-deftest test-org-capture-config-frame-reapable-p-no-capture-ui () + "Normal: an \"org-capture\" frame showing only non-capture buffers is reapable." + (should (cj/org-capture--frame-reapable-p + "org-capture" '("agent [.emacs.d]" "*dashboard*")))) + +(ert-deftest test-org-capture-config-frame-reapable-p-capture-buffer-spares () + "Boundary: a CAPTURE-* buffer means the popup is mid-capture — not reapable." + (should-not (cj/org-capture--frame-reapable-p + "org-capture" '("CAPTURE-todo.org" "*dashboard*")))) + +(ert-deftest test-org-capture-config-frame-reapable-p-select-menu-spares () + "Boundary: the *Org Select* template menu means mid-capture — not reapable." + (should-not (cj/org-capture--frame-reapable-p + "org-capture" '("*Org Select*")))) + +(ert-deftest test-org-capture-config-frame-reapable-p-other-frame-never () + "Error: a frame not named \"org-capture\" is never reapable, even when empty." + (should-not (cj/org-capture--frame-reapable-p + "Emacs 30.2 : agent [.emacs.d]" '("agent [.emacs.d]")))) ;;; cj/org-capture--popup-frame (find the popup frame by name) -- cgit v1.2.3