Now that we are loading package autoloads files (as part of the generated doom-package-autoload-file when running make autoloads), many :commands properties are redundant. In fact, many def-package! blocks are redundant. In some cases, we can do without a config.el file entirely, and can move into the autoloads file or rely entirely on package autoloads. Also, many settings have been moved in their module's autoloads files, which makes them available ASAP; their use no longer depends on module load order. This gained me a modest ~10% boost in startup speed.
163 lines
7.4 KiB
EmacsLisp
163 lines
7.4 KiB
EmacsLisp
;;; feature/workspaces/config.el -*- lexical-binding: t; -*-
|
|
|
|
;; `persp-mode' gives me workspaces, a workspace-restricted `buffer-list', and
|
|
;; file-based session persistence. I used workgroups2 before this, but abandoned
|
|
;; it because it was unstable and slow; `persp-mode' is neither (and still
|
|
;; maintained).
|
|
;;
|
|
;; By default, sessions are autosaved, but not autoloaded. Use :ss or
|
|
;; `+workspace/save-session' to save, and :sl or `+workspace/load-session' to
|
|
;; load the last autosaved session. You can give sessions a custom name so they
|
|
;; can be loaded later.
|
|
;;
|
|
;; NOTE persp-mode requires `workgroups' for file persistence in Emacs 24.4.
|
|
|
|
(defvar +workspaces-main "main"
|
|
"The name of the primary and initial workspace, which cannot be deleted or
|
|
renamed.")
|
|
|
|
(defvar +workspaces-switch-project-function #'doom-project-find-file
|
|
"The function to run after `projectile-switch-project' or
|
|
`counsel-projectile-switch-project'. This function must take one argument: the
|
|
new project directory.")
|
|
|
|
;; FIXME actually use this for wconf bookmark system
|
|
(defvar +workspaces-data-file "_workspaces"
|
|
"The basename of the file to store single workspace perspectives. Will be
|
|
stored in `persp-save-dir'.")
|
|
|
|
(defun +workspaces-restore-last-session (&rest _)
|
|
(add-hook 'doom-post-init-hook #'+workspace/load-session 'append))
|
|
(map-put command-switch-alist '"--restore" #'+workspaces-restore-last-session)
|
|
|
|
|
|
;;
|
|
;; Plugins
|
|
;;
|
|
|
|
(def-package! persp-mode
|
|
:defer t
|
|
:init
|
|
(defun +workspaces|init ()
|
|
;; Remove default buffer predicate so persp-mode can put in its own
|
|
(setq default-frame-alist (map-delete default-frame-alist 'buffer-predicate))
|
|
(add-hook 'after-make-frame-functions #'+workspaces|init-frame)
|
|
(require 'persp-mode)
|
|
(unless (daemonp)
|
|
(+workspaces|init-frame (selected-frame))))
|
|
|
|
(defun +workspaces|init-frame (frame)
|
|
"Make sure a main workspace exists and is switched to, if FRAME isn't in any
|
|
workspace. Also ensures that the *Warnings* buffer will be visible in main.
|
|
|
|
Uses `+workspaces-main' to determine the name of the main workspace."
|
|
(unless persp-mode
|
|
(persp-mode +1))
|
|
(unless noninteractive
|
|
(let (persp-before-switch-functions persp-activated-functions)
|
|
(with-selected-frame frame
|
|
;; The default perspective persp-mode makes (defined by
|
|
;; `persp-nil-name') is special and doesn't actually represent a real
|
|
;; persp object, so buffers can't really be assigned to it, among other
|
|
;; quirks. We create a *real* main workspace to fill this role.
|
|
(unless (persp-get-by-name +workspaces-main)
|
|
(persp-add-new +workspaces-main))
|
|
;; Switch to it if we aren't auto-loading the last session
|
|
(when (and (string= (safe-persp-name (get-current-persp)) persp-nil-name)
|
|
(= persp-auto-resume-time -1))
|
|
(persp-frame-switch +workspaces-main frame)
|
|
;; We want to know where we are in every new daemon frame
|
|
(when (daemonp)
|
|
(run-at-time 0.1 nil #'+workspace/display))
|
|
;; The warnings buffer gets swallowed by creating
|
|
;; `+workspaces-main', so we display it manually, if it exists (fix
|
|
;; #319).
|
|
(when-let* ((warnings (get-buffer "*Warnings*")))
|
|
(save-excursion
|
|
(display-buffer-in-side-window
|
|
warnings '((window-height . shrink-window-if-larger-than-buffer))))))))))
|
|
|
|
(add-hook 'doom-post-init-hook #'+workspaces|init t)
|
|
:config
|
|
(setq persp-autokill-buffer-on-remove 'kill-weak
|
|
persp-nil-hidden t
|
|
persp-auto-save-fname "autosave"
|
|
persp-save-dir (concat doom-etc-dir "workspaces/")
|
|
persp-set-last-persp-for-new-frames t
|
|
persp-switch-to-added-buffer nil
|
|
persp-remove-buffers-from-nil-persp-behaviour nil
|
|
persp-auto-resume-time -1 ; Don't auto-load on startup
|
|
persp-auto-save-opt (if noninteractive 0 1)) ; auto-save on kill
|
|
|
|
;; bootstrap
|
|
(defun +workspaces|init-persp-mode ()
|
|
(cond (persp-mode
|
|
;; Ensure `persp-kill-buffer-query-function' is last in
|
|
;; kill-buffer-query-functions
|
|
(remove-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function)
|
|
(add-hook 'kill-buffer-query-functions 'persp-kill-buffer-query-function t)
|
|
|
|
;; Ensure buffers we've opened/switched to are auto-added to the
|
|
;; current perspective
|
|
(add-hook 'doom-after-switch-buffer-hook #'+workspaces|auto-add-buffer)
|
|
|
|
;; Remap `buffer-list' to current workspace's buffers in
|
|
;; `doom-buffer-list'
|
|
(advice-add #'doom-buffer-list :override #'+workspace-buffer-list))
|
|
(t
|
|
(remove-hook 'doom-after-switch-buffer-hook #'+workspaces|auto-add-buffer)
|
|
(advice-remove #'doom-buffer-list #'+workspace-buffer-list))))
|
|
(add-hook 'persp-mode-hook #'+workspaces|init-persp-mode)
|
|
|
|
(defun +workspaces|leave-nil-perspective (&rest _)
|
|
(when (string= (+workspace-current-name) persp-nil-name)
|
|
(persp-frame-switch +workspaces-main)))
|
|
(add-hook 'persp-after-load-state-functions #'+workspaces|leave-nil-perspective)
|
|
|
|
;; Modify `delete-window' to close the workspace if used on the last window
|
|
(define-key persp-mode-map [remap restart-emacs] #'+workspace/restart-emacs-then-restore)
|
|
(define-key persp-mode-map [remap delete-window] #'+workspace/close-window-or-workspace)
|
|
(define-key persp-mode-map [remap evil-delete-window] #'+workspace/close-window-or-workspace)
|
|
;; only auto-save when real buffers are present
|
|
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers)
|
|
;; On `doom/cleanup-session', delete buffers associated with no perspectives
|
|
(add-hook 'doom-cleanup-hook #'+workspaces|cleanup-unassociated-buffers)
|
|
|
|
(defun +workspaces|select-non-side-window (&rest _)
|
|
"Ensure a side window isn't current when switching workspaces."
|
|
(when (window-parameter nil 'window-side)
|
|
(select-window
|
|
(cl-loop for win in (window-list)
|
|
unless (window-parameter win 'window-side)
|
|
return win))))
|
|
(add-hook 'persp-before-deactivate-functions #'+workspaces|select-non-side-window)
|
|
|
|
;; per-frame workspaces
|
|
(setq persp-init-frame-behaviour t
|
|
persp-init-new-frame-behaviour-override nil
|
|
persp-interactive-init-frame-behaviour-override #'+workspaces|associate-frame
|
|
persp-emacsclient-init-frame-behaviour-override #'+workspaces|associate-frame)
|
|
;; delete frame associated with workspace, if it exists
|
|
(add-hook 'delete-frame-functions #'+workspaces|delete-associated-workspace)
|
|
|
|
;; per-project workspaces, but reuse current workspace if empty
|
|
(setq projectile-switch-project-action #'+workspaces|set-project-action
|
|
counsel-projectile-switch-project-action #'+workspaces|switch-to-project)
|
|
(add-hook 'projectile-after-switch-project-hook #'+workspaces|switch-to-project)
|
|
|
|
;;
|
|
;; eshell
|
|
(persp-def-buffer-save/load
|
|
:mode 'eshell-mode :tag-symbol 'def-eshell-buffer
|
|
:save-vars '(major-mode default-directory))
|
|
;; compile
|
|
(persp-def-buffer-save/load
|
|
:mode 'compilation-mode :tag-symbol 'def-compilation-buffer
|
|
:save-vars
|
|
'(major-mode default-directory compilation-directory compilation-environment compilation-arguments))
|
|
;; magit-status
|
|
(persp-def-buffer-save/load
|
|
:mode 'magit-status-mode :tag-symbol 'def-magit-status-buffer
|
|
:save-vars '(major-mode default-directory)
|
|
:after-load-function #'(lambda (b &rest _) (with-current-buffer b (magit-refresh)))))
|
|
|