aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md5
-rw-r--r--README.md4
-rw-r--r--perspective.el48
-rw-r--r--test/test-perspective.el63
4 files changed, 111 insertions, 9 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a69daa0..2720880 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Temporary `switch-to-buffer` displays with non-nil `norecord` no longer add the displayed buffer to the current perspective. This fixes `consult-buffer` preview importing previewed buffers ([#225](https://github.com/nex3/perspective-el/issues/225)).
+### Added
+
+- `persp-switch-to-buffer-behavior`: configure whether `persp-switch-to-buffer*` imports buffers from other perspectives into the current perspective or switches to an owning perspective instead.
+
+
## [2.21] — 2026-02-10
### Fixed
diff --git a/README.md b/README.md
index db74bd3..515ae5c 100644
--- a/README.md
+++ b/README.md
@@ -383,6 +383,10 @@ Both these functions behave like the built-ins, but use `completing-read`
directly. When called normally, they list buffers filtered by the current
perspective. With a prefix argument, they list buffers in all perspectives.
+`persp-switch-to-buffer*` imports a selected buffer into the current
+perspective by default; set `persp-switch-to-buffer-behavior` to `switch` if
+you prefer it to jump to an existing owning perspective instead.
+
The following sample `use-package` invocation changes Emacs default key bindings
to use the replacements:
diff --git a/perspective.el b/perspective.el
index 04fdbc0..7a8bcdb 100644
--- a/perspective.el
+++ b/perspective.el
@@ -145,6 +145,20 @@ TODO: Eventually eliminate this setting?"
(defalias 'persp-avoid-killing-last-buffer-in-perspective
'persp-feature-flag-prevent-killing-last-buffer-in-perspective)
+(defcustom persp-switch-to-buffer-behavior 'import
+ "How Perspective-owned buffer switchers should handle other-perspective buffers.
+
+If the value is `import', display the selected buffer in the current
+perspective, importing it if necessary.
+
+If the value is `switch', switch to a perspective that already contains
+the selected buffer before displaying it.
+
+This currently affects `persp-switch-to-buffer*'."
+ :group 'perspective-mode
+ :type '(choice (const :tag "Import into current perspective" import)
+ (const :tag "Switch to owning perspective" switch)))
+
(defcustom persp-purge-initial-persp-on-save nil
"When non-nil, kills all the buffers in the initial perspective upon state save.
@@ -974,19 +988,35 @@ Prefers perspectives in the selected frame."
(cons frame (persp-name persp)))))
nil)
-(defun persp-switch-to-buffer (buffer-or-name)
+(cl-defun persp--show-buffer (buffer-or-name &key norecord (behavior 'import))
+ "Display BUFFER-OR-NAME according to BEHAVIOR.
+
+If BEHAVIOR is `import', display the buffer in the current perspective.
+If it is `switch', switch to a perspective containing the buffer first.
+
+If NORECORD is non-nil, pass it through to `switch-to-buffer' and
+`persp-switch'."
+ (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
+ (cl-ecase behavior
+ (import
+ (switch-to-buffer buffer norecord))
+ (switch
+ (if (persp-is-current-buffer buffer)
+ (switch-to-buffer buffer norecord)
+ (let ((other-persp (persp-buffer-in-other-p buffer)))
+ (when (eq (car-safe other-persp) (selected-frame))
+ (persp-switch (cdr other-persp) norecord))
+ (if-let ((window (get-buffer-window buffer (selected-frame))))
+ (select-window window norecord)
+ (switch-to-buffer buffer norecord))))))))
+
+(defun persp-switch-to-buffer (buffer-or-name &optional norecord)
"Like `switch-to-buffer', but switches to another perspective if necessary."
(interactive
(list
(let ((read-buffer-function nil))
(read-buffer-to-switch "Switch to buffer: "))))
- (let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
- (if (persp-is-current-buffer buffer)
- (switch-to-buffer buffer)
- (let ((other-persp (persp-buffer-in-other-p buffer)))
- (when (eq (car-safe other-persp) (selected-frame))
- (persp-switch (cdr other-persp)))
- (switch-to-buffer buffer)))))
+ (persp--show-buffer buffer-or-name :norecord norecord :behavior 'switch))
(cl-defun persp-maybe-kill-buffer ()
"Don't kill a buffer if it's the only buffer in a perspective.
@@ -1639,7 +1669,7 @@ PERSP-SET-IDO-BUFFERS)."
nil nil nil nil
other)))))
(let ((buffer (window-normalize-buffer-to-switch-to buffer-or-name)))
- (switch-to-buffer buffer)))
+ (persp--show-buffer buffer :behavior persp-switch-to-buffer-behavior)))
;; Buffer killing integration: useful for frameworks which enhance the
;; built-in completing-read (e.g., Selectrum).
diff --git a/test/test-perspective.el b/test/test-perspective.el
index 6c55ca5..fbf2917 100644
--- a/test/test-perspective.el
+++ b/test/test-perspective.el
@@ -2130,6 +2130,69 @@ buffers into any perspective."
(should-not (persp-is-current-buffer dummy-buffer))
(should (persp-test-buffer-in-persps dummy-buffer "A")))))
+(ert-deftest basic-persp-switch-to-buffer*-imports-by-default ()
+ "Test that `persp-switch-to-buffer*' imports other-perspective buffers by default."
+ (persp-test-with-persp
+ (persp-test-with-temp-buffers (dummy-buffer)
+ (persp-switch "A")
+ (switch-to-buffer dummy-buffer)
+ (should (persp-test-buffer-in-persps dummy-buffer "A"))
+ (persp-switch "main")
+ (should-not (persp-is-current-buffer dummy-buffer))
+ (let ((persp-switch-to-buffer-behavior 'import))
+ (persp-switch-to-buffer* dummy-buffer))
+ (should (equal (persp-current-name) "main"))
+ (should (eq (current-buffer) dummy-buffer))
+ (should (persp-test-buffer-in-persps dummy-buffer "main" "A")))))
+
+(ert-deftest basic-persp-switch-to-buffer*-switches-when-configured ()
+ "Test that `persp-switch-to-buffer*' can switch to the owning perspective."
+ (persp-test-with-persp
+ (persp-test-with-temp-buffers (dummy-buffer)
+ (persp-switch "A")
+ (switch-to-buffer dummy-buffer)
+ (should (persp-test-buffer-in-persps dummy-buffer "A"))
+ (persp-switch "main")
+ (should-not (persp-is-current-buffer dummy-buffer))
+ (let ((persp-switch-to-buffer-behavior 'switch))
+ (persp-switch-to-buffer* dummy-buffer))
+ (should (equal (persp-current-name) "A"))
+ (should (eq (current-buffer) dummy-buffer))
+ (should (persp-test-buffer-in-persps dummy-buffer "A")))))
+
+(ert-deftest basic-persp-switch-to-buffer*-selects-existing-window-when-switching ()
+ "Test that switching prefers an existing visible window for the target buffer."
+ (unwind-protect
+ (persp-test-with-persp
+ (persp-test-with-files nil (A1 A2 A3 B1 B2 B3 B4)
+ (persp-test-make-sample-environment)
+ (persp-switch "A")
+ (persp-set-buffer A2)
+ (persp-switch "main")
+ (let ((persp-switch-to-buffer-behavior 'switch))
+ (persp-switch-to-buffer* A2))
+ (should (equal (persp-current-name) "A"))
+ (should (eq (current-buffer) A2))
+ (should (eq (window-buffer (selected-window)) A2))
+ (should (equal (list "A1" "A2" "A3")
+ (sort (mapcar #'buffer-name (mapcar #'window-buffer (window-list)))
+ #'string-lessp)))))
+ (persp-test-clean-files "A1" "A2" "A3" "B1" "B2" "B3" "B4")))
+
+(ert-deftest basic-persp-switch-to-buffer-ignores-configured-import-behavior ()
+ "Test that `persp-switch-to-buffer' keeps its switch semantics."
+ (persp-test-with-persp
+ (persp-test-with-temp-buffers (dummy-buffer)
+ (persp-switch "A")
+ (switch-to-buffer dummy-buffer)
+ (should (persp-test-buffer-in-persps dummy-buffer "A"))
+ (persp-switch "main")
+ (let ((persp-switch-to-buffer-behavior 'import))
+ (persp-switch-to-buffer dummy-buffer))
+ (should (equal (persp-current-name) "A"))
+ (should (eq (current-buffer) dummy-buffer))
+ (should (persp-test-buffer-in-persps dummy-buffer "A")))))
+
(defmacro persp-test-make-sample-environment ()
"Make a test environment with the following window layout: