diff options
| author | Craig Jennings <c@cjennings.net> | 2026-05-11 15:35:43 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-05-11 15:35:43 -0500 |
| commit | 0ddbcde1e9f17021377f4160b39cd0790afcbdcc (patch) | |
| tree | d1872d799dc7554b128989411a23b9cad65a6671 | |
| parent | f837e5f7464932fc49c10a7442dc1a23af61b257 (diff) | |
| download | dotemacs-0ddbcde1e9f17021377f4160b39cd0790afcbdcc.tar.gz dotemacs-0ddbcde1e9f17021377f4160b39cd0790afcbdcc.zip | |
feat(window): kill the other window's buffer with C-; b K
`cj/kill-other-window-buffer' (in undead-buffers.el, on `C-; b K') kills or buries the buffer shown in the other window and leaves that window and the split alone. The window just shows whatever bury/kill surfaces next. It reuses `cj/kill-buffer-or-bury-alive', so buffers in `cj/undead-buffer-list' (like `*scratch*') get buried. With more than two windows it acts on `next-window'. Sibling of `cj/kill-other-window' (M-S-o), which deletes the other window. This one keeps it.
| -rw-r--r-- | modules/custom-buffer-file.el | 7 | ||||
| -rw-r--r-- | modules/undead-buffers.el | 16 | ||||
| -rw-r--r-- | tests/test-undead-buffers--kill-other-window-buffer.el | 74 |
3 files changed, 96 insertions, 1 deletions
diff --git a/modules/custom-buffer-file.el b/modules/custom-buffer-file.el index f4401d1f..ef4fc945 100644 --- a/modules/custom-buffer-file.el +++ b/modules/custom-buffer-file.el @@ -17,6 +17,8 @@ ;; ;; Keybindings under ~C-; b~: ;; - ~C-; b k~ kill buffer and window (delete window, kill/bury buffer) +;; - ~C-; b K~ kill the other window's buffer, keeping that window/split +;; (cj/kill-other-window-buffer in undead-buffers.el) ;; - ~C-; b <arrow>~ move the active window's divider that way (via windsize); ;; bare arrows keep nudging until any other key (cj/window-resize-sticky in ;; ui-navigation.el) @@ -37,8 +39,9 @@ (require 'mm-decode) (require 'external-open) ;; for cj/xdg-open, cj/open-this-file-with -;; cj/kill-buffer-and-window defined in undead-buffers.el +;; cj/kill-buffer-and-window and cj/kill-other-window-buffer defined in undead-buffers.el (declare-function cj/kill-buffer-and-window "undead-buffers") +(declare-function cj/kill-other-window-buffer "undead-buffers") ;; cj/window-resize-sticky (C-; b <arrow>) defined in ui-navigation.el (declare-function cj/window-resize-sticky "ui-navigation") @@ -449,6 +452,7 @@ Signals an error if: "n" #'cj/copy-buffer-name "l" #'cj/copy-link-to-buffer-file "k" #'cj/kill-buffer-and-window + "K" #'cj/kill-other-window-buffer "P" #'cj/print-buffer-ps "t" #'cj/clear-to-top-of-buffer "b" #'cj/clear-to-bottom-of-buffer @@ -486,6 +490,7 @@ Signals an error if: "C-; b n" "copy buffer name" "C-; b l" "copy file link" "C-; b k" "kill buffer and window" + "C-; b K" "kill other window's buffer" "C-; b P" "print to PS" "C-; b t" "clear to top" "C-; b b" "clear to bottom" diff --git a/modules/undead-buffers.el b/modules/undead-buffers.el index f79afb4b..c85bde94 100644 --- a/modules/undead-buffers.el +++ b/modules/undead-buffers.el @@ -8,6 +8,8 @@ ;; ;; Additional helper commands and key bindings: ;; - C-; b k (=cj/kill-buffer-and-window=): delete this window and bury/kill its buffer. +;; - C-; b K (=cj/kill-other-window-buffer=): bury/kill the other window's buffer, +;; keeping that window and the split intact. ;; - M-O (=cj/kill-other-window=): delete the next window and bury/kill its buffer. ;; - M-M (=cj/kill-all-other-buffers-and-windows=): kill or bury all buffers except ;; the current one and delete all other windows. @@ -77,6 +79,20 @@ ARG is passed to `save-some-buffers'." (cj/kill-buffer-or-bury-alive buf))) (keymap-global-set "M-S-o" #'cj/kill-other-window) +(defun cj/kill-other-window-buffer () + "Kill or bury the buffer shown in the other window, keeping that window +and the split intact -- the window then shows whatever bury/kill surfaces +next. With more than two windows, acts on `next-window'. + +Sibling of `cj/kill-other-window', which deletes the other window; here the +split is preserved. Buffers in `cj/undead-buffer-list' are buried." + (interactive) + (if (one-window-p) + (user-error "No other window") + (with-selected-window (next-window) + (cj/kill-buffer-or-bury-alive (current-buffer))))) +;; Keybinding in custom-buffer-file.el (C-; b K) + (defun cj/kill-all-other-buffers-and-windows () "Kill or bury all other buffers, then delete other windows." (interactive) diff --git a/tests/test-undead-buffers--kill-other-window-buffer.el b/tests/test-undead-buffers--kill-other-window-buffer.el new file mode 100644 index 00000000..4dbbb710 --- /dev/null +++ b/tests/test-undead-buffers--kill-other-window-buffer.el @@ -0,0 +1,74 @@ +;;; test-undead-buffers--kill-other-window-buffer.el --- Tests for cj/kill-other-window-buffer -*- lexical-binding: t; -*- + +;;; Commentary: +;; `cj/kill-other-window-buffer' kills (or buries, for `cj/undead-buffer-list' +;; buffers) the buffer shown in the other window, leaving that window and the +;; split intact -- the window then shows whatever bury/kill surfaces next. +;; Sibling of `cj/kill-other-window' (which deletes the other window); the +;; distinguishing trait here is that the split is preserved. + +;;; Code: + +(require 'ert) +(require 'cl-lib) + +(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 'undead-buffers) + +(ert-deftest test-undead-buffers-kill-other-window-buffer-keeps-the-window () + "Normal: kills the other window's (non-undead) buffer but keeps the window +and the split -- the current window is left untouched." + (let ((other (generate-new-buffer "test-kill-other-window-buffer")) + (orig (copy-sequence cj/undead-buffer-list))) + (unwind-protect + (save-window-excursion + (delete-other-windows) + (split-window-right) + (let* ((win-a (selected-window)) + (buf-a (window-buffer win-a)) + (win-b (next-window win-a))) + (set-window-buffer win-b other) + (select-window win-a) + (cj/kill-other-window-buffer) + (should (window-live-p win-b)) + (should-not (buffer-live-p other)) + (should (eq (window-buffer win-a) buf-a)))) + (setq cj/undead-buffer-list orig) + (when (buffer-live-p other) (kill-buffer other))))) + +(ert-deftest test-undead-buffers-kill-other-window-buffer-buries-undead () + "Boundary: an undead buffer in the other window is buried, not killed -- +still alive, no longer shown there; the window stays." + (let ((other (generate-new-buffer "test-kill-other-undead")) + (orig (copy-sequence cj/undead-buffer-list))) + (unwind-protect + (save-window-excursion + (add-to-list 'cj/undead-buffer-list (buffer-name other)) + (delete-other-windows) + (split-window-right) + (let* ((win-a (selected-window)) + (win-b (next-window win-a))) + (set-window-buffer win-b other) + (select-window win-a) + (cj/kill-other-window-buffer) + (should (window-live-p win-b)) + (should (buffer-live-p other)) + (should-not (eq (window-buffer win-b) other)))) + (setq cj/undead-buffer-list orig) + (when (buffer-live-p other) (kill-buffer other))))) + +(ert-deftest test-undead-buffers-kill-other-window-buffer-errors-with-one-window () + "Error: with only one window there is no other window to act on." + (save-window-excursion + (delete-other-windows) + (should-error (cj/kill-other-window-buffer) :type 'user-error))) + +(ert-deftest test-undead-buffers-kill-other-window-buffer-bound-under-c-semicolon-b () + "Normal: reachable via C-; b K." + (require 'custom-buffer-file) + (should (eq (keymap-lookup cj/buffer-and-file-map "K") + #'cj/kill-other-window-buffer))) + +(provide 'test-undead-buffers--kill-other-window-buffer) +;;; test-undead-buffers--kill-other-window-buffer.el ends here |
