diff --git a/.emacs.d/lisp/init-dashboard.el b/.emacs.d/lisp/init-dashboard.el index 30285a5..63cacc6 100644 --- a/.emacs.d/lisp/init-dashboard.el +++ b/.emacs.d/lisp/init-dashboard.el @@ -8,8 +8,8 @@ dashboard-startup-banner 'logo dashboard-set-footer nil dashboard-week-agenda t - dashboard-projects-backend 'projectile - dashboard-projects-switch-function 'projectile-persp-switch-project + dashboard-projects-backend 'project-el + dashboard-projects-switch-function 'switch-project dashboard-items '((recents . 15) (bookmarks . 5) (projects . 5) diff --git a/.emacs.d/lisp/init-minibuffer.el b/.emacs.d/lisp/init-minibuffer.el index 31a9268..f1d81a4 100644 --- a/.emacs.d/lisp/init-minibuffer.el +++ b/.emacs.d/lisp/init-minibuffer.el @@ -64,7 +64,7 @@ :init (defvar switching-project nil) (defun vertico-directory-enter-or-switch-project () - "Wrapper around vertico-directory-enter that plays nicely with Projectile." + "Wrapper around vertico-directory-enter that plays nicely with adding projects." (interactive) (if switching-project (vertico-exit) @@ -72,7 +72,7 @@ (defun read-project (orig &rest args) (let ((switching-project t)) (apply orig args))) - (advice-add 'projectile-completing-read :around + (advice-add 'project-prompt-project-dir :around 'read-project) :config (defun vertico-directory-slash () @@ -104,7 +104,6 @@ :bind ("M-P" . vertico-repeat)) (use-package consult - :after projectile :bind (;; C-c bindings (mode-specific-map) ("C-c h" . consult-history) ("C-c m" . consult-mode-command) @@ -253,20 +252,78 @@ ;; You may want to use `embark-prefix-help-command' or which-key instead. ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help) - (autoload 'projectile-project-root "projectile") - (setq consult-project-root-function #'projectile-project-root) + (setq consult-project-root-function + (lambda () + (when-let (project (project-current)) + (car (project-roots project))))) + + ;; Switch perspective when switching buffer if needed + (setq consult--display-buffer #'persp-switch-to-buffer) (defvar consult-initial-narrow-config - '((consult-buffer . ?p) - (consult-buffer-no-preview . ?p))) + '((consult-buffer . ?x) + (consult-buffer-no-preview . ?x))) ;; Add initial narrowing hook (defun consult-initial-narrow () (when-let (key (alist-get this-command consult-initial-narrow-config)) (setq unread-command-events (append unread-command-events (list key 32))))) (add-hook 'minibuffer-setup-hook #'consult-initial-narrow) - (when (and (eq system-type 'darwin) (string-match-p "^find" consult-find-command)) - (setq consult-find-command (concat "g" consult-find-command))) + (when (and (eq system-type 'darwin) (string-match-p "^find" consult-find-args)) + (setq consult-find-args (concat "g" consult-find-args))) + + ;; Use fd that that we aren't just getting recentf, but also respect .gitignore + (setq consult--source-project-file + (plist-put consult--source-project-file + :items '(lambda () + (let* ((root (consult--project-root)) + (len (length root)) + (inv-root (propertize root 'invisible t))) + (mapcar (lambda (x) + (concat inv-root (substring x len))) + (split-string + (shell-command-to-string + (format "fd --color never -t f -0 . %s" root)) + "\0" t)))))) + + (defvar consult--source-perspective-buffer + `(:name "Perspective Buffer" + :narrow (?x . "Perspective") + :hidden t + :category buffer + :face consult-buffer + :history buffer-name-history + :state ,#'consult--buffer-state + :enabled ,(lambda () persp-mode) + :items + ,(lambda () + (consult--buffer-query :sort 'visibility + :predicate #'persp-is-current-buffer + :as #'buffer-name))) + "Perspective buffer candidate source for `consult-buffer'.") + (add-to-list 'consult-buffer-sources 'consult--source-perspective-buffer t) + + ;; Copy of consult--source-project-file to use with perspective narrowing (identical except for narrowing key) + (defvar consult--source-perspective-files + (plist-put (copy-sequence consult--source-project-file) :narrow '(?x "Project Files"))) + (add-to-list 'consult-buffer-sources 'consult--source-perspective-files t) + + ;; Versions of consult--source-project-buffer and consult--source-project-file for use by consult-project-buffer + ;; They allow narrowing with b and f (instead of p) + (defvar consult--project-source-project-buffer + (plist-put (plist-put (copy-sequence consult--source-project-buffer) + :hidden nil) + :narrow '(?b . "Project Buffer"))) + (defvar consult--project-source-project-file + (plist-put (plist-put (copy-sequence consult--source-project-file) + :hidden nil) + :narrow '(?f . "Project File"))) + + (defun consult-project-buffer () + (interactive) + (let ((consult-buffer-sources '(consult--project-source-project-buffer + consult--project-source-project-file))) + (consult-buffer))) (defun consult--orderless-regexp-compiler (input type) (setq input (orderless-pattern-compiler input)) diff --git a/.emacs.d/lisp/init-project.el b/.emacs.d/lisp/init-project.el new file mode 100644 index 0000000..63aec7d --- /dev/null +++ b/.emacs.d/lisp/init-project.el @@ -0,0 +1,60 @@ +;;; init-project.el --- Project (and Perspective) Configuration File -*- lexical-binding: t -*- +;;; Commentary: +;;; Code: + +(use-package project + :ensure nil + :config + (defun project-recentf () + "Show a list of recently visited files in a project." + (interactive) + (if (boundp 'recentf-list) + (let* ((project-root (expand-file-name (project-root (project-current)))) + (project-recentf-files (mapcar + (lambda (f) (file-relative-name f project-root)) + (seq-filter (apply-partially 'string-prefix-p project-root) recentf-list)))) + (find-file (expand-file-name + (funcall project-read-file-name-function + "Find recent project files" + project-recentf-files nil 'file-name-history nil) + project-root))) + (message "recentf is not enabled"))) + + (add-to-list 'project-switch-commands '(?h "Recentf" project-recentf) t) + (add-to-list 'project-switch-commands '(?b "Consult Project Buffer" consult-project-buffer) t) + (add-to-list 'project-switch-commands '(?r "Consult Ripgrep" consult-ripgrep) t) + (add-to-list 'project-switch-commands '(?m "Magit" magit-status) t) + (add-to-list 'project-switch-commands '(?R "Replace Regexp" project-query-replace-regexp) t) + + ;; project-root and project-try-local copied/modified from https://github.com/karthink/project-x/blob/master/project-x.el + (cl-defmethod project-root ((project (head local))) + "Return root directory of current PROJECT." + (cdr project)) + (defun project-try-local (dir) + "Treat DIR as a project if it contains a .project file." + (if-let ((root (locate-dominating-file dir ".project"))) + (cons 'local root))) + ;; Add this hook last so so that vc takes precedence over local + (add-hook 'project-find-functions 'project-try-local 90) + :bind + ("C-x p P" . project-switch-project) + ("C-x f" . project-recentf)) + +(use-package perspective + :config (persp-mode) + (defun switch-project (proj) + "Switch to project or already open project perspective." + (interactive (list (project-prompt-project-dir))) + (let* ((persp-name (file-name-nondirectory (directory-file-name proj))) + (persp (gethash persp-name (perspectives-hash)))) + (unless (equal persp (persp-curr)) + ;; Create or switch to a perspective named after the project + (persp-switch persp-name) + ;; If the perspective did not exist, switch to the project + (when (not persp) + (project-switch-project proj))))) + :bind + ("C-x p p" . switch-project)) + +(provide 'init-project) +;;; init-project.el ends here diff --git a/.emacs.d/lisp/init-shell.el b/.emacs.d/lisp/init-shell.el index a312d8c..651ad61 100644 --- a/.emacs.d/lisp/init-shell.el +++ b/.emacs.d/lisp/init-shell.el @@ -33,6 +33,7 @@ (use-package multi-vterm :bind (("C-c t" . multi-vterm-next) + ("C-x p t" . multi-vterm-project) ("C-c C-M-t" . multi-vterm) (:map vterm-mode-map ("M-[" . multi-vterm-prev)