158 lines
5.8 KiB
EmacsLisp
158 lines
5.8 KiB
EmacsLisp
;;; init-perspective.el --- Perspective and Projectile configuration -*- lexical-binding: t -*-
|
|
;;; Commentary:
|
|
;;; Workspace management with perspective.el integrated with Projectile
|
|
|
|
;;; Code:
|
|
|
|
;; Projectile - Project management
|
|
(use-package projectile
|
|
:ensure t
|
|
:diminish projectile-mode
|
|
:init
|
|
(setq projectile-keymap-prefix (kbd "C-c p"))
|
|
:config
|
|
(projectile-mode +1)
|
|
|
|
;; Use hybrid indexing for best performance
|
|
(setq projectile-indexing-method 'hybrid)
|
|
|
|
;; Enable caching
|
|
(setq projectile-enable-caching t)
|
|
|
|
;; Project root markers
|
|
(setq projectile-project-root-files-top-down-recurring
|
|
'(".projectile" ".git" ".hg" ".svn"))
|
|
|
|
(setq projectile-project-root-files
|
|
'("Makefile" "package.json" "Cargo.toml" "go.mod"
|
|
"pom.xml" "build.gradle" "requirements.txt"
|
|
"setup.py" "pyproject.toml" "Gemfile" "composer.json"))
|
|
|
|
;; Sort files by recently opened
|
|
(setq projectile-sort-order 'recentf)
|
|
|
|
;; Use completion system (works with vertico/consult)
|
|
(setq projectile-completion-system 'default)
|
|
|
|
;; Where to store projectile cache
|
|
(setq projectile-cache-file
|
|
(expand-file-name "projectile.cache" user-emacs-directory))
|
|
(setq projectile-known-projects-file
|
|
(expand-file-name "projectile-bookmarks.eld" user-emacs-directory))
|
|
|
|
;; Integration with consult if available
|
|
(with-eval-after-load 'consult
|
|
(setq consult-project-function (lambda (_) (projectile-project-root)))))
|
|
|
|
;; Perspective - Workspace management
|
|
(use-package perspective
|
|
:ensure t
|
|
:bind (("C-x x s" . persp-switch)
|
|
("C-x x k" . persp-kill)
|
|
("C-x x r" . persp-rename)
|
|
("C-x x a" . persp-add-buffer)
|
|
("C-x x A" . persp-set-buffer)
|
|
("C-x x b" . persp-switch-to-buffer)
|
|
("C-x x n" . persp-next)
|
|
("C-x x p" . persp-prev)
|
|
("C-x x i" . persp-import)
|
|
("C-x x m" . persp-merge)
|
|
("C-x x u" . persp-unmerge)
|
|
("C-x x g" . persp-add-buffer-to-frame-global)
|
|
("C-x x x" . persp-switch-last))
|
|
:custom
|
|
;; Show perspective name in mode line
|
|
(persp-mode-prefix-key (kbd "C-x x"))
|
|
(persp-initial-frame-name "main")
|
|
;; Don't auto-kill buffers when perspective is killed
|
|
(persp-kill-foreign-buffer-behaviour nil)
|
|
;; Save state on exit
|
|
(persp-state-default-file (expand-file-name "persp-state" user-emacs-directory))
|
|
:init
|
|
(persp-mode +1)
|
|
:config
|
|
;; Show perspective in mode line
|
|
(setq persp-show-modestring t)
|
|
|
|
;; Remove/bury buffers not associated with the current perspective when switching
|
|
(defun my/persp-remove-foreign-buffers ()
|
|
"Bury buffers not belonging to the current perspective."
|
|
(when (and (boundp 'perspectives-hash) (hash-table-p perspectives-hash))
|
|
(let ((persp-buffers (persp-current-buffers)))
|
|
(dolist (buf (buffer-list))
|
|
(unless (or (memq buf persp-buffers)
|
|
(string-prefix-p " " (buffer-name buf)) ; internal buffers
|
|
(string-prefix-p "*Messages*" (buffer-name buf))
|
|
(string-prefix-p "*scratch*" (buffer-name buf)))
|
|
(bury-buffer buf))))))
|
|
|
|
(add-hook 'persp-activated-hook #'my/persp-remove-foreign-buffers)
|
|
|
|
;; Save and restore perspectives on Emacs quit/start
|
|
(add-hook 'kill-emacs-hook #'persp-state-save)
|
|
|
|
;; Restore perspectives on startup (after init)
|
|
(defun my/persp-restore-state ()
|
|
"Restore perspective state if file exists."
|
|
(when (file-exists-p persp-state-default-file)
|
|
(condition-case err
|
|
(persp-state-load persp-state-default-file)
|
|
(error
|
|
(message "Failed to restore perspective state: %s. Resetting perspectives." (error-message-string err))
|
|
(my/persp-reset)))))
|
|
(add-hook 'emacs-startup-hook #'my/persp-restore-state))
|
|
|
|
;; Persp-Projectile - Integration between perspective and projectile
|
|
(use-package persp-projectile
|
|
:ensure t
|
|
:after (perspective projectile)
|
|
:bind (:map projectile-mode-map
|
|
("C-c p p" . projectile-persp-switch-project))
|
|
:config
|
|
;; When switching projects, create/switch to a perspective named after the project
|
|
(setq projectile-switch-project-action #'projectile-find-file))
|
|
|
|
;; Helper functions
|
|
(defun my/persp-project-switch ()
|
|
"Switch to a project and its perspective."
|
|
(interactive)
|
|
(call-interactively #'projectile-persp-switch-project))
|
|
|
|
(defun my/persp-kill-project-buffers ()
|
|
"Kill all buffers in current perspective/project."
|
|
(interactive)
|
|
(if (and (boundp 'perspectives-hash) (hash-table-p perspectives-hash))
|
|
(when (y-or-n-p (format "Kill all buffers in perspective '%s'? " (persp-current-name)))
|
|
(persp-kill-buffer*))
|
|
(message "Perspectives not initialized or corrupted. Use M-x my/persp-reset to reset.")))
|
|
|
|
(defun my/persp-reset ()
|
|
"Reset perspectives if they become corrupted."
|
|
(interactive)
|
|
(when (boundp 'perspectives-hash)
|
|
(setq perspectives-hash (make-hash-table :test 'equal)))
|
|
(persp-mode +1)
|
|
(message "Perspectives reset."))
|
|
|
|
(defun my/persp-list ()
|
|
"List all perspectives."
|
|
(interactive)
|
|
(if (and (boundp 'perspectives-hash) (hash-table-p perspectives-hash))
|
|
(let ((perspectives (persp-names)))
|
|
(message "Perspectives: %s" (string-join perspectives ", ")))
|
|
(message "Perspectives not initialized or corrupted. Use M-x my/persp-reset to reset.")))
|
|
|
|
;; Additional keybindings for convenience
|
|
(with-eval-after-load 'projectile
|
|
(define-key projectile-mode-map (kbd "C-c p P") #'my/persp-project-switch)
|
|
(define-key projectile-mode-map (kbd "C-c p K") #'my/persp-kill-project-buffers)
|
|
(define-key projectile-mode-map (kbd "C-c p L") #'my/persp-list))
|
|
|
|
;; Integration with CUA mode - ensure perspective commands work in special modes
|
|
(with-eval-after-load 'perspective
|
|
(dolist (cmd '(persp-switch persp-kill persp-rename persp-next persp-prev))
|
|
(put cmd 'CUA 'move)))
|
|
|
|
(provide 'init-perspective)
|
|
;;; init-perspective.el ends here
|