From 322528ca8d6330c9f3492c1e86216ce0d1edaf0c Mon Sep 17 00:00:00 2001 From: Miciah Masters Date: Fri, 10 May 2019 19:48:18 -0400 Subject: [PATCH] spacemacs-layouts: Fix adding buffers to new persp Delete the hook that commit 9fcf8c898dd1069ef362f1ede320e85065358ac6 added to persp-created-functions, and change spacemacs/ivy-spacemacs-layouts, spacemacs/helm-perspectives, spacemacs/helm-persp-switch-project, and spacemacs/ivy-persp-switch-project to achieve the intended goal of adding the desired buffers after creating a new perspective. Change spacemacs/helm-persp-switch-project and spacemacs/ivy-persp-switch-project as follows: If the user selects a project but then quits without selecting a file or buffer, the new perspective is now immediately killed. Otherwise, if the perspective did not already exist, any buffers that belong to the selected project are added to the perspective. Add the following actions to spacemacs/ivy-spacemacs-layouts and spacemacs/helm-perspectives: * Create a new perspective with the Spacemacs home buffer (default action). * Create a new perspective with the buffers that belong to the current buffer's project. * Create a new perspective with the buffers that belong to the current perspective (i.e., make a copy of the current perspective). This commit resolves the problem reported in https://github.com/syl20bnr/spacemacs/commit/9fcf8c898dd1069ef362f1ede320e85065358ac6#commitcomment-33343455. This commit also fixes a problem with the default action for spacemacs/ivy-spacemacs-layouts and spacemacs/helm-perspectives. According to commit 7b931a9f5b4f996394e902b254ba85e9fe1b22be, the default action is supposed to display the home buffer if the action creates a new perspective, which was determined by checking whether the perspective was missing from the list of perspectives _before_ switching. However, commit eb7ca651fe72241a5784c289543f73b6c273faf4 changed this logic so it was checking whether the perspective was missing from the list of perspectives _after_ switching. This commit restores the correct logic. * CHANGELOG.develop: Update. * layers/+completion/ivy/funcs.el (spacemacs/ivy-spacemacs-layouts): Add "Copy Current Layout" and "Create Project Layout" actions to the docstring. Use spacemacs//create-persp-with-home-buffer for the default action. * layers/+completion/ivy/packages.el (ivy/post-init-persp-mode): Add actions for spacemacs//create-persp-with-current-project-buffers and persp-copy. * layers/+spacemacs/spacemacs-layouts/funcs.el (spacemacs||switch-layout): New macro. Switch to the named perspective, and initialize it using the provided forms if the perspective is new. (spacemacs//create-persp-with-current-project-buffers): New function. Create a new perspective with the current project's buffers. (spacemacs||switch-project-persp): New macro. Switch to the named perspective, and evaluate the provided forms with projectile-after-switch-project-hook bound with a hook that adds the current project's buffers to the perspective. If the user quits during the evaluation of the forms, kill the perspective. (spacemacs//create-persp-with-home-buffer): New function. Switch to the named perspective, and go to the Spacemacs home buffer if the perspective is new. (spacemacs/helm-perspectives): Use spacemacs//create-persp-with-home-buffer for the default action. Add actions for spacemacs//create-persp-with-current-project-buffers and persp-copy. (spacemacs//helm-persp-switch-project-action): New function. Switch to the named perspective and call projectile-switch-project-by-name, using the new spacemacs||switch-project-persp macro. Bind helm-quit-hook with a hook that kills the new perspective if the user quits projectile-switch-project-by-name. (spacemacs/helm-persp-switch-project): Use spacemacs//helm-persp-switch-project-action. (spacemacs//ivy-persp-switch-project-action): New function. Switch to the named perspective and call counsel-projectile-switch-project-action with a hook to add the project's buffers to the new perspective. (spacemacs/ivy-persp-switch-project): Delete advice for counsel-projectile-switch-project-action. Use spacemacs//ivy-persp-switch-project-action instead. (spacemacs//add-project-buffers-to-persp): Deleted. * layers/+spacemacs/spacemacs-layouts/packages.el (spacemacs-layouts/init-persp-mode): Don't add a hook to persp-created-functions. --- CHANGELOG.develop | 11 +- layers/+completion/ivy/funcs.el | 10 +- layers/+completion/ivy/packages.el | 5 +- layers/+spacemacs/spacemacs-layouts/funcs.el | 120 ++++++++++++++---- .../+spacemacs/spacemacs-layouts/packages.el | 2 - 5 files changed, 110 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.develop b/CHANGELOG.develop index 353b1451b..198680e93 100644 --- a/CHANGELOG.develop +++ b/CHANGELOG.develop @@ -511,7 +511,16 @@ Other: - Fixed bug that could overwrites customize variables (thanks to bmag) - Don't suggest ~SPC q r~ if =restart-emacs= package is missing after an update (thanks to Keshav Kini) - - spacemacs-layouts: Add Projectile project buffers to new perspectives. + - spacemacs-layouts: Improvements to ~SPC l l~ (=spacemacs/helm-perspectives= + or =spacemacs/ivy-spacemacs-layouts=): + - If the user selects a project that does not already have a layout and then + quits without selecting a file or buffer, kill the new layout. + - When creating a new layout, add any buffers that belong to the project. + - spacemacs-layouts: Improvements to ~SPC p l~ + (=spacemacs/helm-persp-switch-project= or + =spacemacs/ivy-persp-switch-project=): + - Fixed the default action to display the home buffer in the new layout. + - Added actions to copy the current layout or create a new project layout. - Resolve symlinks in warning message about duplicate layers (thanks to Ben Gamari) - Check toggle condition in status function (thanks to Eivind Fonn) diff --git a/layers/+completion/ivy/funcs.el b/layers/+completion/ivy/funcs.el index d06d51895..6ea13b175 100644 --- a/layers/+completion/ivy/funcs.el +++ b/layers/+completion/ivy/funcs.el @@ -413,6 +413,8 @@ If match is found \(default) Select layout c: Close Layout(s) <- mark with C-SPC to close more than one-window k: Kill Layout(s) +n: Copy current layout +p: Create project layout If match is not found Creates layout @@ -422,13 +424,7 @@ Closing doesn't kill buffers inside the layout while killing layouts does." (ivy-read "Layouts: " (persp-names) :caller 'spacemacs/ivy-spacemacs-layouts - :action (lambda (name) - (let ((persp-reset-windows-on-nil-window-conf t)) - (persp-switch name) - (unless - (member name - (persp-names-current-frame-fast-ordered)) - (spacemacs/home)))))) + :action 'spacemacs//create-persp-with-home-buffer)) (defun spacemacs/ivy-spacemacs-layout-buffer () "Switch to layout buffer using ivy." diff --git a/layers/+completion/ivy/packages.el b/layers/+completion/ivy/packages.el index d7d6183c2..f965d133b 100644 --- a/layers/+completion/ivy/packages.el +++ b/layers/+completion/ivy/packages.el @@ -300,7 +300,10 @@ (ivy-set-actions 'spacemacs/ivy-spacemacs-layouts '(("c" persp-kill-without-buffers "Close layout(s)") - ("k" persp-kill "Kill layout(s)"))) + ("k" persp-kill "Kill layout(s)") + ("n" persp-copy "Copy Current Layout") + ("p" spacemacs//create-persp-with-current-project-buffers + "Create Project Layout"))) ;; TODO: better handling of C and X bindings for ivy ;; check ivy/pre-init-persp-mode (spacemacs/transient-state-register-remove-bindings 'layouts diff --git a/layers/+spacemacs/spacemacs-layouts/funcs.el b/layers/+spacemacs/spacemacs-layouts/funcs.el index 5bb04378d..388704a6f 100644 --- a/layers/+spacemacs/spacemacs-layouts/funcs.el +++ b/layers/+spacemacs/spacemacs-layouts/funcs.el @@ -327,6 +327,76 @@ format so they are supported by the :bindings ,@bindings)))) + +;; Persp and Projectile integration + +(defmacro spacemacs||switch-layout (name &rest props) + "Switch to the perspective called NAME. + +Available PROPS: + +`:init EXPRESSIONS' + One or more forms, which will be evaluated after switching to perspective + NAME if the perspective did not already exist." + (declare (indent 1)) + (let ((init (spacemacs/mplist-get-values props :init))) + `(let ((persp-reset-windows-on-nil-window-conf t) + (persp-already-exists (persp-with-name-exists-p ,name))) + (persp-switch ,name) + (unless persp-already-exists + ,@init)))) + +(defun spacemacs//create-persp-with-current-project-buffers (name) + "Create new perspective with project buffers. + +If perspective NAME does not already exist, create it and add any +buffers that belong to the current buffer's project." + (if (persp-with-name-exists-p name) + (message "There is already a perspective named %s" name) + (if-let ((project (projectile-project-p))) + (spacemacs||switch-layout name + :init + (persp-add-buffer (projectile-project-buffers project) + (persp-get-by-name name) nil nil)) + (message "Current buffer does not belong to a project")))) + +(defmacro spacemacs||switch-project-persp (name &rest body) + "Switch to persp and execute BODY with hook to add project buffers. + +Switch to perspective NAME, and then evaluate the forms in BODY. +If the perspective did not already exist, then BODY will be +evaluated with `projectile-after-switch-project-hook' bound to +add a hook that adds the current project's buffers to the +perspective. If the user quits during the evaluation of BODY, +the new perspective will be killed." + (declare (indent 1)) + `(let ((projectile-after-switch-project-hook + projectile-after-switch-project-hook)) + (spacemacs||switch-layout ,name + :init + (add-hook 'projectile-after-switch-project-hook + (lambda () + (let ((persp (persp-get-by-name ,name))) + (when (persp-p persp) + (persp-add-buffer (projectile-project-buffers + (expand-file-name ,name)) + persp nil nil))))) + (condition-case nil + (progn + ,@body) + (quit (persp-kill-without-buffers ,name)))))) + + +;; Helm and Ivy common functions + +(defun spacemacs//create-persp-with-home-buffer (name) + "Switch to perspective and display the Spacemacs home buffer. + +If perspective NAME does not already exist, create it and display +the Spacemacs home buffer. If the perspective already exists, +just switch to it." + (spacemacs||switch-layout name :init (spacemacs/home))) + ;; Helm integration @@ -371,11 +441,11 @@ perspectives does." :requires-pattern t :action '(("Create new perspective" . - (lambda (name) - (let ((persp-reset-windows-on-nil-window-conf t)) - (persp-switch name) - (unless (member name (persp-names-current-frame-fast-ordered)) - (spacemacs/home)))))))))) + spacemacs//create-persp-with-home-buffer) + ("Create new perspective with buffers from current project" . + spacemacs//create-persp-with-current-project-buffers) + ("Create new perspective with buffers from current perspective" . + persp-copy)))))) ;; ability to use helm find files but also adds to current perspective (defun spacemacs/helm-persp-close () @@ -410,7 +480,17 @@ perspectives does." (mapcar 'persp-kill (helm-marked-candidates)))))))) +(defun spacemacs//helm-persp-switch-project-action (project) + "Default action for `spacemacs/helm-persp-switch-project'." + (spacemacs||switch-project-persp project + (let ((projectile-completion-system 'helm) + (helm-quit-hook (append helm-quit-hook + (lambda () + (persp-kill-without-buffers project))))) + (projectile-switch-project-by-name project)))) + (defun spacemacs/helm-persp-switch-project (arg) + "Select a project layout using Helm." (interactive "P") (helm :sources @@ -423,33 +503,27 @@ perspectives does." :fuzzy-match helm-projectile-fuzzy-match :mode-line helm-read-file-name-mode-line-string :action '(("Switch to Project Perspective" . - (lambda (project) - (let ((persp-reset-windows-on-nil-window-conf t)) - (persp-switch project) - (let ((projectile-completion-system 'helm)) - (projectile-switch-project-by-name project))))))) + spacemacs//helm-persp-switch-project-action))) :buffer "*Helm Projectile Layouts*")) ;; Ivy integration -(defun spacemacs/ivy-persp-switch-project-advice (project) - (let ((persp-reset-windows-on-nil-window-conf t)) - (persp-switch project))) +(defun spacemacs//ivy-persp-switch-project-action (project) + "Default action for `spacemacs/ivy-persp-switch-project'." + (spacemacs||switch-project-persp project + (counsel-projectile-switch-project-action project))) (defun spacemacs/ivy-persp-switch-project (arg) + "Select a project layout using Ivy." (interactive "P") (require 'counsel-projectile) - (advice-add 'counsel-projectile-switch-project-action - :before #'spacemacs/ivy-persp-switch-project-advice) (ivy-read "Switch to Project Perspective: " (if (projectile-project-p) (cons (abbreviate-file-name (projectile-project-root)) (projectile-relevant-known-projects)) projectile-known-projects) - :action #'counsel-projectile-switch-project-action - :caller 'spacemacs/ivy-persp-switch-project) - (advice-remove 'counsel-projectile-switch-project-action - 'spacemacs/ivy-persp-switch-project-advice)) + :action #'spacemacs//ivy-persp-switch-project-action + :caller 'spacemacs/ivy-persp-switch-project)) ;; Eyebrowse @@ -689,11 +763,3 @@ containing the buffer." (append (persp-parameter 'gui-eyebrowse-window-configs persp) (persp-parameter 'term-eyebrowse-window-configs persp))) (eyebrowse--rename-window-config-buffers window-config old new))))) - - -;; Persp and Projectile integration - -(defun spacemacs//add-project-buffers-to-persp (persp _persp-hash) - (if-let ((buffers (and (projectile-project-p) - (projectile-project-buffers)))) - (persp-add-buffer buffers persp nil nil))) diff --git a/layers/+spacemacs/spacemacs-layouts/packages.el b/layers/+spacemacs/spacemacs-layouts/packages.el index e99a48dd1..1a32c8c0d 100644 --- a/layers/+spacemacs/spacemacs-layouts/packages.el +++ b/layers/+spacemacs/spacemacs-layouts/packages.el @@ -219,8 +219,6 @@ (defadvice persp-activate (before spacemacs//save-toggle-layout activate) (setq spacemacs--last-selected-layout persp-last-persp-name)) (add-hook 'persp-mode-hook 'spacemacs//layout-autosave) - (add-hook 'persp-created-functions - #'spacemacs//add-project-buffers-to-persp) (advice-add 'persp-load-state-from-file :before 'spacemacs//layout-wait-for-modeline) ;; Override SPC TAB to only change buffers in perspective (spacemacs/set-leader-keys