doomemacs/modules/feature/workspaces/config.el
Henrik Lissner 4984a548d1
Refactor DOOM init & add new init hooks
+ Add doom-init-hook and doom-post-init-hook to simplify Emacs init
  hooks into less ambiguous ones.
+ Attach former after-init-hook and emacs-startup-hook hooks to new doom
  init hooks.
+ Vastly improves daemon and tty support: preventing incorrect colors
  from bleeding across face class barriers, and into GUI Emacs and vice
  versa, when spawned with emacsclient.
+ Fix persp-mode breaking Emacs daemon, and ensuring that initialization
  is done properly in terminal Emacs (and emacsclient frames).
2017-06-12 00:37:14 +02:00

116 lines
4.8 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 had used workgroups2 before this, but
;; abandoned it because of its instability and impact on performance.
;; `persp-mode' has proven faster and more reliable (and it's still maintained).
;;
;; By default, sessions are auto-saved, but not auto-loaded. 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 much later.
;;
;; Note: persp-mode requires `workgroups' for file persistence in Emacs 24.4.
(defvar +workspaces-load-session-hook nil
"A hook that runs when persp loads a new session.")
(defvar +workspaces-main "main"
"The name of the primary and initial workspace, which cannot be deleted or
renamed.")
;;
;; Plugins
;;
(def-package! persp-mode
:demand t
:config
(setq persp-autokill-buffer-on-remove 'kill-weak
persp-nil-name "nil"
persp-nil-hidden t
persp-auto-save-fname "autosave"
persp-save-dir (concat doom-cache-dir "workspaces/")
persp-set-last-persp-for-new-frames nil
persp-switch-to-added-buffer nil
persp-remove-buffers-from-nil-persp-behaviour nil
;; Don't restore winconf on new frames
persp-init-frame-behaviour t
persp-init-new-frame-behaviour-override 'auto-temp
;; Don't auto-load on startup
persp-auto-resume-time -1
;; auto-save on kill
persp-auto-save-opt 1)
(add-hook 'doom-init-hook #'+workspaces|init t)
(add-hook 'after-make-frame-functions #'+workspaces|init)
(defun +workspaces|init (&optional frame)
(let ((frame (or frame (selected-frame))))
(unless persp-mode
(persp-mode +1))
;; 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-with-name-exists-p +workspaces-main)
(persp-add-new +workspaces-main))
;; Switch to it if we aren't auto-loading the last session
(when (or (equal (safe-persp-name (get-current-persp)) persp-nil-name)
(and (one-window-p)
(eq (window-buffer (selected-window)) (doom-fallback-buffer))))
(persp-frame-switch +workspaces-main frame))))
(define-key persp-mode-map [remap delete-window] #'+workspace/close-window-or-workspace)
;; Spawn a perspective for each new frame
(setq persp-init-new-frame-behaviour-override nil
persp-interactive-init-frame-behaviour-override
(lambda (frame &optional _new-frame-p)
(select-frame frame)
(+workspace/new)
(set-frame-parameter frame 'assoc-persp (+workspace-current-name))))
(defun +workspaces*delete-frame-and-persp (frame)
"Delete workspace associated with current frame IF it has no real buffers."
(when (and (string= (or (frame-parameter frame 'assoc-persp) "")
(+workspace-current-name))
(not (delq (doom-fallback-buffer) (doom-real-buffers-list))))
(+workspace/delete persp-name)))
(add-hook 'delete-frame-functions #'+workspaces*delete-frame-and-persp)
(defun +workspaces*auto-add-buffer (buffer &rest _)
"Auto-associate buffers with perspectives upon opening them. Allows a
perspective-specific buffer list via `doom-buffer-list'."
(when (and persp-mode
(not persp-temporarily-display-buffer)
(doom-real-buffer-p buffer))
(persp-add-buffer buffer (get-current-persp) nil)
(redisplay)))
(advice-add #'switch-to-buffer :after #'+workspaces*auto-add-buffer)
(advice-add #'display-buffer :after #'+workspaces*auto-add-buffer)
(defun +workspaces|workspace-per-project ()
"Create a new workspace when switching project with projectile."
(+workspace-switch (projectile-project-name) t))
(add-hook 'projectile-before-switch-project-hook #'+workspaces|workspace-per-project)
(defun +workspaces|restore-popups (&rest _)
"Restore popup windows when loading a perspective from file."
(dolist (window (window-list))
(when-let (plist (window-parameter window 'popup))
(with-selected-window window
(unless doom-popup-mode
(setq-local doom-popup-rules plist)
(doom-popup-mode +1))))))
(advice-add #'persp-load-state-from-file :after #'+workspaces|restore-popups)
(defun +workspaces*autosave-real-buffers (orig-fn &rest args)
"Don't autosave if no real buffers are open."
(when (doom-real-buffers-list)
(apply orig-fn args))
t)
(advice-add #'persp-asave-on-exit :around #'+workspaces*autosave-real-buffers))