diff --git a/doc/DOCUMENTATION.org b/doc/DOCUMENTATION.org index f7258afc3..27c4bc53c 100644 --- a/doc/DOCUMENTATION.org +++ b/doc/DOCUMENTATION.org @@ -2080,10 +2080,6 @@ Windows manipulation commands (start with ~w~): | ~SPC w =~ | balance split windows | | ~SPC w _~ | maximize window horizontally | | ~SPC w \vert~ | maximize window vertically | -| ~SPC w 1~ | make 1 window layout | -| ~SPC w 2~ | make 2 windows layout (split vertically) | -| ~SPC w 3~ | make 3 windows layout (split vertically) | -| ~SPC w 4~ | make 4 windows layout (split in 2x2 grid) | | ~SPC w b~ | force the focus back to the minibuffer | | ~SPC w c~ | maximize/minimize a window and center it | | ~SPC w C~ | maximize/minimize a window and center it using [[https://github.com/abo-abo/ace-window][ace-window]] | @@ -2119,6 +2115,50 @@ Windows manipulation commands (start with ~w~): | ~SPC w W~ | select window using [[https://github.com/abo-abo/ace-window][ace-window]] | | ~SPC w x~ | delete a window and its current buffer (does not delete the file) | +Split the current window into multiple ones, deleting all others using the +following commands: + +| Key Binding | Description | +|-------------+-------------------------------------------| +| ~SPC w 1~ | make 1 window layout | +| ~SPC w 2~ | make 2 windows layout (split vertically) | +| ~SPC w 3~ | make 3 windows layout (split vertically) | +| ~SPC w 4~ | make 4 windows layout (split in 2x2 grid) | + +By default, the commands above ignore some windows, like the filetrees (treemacs +and neotree) but you can use a prefix argument to force delete them. + +| Key Binding | Description | +|-----------------+-------------------------------------------------------------| +| ~SPC u SPC w 1~ | make 1 window layout with force delete | +| ~SPC u SPC w 2~ | make 2 windows layout (split vertically) with force delete | +| ~SPC u SPC w 3~ | make 3 windows layout (split vertically) with force delete | +| ~SPC u SPC w 4~ | make 4 windows layout (split in 2x2 grid) with force delete | + +You can also configure which windows get ignored when executing the above +commands by adding a prefix to the =spacemacs-window-split-ignore-prefixes= +list: + +#+BEGIN_SRC emacs-lisp +(add-to-list 'spacemacs-window-split-ignore-prefixes "My Favourite Window") +#+END_SRC + +Or if you want a certain ignored window to always be deleted you can remote it +from the list: + +#+BEGIN_SRC emacs-lisp +(setq spacemacs-window-split-ignore-prefixes + (remove treemacs--buffer-name-prefix spacemacs-window-split-ignore-prefixes)) +#+END_SRC + +And if you want even more control over the way windows are removed you can +define your own deletion function: + +#+BEGIN_SRC emacs-lisp +(defun my-delete-other-windows () (delete-other-windows)) +(setq spacemacs-window-split-delete-function 'my-delete-other-windows) +#+END_SRC + **** Window manipulation transient state A convenient window manipulation transient state allows performing most of the actions listed above. The transient state allows additional actions as well like diff --git a/layers/+filetree/neotree/packages.el b/layers/+filetree/neotree/packages.el index 622061235..3b9e84efe 100644 --- a/layers/+filetree/neotree/packages.el +++ b/layers/+filetree/neotree/packages.el @@ -109,7 +109,9 @@ Navigation^^^^ Actions^^ Visual actions/config^^^ "fT" 'neotree-show "pt" 'neotree-find-project-root)) :config - (spacemacs//neotree-key-bindings))) + (progn + (spacemacs//neotree-key-bindings) + (add-to-list 'spacemacs-window-split-ignore-prefixes neo-buffer-name)))) (defun neotree/pre-init-winum () (spacemacs|use-package-add-hook winum diff --git a/layers/+filetree/treemacs/packages.el b/layers/+filetree/treemacs/packages.el index cc4263415..3f3f634eb 100644 --- a/layers/+filetree/treemacs/packages.el +++ b/layers/+filetree/treemacs/packages.el @@ -53,7 +53,8 @@ (when treemacs-use-filewatch-mode (treemacs-filewatch-mode t)) (when (memq treemacs-use-git-mode '(simple extended)) - (treemacs-git-mode treemacs-use-git-mode))))) + (treemacs-git-mode treemacs-use-git-mode)) + (add-to-list 'spacemacs-window-split-ignore-prefixes treemacs--buffer-name-prefix)))) (defun treemacs/init-treemacs-evil () (use-package treemacs-evil diff --git a/layers/+spacemacs/spacemacs-defaults/funcs.el b/layers/+spacemacs/spacemacs-defaults/funcs.el index 017e7e5e0..1f89b7e62 100644 --- a/layers/+spacemacs/spacemacs-defaults/funcs.el +++ b/layers/+spacemacs/spacemacs-defaults/funcs.el @@ -559,30 +559,148 @@ in a split window to the right." (split-window-horizontally) (other-window 1)) -(defun spacemacs/layout-grid () - " Set the layout to a 2x2 grid. " - (interactive) - (delete-other-windows) - (split-window (split-window-right) nil 'below) - (split-window-below)) + +;; Window Split -(defun spacemacs/layout-triple-columns () - " Set the layout to triple columns. " - (interactive) - (delete-other-windows) - (dotimes (i 2) (split-window-right)) +(defun spacemacs--window-split-splittable-windows () + (seq-remove + (lambda (window) + ;; TODO: find a way to identify unsplittable side windows reliably! + nil) + (spacemacs--window-split-non-ignored-windows))) + +(defun spacemacs--window-split-non-ignored-windows () + "Determines the list of windows to be deleted." + (seq-filter + (lambda (window) + (let* ((name (buffer-name (window-buffer window))) + (prefixes-matching + (seq-filter + (lambda (prefix) (string-prefix-p prefix name)) + spacemacs-window-split-ignore-prefixes))) + (not prefixes-matching))) + (window-list (selected-frame)))) + +(defun spacemacs/window-split-default-delete () + "Deletes other windows, except a list of excluded ones." + (if spacemacs-window-split-ignore-prefixes + (let* ((deletable (spacemacs--window-split-non-ignored-windows)) + (splittable (spacemacs--window-split-splittable-windows))) + (when splittable + (let* ((selected (car splittable)) + (to-delete (delq selected deletable))) + (select-window selected) + (dolist (window to-delete) (delete-window window))))) + (delete-other-windows))) + +(defvar spacemacs-window-split-ignore-prefixes nil + "Prefixes for windows that are not deleted when changing split layout. + +You can add an entry here by using the following: + (add-to-list 'spacemacs-window-split-ignore-prefixes \"Buffer prefix\")") + +(defvar spacemacs-window-split-delete-function 'spacemacs/window-split-default-delete + "Function used to delete other windows when changing layout. + +Used as a callback by the following functions: + - spacemacs/window-split-grid + - spacemacs/window-split-triple-columns + - spacemacs/window-split-double-columns + - spacemacs/window-split-single-column + +Possible values: + - 'spacemacs/window-split-default-delete (default) + - 'delete-other-windows + - 'treemacs-delete-other-windows (when using the treemacs package) + - a lambda: (lambda () (delete-other-windows)) + - a custom function: + (defun my-delete-other-windows () (delete-other-windows)) + (setq spacemacs-window-split-delete-function 'my-delete-other-windows)") + +(defun spacemacs/window-split-grid (&optional purge) + "Set the layout to a 2x2 grid. + +Uses the funcion defined in `spacemacs-window-split-delete-function' as a means to +remove windows. + +When called with a prefix argument, it uses `delete-other-windows' as a means +to remove windows, regardless of the value in `spacemacs-window-split-delete-function'." + (interactive "P") + (if purge + (let ((ignore-window-parameters t)) + (delete-other-windows)) + (funcall spacemacs-window-split-delete-function)) + (if (spacemacs--window-split-splittable-windows) + (let* ((previous-files (seq-filter #'buffer-file-name + (delq (current-buffer) (buffer-list)))) + (second (split-window-below)) + (third (split-window-right)) + (fourth (split-window second nil 'right))) + (set-window-buffer third (or (car previous-files) "*scratch*")) + (set-window-buffer second (or (cadr previous-files) "*scratch*")) + (set-window-buffer fourth (or (caddr previous-files) "*scratch*")) + (balance-windows)) + (message "There are no main windows available to split!"))) + +(defun spacemacs/window-split-triple-columns (&optional purge) + "Set the layout to triple columns. + +Uses the funcion defined in `spacemacs-window-split-delete-function' as a means to +remove windows. + +When called with a prefix argument, it uses `delete-other-windows' as a means +to remove windows, regardless of the value in `spacemacs-window-split-delete-function'." + (interactive "P") + (if purge + (let ((ignore-window-parameters t)) + (delete-other-windows)) + (funcall spacemacs-window-split-delete-function)) + (if (spacemacs--window-split-splittable-windows) + (let* ((previous-files (seq-filter #'buffer-file-name + (delq (current-buffer) (buffer-list)))) + (second (split-window-right)) + (third (split-window second nil 'right))) + (set-window-buffer second (or (car previous-files) "*scratch*")) + (set-window-buffer third (or (cadr previous-files) "*scratch*")) + (balance-windows)) + (message "There are no main windows available to split!"))) + +(defun spacemacs/window-split-double-columns (&optional purge) + "Set the layout to double columns. + +Uses the funcion defined in `spacemacs-window-split-delete-function' as a means to +remove windows. + +When called with a prefix argument, it uses `delete-other-windows' as a means +to remove windows, regardless of the value in `spacemacs-window-split-delete-function'." + (interactive "P") + (if purge + (let ((ignore-window-parameters t)) + (delete-other-windows)) + (funcall spacemacs-window-split-delete-function)) + (if (spacemacs--window-split-splittable-windows) + (let* ((previous-files (seq-filter #'buffer-file-name + (delq (current-buffer) (buffer-list))))) + (set-window-buffer (split-window-right) (or (car previous-files) "*scratch*")) + (balance-windows)) + (message "There are no main windows available to split!"))) + +(defun spacemacs/window-split-single-column (&optional purge) + "Set the layout to single column. + +Uses the funcion defined in `spacemacs-window-split-delete-function' as a means to +remove windows. + +When called with a prefix argument, it uses `delete-other-windows' as a means +to remove windows, regardless of the value in `spacemacs-window-split-delete-function'." + (interactive "P") + (if purge + (let ((ignore-window-parameters t)) + (delete-other-windows)) + (funcall spacemacs-window-split-delete-function)) (balance-windows)) -(defun spacemacs/layout-double-columns () - " Set the layout to double columns. " - (interactive) - (delete-other-windows) - (split-window-right)) - -(defun spacemacs/layout-single-column () - " Set the layout to single column. " - (interactive) - (delete-other-windows)) + (defun spacemacs/insert-line-above-no-indent (count) "Insert a new line above with no indentation." diff --git a/layers/+spacemacs/spacemacs-defaults/keybindings.el b/layers/+spacemacs/spacemacs-defaults/keybindings.el index 1b22342a8..12410ed7c 100644 --- a/layers/+spacemacs/spacemacs-defaults/keybindings.el +++ b/layers/+spacemacs/spacemacs-defaults/keybindings.el @@ -404,10 +404,10 @@ (spacemacs/set-leader-keys "w TAB" 'spacemacs/alternate-window - "w1" 'spacemacs/layout-single-column - "w2" 'spacemacs/layout-double-columns - "w3" 'spacemacs/layout-triple-columns - "w4" 'spacemacs/layout-grid + "w1" 'spacemacs/window-split-single-column + "w2" 'spacemacs/window-split-double-columns + "w3" 'spacemacs/window-split-triple-columns + "w4" 'spacemacs/window-split-grid "wb" 'spacemacs/switch-to-minibuffer-window "wd" 'spacemacs/delete-window "wt" 'spacemacs/toggle-current-window-dedication