diff options
| author | Constantine Vetoshev <vetoshev@gmail.com> | 2026-04-02 22:38:16 -0700 |
|---|---|---|
| committer | Constantine Vetoshev <vetoshev@gmail.com> | 2026-04-02 22:38:16 -0700 |
| commit | 230cabf4c1406569bac416cff9502ae23648e3f8 (patch) | |
| tree | 259fe4d91e151d3dc0610d9b9dfa775184d74195 | |
| parent | 1271ac579798fe65ba2246a72a44efb1eeeba2ec (diff) | |
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | perspective.el | 12 | ||||
| -rw-r--r-- | test/test-perspective.el | 21 |
3 files changed, 32 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index b90c9af..90255d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ 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)). - `persp-maybe-kill-buffer`: improve performance by avoiding switching perspectives and rebuilding buffer-name lists ([#226](https://github.com/nex3/perspective-el/issues/226)). +- `persp-delete-frame`: guard against reentrant frame-deletion cleanup to avoid excessive Lisp nesting when killing frames with dedicated windows ([#195](https://github.com/nex3/perspective-el/issues/195)). ### Added diff --git a/perspective.el b/perspective.el index 962a500..1d4191c 100644 --- a/perspective.el +++ b/perspective.el @@ -404,6 +404,12 @@ Run with the activated perspective active.") (defvar persp--winner-after-load-registered nil "Non-nil when Winner setup has been registered via `eval-after-load'.") +(defvar persp--delete-frame-in-progress nil + "Non-nil while `persp-delete-frame' is cleaning up a frame. +This prevents reentrant calls when killing a perspective causes a +buffer kill, which may trigger another `delete-frame' while the +original frame teardown is still in progress.") + (defvar persp-mode-map (make-sparse-keymap) "Keymap for perspective-mode.") @@ -1551,8 +1557,10 @@ By default, this uses the current frame." "Clean up perspectives in FRAME. By default this uses the current frame." (with-selected-frame frame - (unless persp-started-after-server-mode - (mapcar #'persp-kill (persp-names))))) + (unless (or persp-started-after-server-mode + persp--delete-frame-in-progress) + (let ((persp--delete-frame-in-progress t)) + (mapc #'persp-kill (persp-names)))))) (defun persp-make-variable-persp-local (variable) "Make VARIABLE become perspective-local. diff --git a/test/test-perspective.el b/test/test-perspective.el index c4f1331..31f3272 100644 --- a/test/test-perspective.el +++ b/test/test-perspective.el @@ -2427,4 +2427,25 @@ persp-test-make-sample-environment." (sort (persp-get-buffer-names "C") #'string-lessp)))))))) (persp-test-clean-files "A1" "A2" "B1" "B2" "C1" "C2")))) +(ert-deftest basic-persp-delete-frame-ignores-reentrant-calls () + "Test that `persp-delete-frame' ignores nested reentrant calls." + (persp-test-with-persp + (persp-switch "A") + (persp-switch "B") + (let ((expected-names (sort (copy-sequence (persp-names)) #'string-lessp)) + killed-names + reentered) + (cl-letf (((symbol-function 'persp-kill) + (lambda (name) + (push name killed-names) + ;; Simulate a nested `delete-frame' triggered while + ;; perspective cleanup is already in progress. + (unless reentered + (setq reentered t) + (persp-delete-frame (selected-frame)))))) + (persp-delete-frame (selected-frame))) + (should reentered) + (should (equal expected-names + (sort killed-names #'string-lessp)))))) + ;;; test-perspective.el ends here |
