From 95d40f8faaff160574d83c4cea6e06d22442c935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Mon, 17 Jun 2019 13:22:57 -0400 Subject: [PATCH 1/6] Lower consing when figuring out window purposes Using `cl-block` combined with `maphash` prevents creating several intermediate lists of which we only want one item. Note- `purpose--iter-hash` is no longer used, but still updated to lower consing by simply using `push` rather than appending new entries to the tail of the already-gathered-results --- window-purpose-core.el | 30 ++++++++++++++++-------------- window-purpose-utils.el | 4 +--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/window-purpose-core.el b/window-purpose-core.el index 33e8467..19c7b40 100644 --- a/window-purpose-core.el +++ b/window-purpose-core.el @@ -79,12 +79,13 @@ dummy buffer with the purpose 'edit." mode and MODE-CONF. MODE-CONF is a hash table mapping modes to purposes." (when (get-buffer buffer-or-name) ; check if buffer exists - (let* ((major-mode (purpose--buffer-major-mode buffer-or-name)) - (derived-modes (purpose--iter-hash #'(lambda (mode _purpose) mode) - mode-conf)) - (derived-mode (apply #'derived-mode-p derived-modes))) - (when derived-mode - (gethash derived-mode mode-conf))))) + (cl-block nil + (maphash + (let ((buffer-mode (purpose--buffer-major-mode buffer-or-name))) + #'(lambda (mode purpose) + (when (provided-mode-derived-p buffer-mode mode) + (cl-return purpose)))) + mode-conf)))) (defun purpose--buffer-purpose-name (buffer-or-name name-conf) "Return the purpose of buffer BUFFER-OR-NAME, as determined by its @@ -107,13 +108,14 @@ regexp REGEXP." "Return the purpose of buffer BUFFER-OR-NAME, as determined by the regexps matched by its name. REGEXP-CONF is a hash table mapping name regexps to purposes." - (car (remove nil - (purpose--iter-hash - #'(lambda (regexp purpose) - (purpose--buffer-purpose-name-regexp-1 buffer-or-name - regexp - purpose)) - regexp-conf)))) + (cl-block nil + (maphash + #'(lambda (regexp purpose) + (when (purpose--buffer-purpose-name-regexp-1 buffer-or-name + regexp + purpose) + (cl-return purpose))) + regexp-conf))) (defun purpose-buffer-purpose (buffer-or-name) "Get the purpose of buffer BUFFER-OR-NAME. @@ -168,7 +170,7 @@ If no purpose was determined, return `default-purpose'." (defun purpose-buffers-with-purpose (purpose) "Return a list of all existing buffers with purpose PURPOSE." - (cl-remove-if-not #'(lambda (buffer) + (cl-delete-if-not #'(lambda (buffer) (and (eql purpose (purpose-buffer-purpose buffer)) (not (minibufferp buffer)))) (buffer-list))) diff --git a/window-purpose-utils.el b/window-purpose-utils.el index 7e1a650..3a19c86 100644 --- a/window-purpose-utils.el +++ b/window-purpose-utils.el @@ -105,9 +105,7 @@ Example: for each entry in hash-table TABLE." (let (results) (maphash #'(lambda (key value) - (setq results - (append results - (list (funcall function key value))))) + (push (funcall function key value) results)) table) results)) From 079d82ed06aa48415aa4870245fea45338cccf0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Mon, 17 Jun 2019 13:26:05 -0400 Subject: [PATCH 2/6] purpose-x-kill: Don't calculate 'other-buffers' unless necessary Fixes #149 The problem is that 'gathering a list of other buffers with the same purpose' conses due to an inevitable maphash later on, and even though it's not a ton, it adds up quick because this function is called on every kill-buffer call. Even for the tons and tons of background temp buffers used by company, helm, sly, and others. The fix: We don't need to figure out the list of other buffers unless we actually come across a window that was displaying the killed buffer. So this fix just delays calculating it until we actually need it. --- window-purpose-x.el | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/window-purpose-x.el b/window-purpose-x.el index 4db9ec4..8afa7ab 100644 --- a/window-purpose-x.el +++ b/window-purpose-x.el @@ -653,13 +653,22 @@ This function removes the buffer denoted by BUFFER-OR-NAME from all window-local buffer lists." (interactive "bBuffer to replace: ") (let* ((buffer (window-normalize-buffer buffer-or-name)) - (purpose (purpose-buffer-purpose buffer)) - (other-buffers (delete buffer (purpose-buffers-with-purpose purpose)))) + ;; Delay calculating other-buffers until we need it + ;; This prevents unnecessary calculations on temporary + ;; buffers created by `with-temp-buffer' and other likewise + ;; non-displayed buffers + (have-other-buffers nil) + (other-buffers nil)) (dolist (window (window-list-1 nil nil t)) (if (eq (window-buffer window) buffer) (unless (window--delete window t t) - (let ((dedicated (purpose-window-purpose-dedicated-p window)) - (deletable (window-deletable-p window))) + (let* ((purpose (purpose-buffer-purpose buffer)) + (other-buffers (if have-other-buffers + other-buffers + (setq have-other-buffers t + other-buffers (delete buffer (purpose-buffers-with-purpose purpose))))) + (dedicated (purpose-window-purpose-dedicated-p window)) + (deletable (window-deletable-p window))) (cond ((and dedicated other-buffers) ;; dedicated, so replace with a buffer with the same purpose From 99aeec62d0890189a42dd443a9b6e3afea4fd515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Fri, 28 Jun 2019 13:35:11 -0400 Subject: [PATCH 3/6] Revert purpose--buffer-purpose-mode to fix choosing incorrect mode --- window-purpose-core.el | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/window-purpose-core.el b/window-purpose-core.el index 19c7b40..5e07853 100644 --- a/window-purpose-core.el +++ b/window-purpose-core.el @@ -79,13 +79,12 @@ dummy buffer with the purpose 'edit." mode and MODE-CONF. MODE-CONF is a hash table mapping modes to purposes." (when (get-buffer buffer-or-name) ; check if buffer exists - (cl-block nil - (maphash - (let ((buffer-mode (purpose--buffer-major-mode buffer-or-name))) - #'(lambda (mode purpose) - (when (provided-mode-derived-p buffer-mode mode) - (cl-return purpose)))) - mode-conf)))) + (let* ((major-mode (purpose--buffer-major-mode buffer-or-name)) + (derived-modes (purpose--iter-hash #'(lambda (mode _purpose) mode) + mode-conf)) + (derived-mode (apply #'derived-mode-p derived-modes))) + (when derived-mode + (gethash derived-mode mode-conf))))) (defun purpose--buffer-purpose-name (buffer-or-name name-conf) "Return the purpose of buffer BUFFER-OR-NAME, as determined by its From e935c888afb3923c0b42f9aa876b33b08e1c2701 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Fri, 28 Jun 2019 13:36:32 -0400 Subject: [PATCH 4/6] Replace cl-block with catch Better backwards-compatibility and no cl-lib dependency --- window-purpose-core.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/window-purpose-core.el b/window-purpose-core.el index 5e07853..be98b32 100644 --- a/window-purpose-core.el +++ b/window-purpose-core.el @@ -107,13 +107,13 @@ regexp REGEXP." "Return the purpose of buffer BUFFER-OR-NAME, as determined by the regexps matched by its name. REGEXP-CONF is a hash table mapping name regexps to purposes." - (cl-block nil + (catch found (maphash #'(lambda (regexp purpose) (when (purpose--buffer-purpose-name-regexp-1 buffer-or-name regexp purpose) - (cl-return purpose))) + (throw 'found purpose))) regexp-conf))) (defun purpose-buffer-purpose (buffer-or-name) From 66a2d90d4990d0bc3d2e19431680beed85bf3845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Fri, 28 Jun 2019 13:37:19 -0400 Subject: [PATCH 5/6] Refactor setting other-buffers to clean it up --- window-purpose-x.el | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/window-purpose-x.el b/window-purpose-x.el index 8afa7ab..407f525 100644 --- a/window-purpose-x.el +++ b/window-purpose-x.el @@ -657,18 +657,17 @@ window-local buffer lists." ;; This prevents unnecessary calculations on temporary ;; buffers created by `with-temp-buffer' and other likewise ;; non-displayed buffers - (have-other-buffers nil) + (other-buffers-calculated nil) (other-buffers nil)) (dolist (window (window-list-1 nil nil t)) (if (eq (window-buffer window) buffer) (unless (window--delete window t t) (let* ((purpose (purpose-buffer-purpose buffer)) - (other-buffers (if have-other-buffers - other-buffers - (setq have-other-buffers t - other-buffers (delete buffer (purpose-buffers-with-purpose purpose))))) (dedicated (purpose-window-purpose-dedicated-p window)) (deletable (window-deletable-p window))) + (unless other-buffers-calculated + (setq other-buffers (delete buffer (purpose-buffers-with-purpose purpose)) + other-buffers-calculated t)) (cond ((and dedicated other-buffers) ;; dedicated, so replace with a buffer with the same purpose From fbbb370cfca274ccb03459f8cd03d6cf45631f06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilfredo=20Vel=C3=A1zquez-Rodr=C3=ADguez?= Date: Fri, 28 Jun 2019 13:44:02 -0400 Subject: [PATCH 6/6] Fix typo in previous commit (need to quote catch name) --- window-purpose-core.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/window-purpose-core.el b/window-purpose-core.el index be98b32..b3be2f9 100644 --- a/window-purpose-core.el +++ b/window-purpose-core.el @@ -107,7 +107,7 @@ regexp REGEXP." "Return the purpose of buffer BUFFER-OR-NAME, as determined by the regexps matched by its name. REGEXP-CONF is a hash table mapping name regexps to purposes." - (catch found + (catch 'found (maphash #'(lambda (regexp purpose) (when (purpose--buffer-purpose-name-regexp-1 buffer-or-name