Merge pull request #1271 from flatwhatson/kill-project

* Add doom/kill-project-buffers command

Prompts for an open project and kills all its buffers.  This is useful
for closing `.emacs.d` in an effort to get some *billable* work done.

Added `doom-fixup-windows` and `doom-kill-buffer(s)-fixup-windows`
helper functions for leaving affected windows on a real buffer or the
fallback buffer.

Fixed `doom/kill-this-buffer-in-all-windows` to properly "fixup"
windows.

* Code review (squash)

* Code review (squash)
This commit is contained in:
Henrik Lissner 2019-04-05 02:06:29 -04:00 committed by GitHub
commit 14e7e1b590
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -56,17 +56,32 @@ scratch buffer. See `doom-fallback-buffer-name' to change this."
(defalias 'doom-buffer-list #'buffer-list) (defalias 'doom-buffer-list #'buffer-list)
;;;###autoload ;;;###autoload
(defun doom-project-buffer-list () (defun doom-project-buffer-list (&optional project)
"Return a list of buffers belonging to the current project. "Return a list of buffers belonging to the specified PROJECT.
If PROJECT is nil, default to the current project.
If no project is active, return all buffers." If no project is active, return all buffers."
(let ((buffers (doom-buffer-list))) (let ((buffers (doom-buffer-list)))
(if-let* ((project-root (doom-project-root))) (if-let* ((project-root
(if project (expand-file-name project)
(doom-project-root))))
(cl-loop for buf in buffers (cl-loop for buf in buffers
if (projectile-project-buffer-p buf project-root) if (projectile-project-buffer-p buf project-root)
collect buf) collect buf)
buffers))) buffers)))
;;;###autoload
(defun doom-open-projects ()
"Return a list of projects with open buffers."
(cl-loop with projects = (make-hash-table :test 'equal :size 8)
for buffer in (doom-buffer-list)
if (buffer-live-p buffer)
if (doom-real-buffer-p buffer)
if (with-current-buffer buffer (doom-project-root))
do (puthash (abbreviate-file-name it) t projects)
finally return (hash-table-keys projects)))
;;;###autoload ;;;###autoload
(defun doom-dired-buffer-p (buf) (defun doom-dired-buffer-p (buf)
"Returns non-nil if BUF is a dired buffer." "Returns non-nil if BUF is a dired buffer."
@ -181,6 +196,36 @@ If DERIVED-P, test with `derived-mode-p', otherwise use `eq'."
(delete-window window))) (delete-window window)))
(kill-buffer buffer)) (kill-buffer buffer))
;;;###autoload
(defun doom-fixup-windows (windows)
"Ensure that each of WINDOWS is showing a real buffer or the fallback buffer."
(dolist (window windows)
(with-selected-window window
(when (doom-unreal-buffer-p (window-buffer))
(previous-buffer)
(when (doom-unreal-buffer-p (window-buffer))
(switch-to-buffer (doom-fallback-buffer)))))))
;;;###autoload
(defun doom-kill-buffer-fixup-windows (buffer)
"Kill the BUFFER and ensure all the windows it was displayed in have switched
to a real buffer or the fallback buffer."
(let ((windows (get-buffer-window-list buffer)))
(kill-buffer buffer)
(doom-fixup-windows (cl-remove-if-not #'window-live-p windows))))
;;;###autoload
(defun doom-kill-buffers-fixup-windows (buffers)
"Kill the BUFFERS and ensure all the windows they were displayed in have
switched to a real buffer or the fallback buffer."
(let ((seen-windows (make-hash-table :test 'eq :size 8)))
(dolist (buffer buffers)
(let ((windows (get-buffer-window-list buffer)))
(kill-buffer buffer)
(dolist (window (cl-remove-if-not #'window-live-p windows))
(puthash window t seen-windows))))
(doom-fixup-windows (hash-table-keys seen-windows))))
;;;###autoload ;;;###autoload
(defun doom-kill-matching-buffers (pattern &optional buffer-list) (defun doom-kill-matching-buffers (pattern &optional buffer-list)
"Kill all buffers (in current workspace OR in BUFFER-LIST) that match the "Kill all buffers (in current workspace OR in BUFFER-LIST) that match the
@ -240,21 +285,16 @@ windows, switch to `doom-fallback-buffer'. Otherwise, delegate to original
;;;###autoload ;;;###autoload
(defun doom/kill-this-buffer-in-all-windows (buffer &optional dont-save) (defun doom/kill-this-buffer-in-all-windows (buffer &optional dont-save)
"Kill BUFFER globally and ensure all windows previously showing this buffer "Kill BUFFER globally and ensure all windows previously showing this buffer
have switched to a real buffer. have switched to a real buffer or the fallback buffer.
If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)." If DONT-SAVE, don't prompt to save modified buffers (discarding their changes)."
(interactive (interactive
(list (current-buffer) current-prefix-arg)) (list (current-buffer) current-prefix-arg))
(cl-assert (bufferp buffer) t) (cl-assert (bufferp buffer) t)
(let ((windows (get-buffer-window-list buffer nil t))) (when (and (buffer-modified-p buffer) dont-save)
(when (and (buffer-modified-p buffer) dont-save) (with-current-buffer buffer
(with-current-buffer buffer (set-buffer-modified-p nil)))
(set-buffer-modified-p nil))) (doom-kill-buffer-fixup-windows buffer))
(kill-buffer buffer)
(cl-loop for win in windows
if (and (window-live-p win)
(doom-unreal-buffer-p (window-buffer win)))
do (with-selected-window win (previous-buffer)))))
;;;###autoload ;;;###autoload
(defun doom/kill-all-buffers (&optional project-p) (defun doom/kill-all-buffers (&optional project-p)
@ -319,3 +359,25 @@ current project."
(message "Killed %d buffer(s)" (message "Killed %d buffer(s)"
(- (length buffers) (- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers))))))) (length (cl-remove-if-not #'buffer-live-p buffers)))))))
;;;###autoload
(defun doom/kill-project-buffers (project)
"Kill buffers for the specified PROJECT."
(interactive
(list (if-let* ((open-projects (doom-open-projects)))
(completing-read
"Kill buffers for project: " open-projects
nil t nil nil
(if-let* ((project-root (doom-project-root))
(project-root (abbreviate-file-name project-root))
((member project-root open-projects)))
project-root))
(message "No projects are open!")
nil)))
(when project
(let ((buffers (doom-project-buffer-list project)))
(doom-kill-buffers-fixup-windows buffers)
(when (called-interactively-p 'interactive)
(message "Killed %d buffer(s)"
(- (length buffers)
(length (cl-remove-if-not #'buffer-live-p buffers))))))))