diff options
Diffstat (limited to 'modules/org-capture-config.el')
| -rw-r--r-- | modules/org-capture-config.el | 63 |
1 files changed, 56 insertions, 7 deletions
diff --git a/modules/org-capture-config.el b/modules/org-capture-config.el index 292e26a7..b7250f1e 100644 --- a/modules/org-capture-config.el +++ b/modules/org-capture-config.el @@ -157,6 +157,8 @@ re-scanning large target files after the first successful lookup." (interactive) (user-error "Key disabled during capture -- finalize with C-c C-c or abort with C-c C-k")) +(defvar org-capture-mode-map) + (with-eval-after-load 'org-capture (dolist (key '("<f1>" "<f10>" "<f11>" "<f12>" "M-SPC")) (keymap-set org-capture-mode-map key #'cj/--org-capture-blocked-key))) @@ -381,10 +383,10 @@ A popup still mid-capture has capture UI and is not reapable, so it is spared." (defun cj/org-capture-reap-popup-frames () "Delete every quick-capture popup frame that no longer shows capture UI. Reaps across ALL frames, not just the selected one: a capture that finalizes, -aborts, or errors while the daemon's selected frame is something else (the common -multi-frame case) still cleans up its \"org-capture\" popup, while a popup -mid-capture is spared. Never deletes the last remaining frame. Safe to call -anytime — bound to nothing, run via M-x when a stray popup needs clearing." +aborts, or errors while the daemon's selected frame is something else (the +common multi-frame case) still cleans up its \"org-capture\" popup, while a +popup mid-capture is spared. Never deletes the last remaining frame. Safe to +call anytime — bound to nothing, run via M-x when a stray popup needs clearing." (interactive) (dolist (f (frame-list)) (when (and (frame-live-p f) @@ -395,9 +397,7 @@ anytime — bound to nothing, run via M-x when a stray popup needs clearing." (window-list f 'no-minibuf)))) (delete-frame f)))) -;; Reap on every capture exit. `remove-hook' first so a live module reload swaps -;; the retired narrow (selected-frame) handler for this one without leaving both. -(remove-hook 'org-capture-after-finalize-hook #'cj/org-capture--delete-popup-frame) +;; Reap on every capture exit. (add-hook 'org-capture-after-finalize-hook #'cj/org-capture-reap-popup-frames) ;; The popup opens a fresh emacsclient frame still showing the daemon's last @@ -437,6 +437,55 @@ never split the small floating frame." '(cj/org-capture--popup-display-condition cj/org-capture--display-sole-window)) +;; A fresh "org-capture" popup opens showing the daemon's last buffer (see the +;; comment above), and only the capture UI + the reap-on-finalize hook clear it. +;; If a capture aborts before its UI paints (a C-g, an erroring template, a path +;; that skips `cj/quick-capture'), the popup lingers showing whatever was current +;; -- and if that was a live terminal (an eat/vterm Claude Code buffer), eat +;; sizes the terminal to that small popup window and clamps the real frame down +;; to the popup's rows. These two guards keep the popup from ever holding a +;; size-sensitive live buffer: it only ever shows capture UI or *scratch*. + +(defun cj/org-capture--neutralize-frame (frame) + "Point every non-capture-UI window of the \"org-capture\" popup FRAME at +*scratch*. Capture UI (the *Org Select* menu, a CAPTURE-* buffer) is spared, so +this never disturbs a live capture; it only evicts a stray live buffer (the +daemon's last buffer on open, or a buffer restored on abort) that would +otherwise mirror the popup's size onto its source buffer. Idempotent: a window +already on *scratch* is left alone, so it can't loop through the +`window-buffer-change-functions' it fires." + (when (and (frame-live-p frame) + (equal (frame-parameter frame 'name) "org-capture")) + (dolist (w (window-list frame 'no-minibuf)) + (let ((name (buffer-name (window-buffer w)))) + (unless (or (cj/org-capture--popup-sole-window-p "org-capture" name) + (equal name "*scratch*")) + (set-window-buffer w (get-buffer-create "*scratch*"))))))) + +;; Guard 1 (root cause): neutralize the popup the instant it is created, before +;; any capture UI paints, so it never opens mirroring the daemon's last buffer. +(defun cj/org-capture--neutralize-new-frame (frame) + "Neutralize a freshly-made \"org-capture\" popup FRAME on creation. +See `cj/org-capture--neutralize-frame'." + (cj/org-capture--neutralize-frame frame)) + +(add-hook 'after-make-frame-functions #'cj/org-capture--neutralize-new-frame) + +;; Guard 2 (safety net): catch any path the finalize reap misses. If a live +;; buffer is displayed in the popup after creation (an aborted capture restoring +;; the previous buffer, a stray `switch-to-buffer'), evict it at once. +(defun cj/org-capture--neutralize-on-buffer-change (frame-or-window) + "Neutralize the \"org-capture\" popup after any buffer change in FRAME-OR-WINDOW. +`window-buffer-change-functions' passes a frame (global hook) or a window +(buffer-local); handle both." + (let ((frame (if (windowp frame-or-window) + (window-frame frame-or-window) + frame-or-window))) + (cj/org-capture--neutralize-frame frame))) + +(add-hook 'window-buffer-change-functions + #'cj/org-capture--neutralize-on-buffer-change) + ;; The desktop quick-capture popup is launched globally (no browser selection, ;; no mu4e message, no pdf/epub buffer), so the context-dependent templates make ;; no sense there. `cj/quick-capture' captures a single Task straight into the |
