diff --git a/modules/ui/doom-dashboard/config.el b/modules/ui/doom-dashboard/config.el index e606e3ded..7687aad3d 100644 --- a/modules/ui/doom-dashboard/config.el +++ b/modules/ui/doom-dashboard/config.el @@ -122,11 +122,8 @@ PLIST can have the following properties: (add-hook 'doom-switch-buffer-hook #'+doom-dashboard-reload-maybe-h) (add-hook 'delete-frame-functions #'+doom-dashboard-reload-frame-h) ;; Update `default-directory' in dashboard when switching workspaces - (add-hook 'tab-bar-tab-post-select-functions #'+doom-dashboard--tab-detect-project-fn) - ;; HACK Fix #2219 where, in GUI daemon frames, the dashboard loses center - ;; alignment after switching (or killing) workspaces. - (when (daemonp) - (add-hook 'tab-bar-tab-post-select-functions #'+doom-dashboard-reload-maybe-h)))) + ;; (add-hook 'tab-bar-tab-pre-select-functions #'+doom-dashboard--record-project-h) + (add-hook 'tab-bar-tab-post-select-functions #'+doom-dashboard--record-project-h))) (add-hook 'doom-init-ui-hook #'+doom-dashboard-init-h 'append) @@ -288,38 +285,19 @@ whose dimensions may not be fully initialized by the time this is run." (car +doom-dashboard-banner-padding)) ?\n)))))))) -(defun +doom-dashboard--tab-detect-project-fn (from-tab to-tab &rest _) +(defun +doom-dashboard--record-project-h (from-tab to-tab &rest _) "Set dashboard's PWD to current persp's `last-project-root', if it exists. -This and `+doom-dashboard--tab-record-project-h' provides `persp-mode' +This and `+doom-dashboard--persp-record-project-h' provides `persp-mode' integration with the Doom dashboard. It ensures that the dashboard is always in the correct project (which may be different across perspective)." (when (bound-and-true-p tabspaces-mode) - (setf (alist-get 'last-project-root from-tab) - (doom-project-root)) - (when-let* ((pwd (alist-get 'last-project-root to-tab))) + (ignore-errors + (+workspaces-parameter-set (+workspaces-get-by-id (alist-get 'id from-tab)) + 'last-project-root (doom-project-root))) + (when-let* ((pwd (+workspaces-parameter to-tab 'last-project-root))) (+doom-dashboard-update-pwd-h pwd)))) -;; (defun +doom-dashboard--persp-detect-project-h (&rest _) -;; "Set dashboard's PWD to current persp's `last-project-root', if it exists. - -;; This and `+doom-dashboard--persp-record-project-h' provides `persp-mode' -;; integration with the Doom dashboard. It ensures that the dashboard is always in -;; the correct project (which may be different across perspective)." -;; (when (bound-and-true-p persp-mode) -;; (when-let (pwd (persp-parameter 'last-project-root)) -;; (+doom-dashboard-update-pwd-h pwd)))) - -;; (defun +doom-dashboard--persp-record-project-h (&optional persp &rest _) -;; "Record the last `doom-project-root' for the current persp. -;; See `+doom-dashboard--persp-detect-project-h' for more information." -;; (when (bound-and-true-p persp-mode) -;; (set-persp-parameter -;; 'last-project-root (doom-project-root) -;; (if (persp-p persp) -;; persp -;; (get-current-persp))))) - ;; ;;; Library diff --git a/modules/ui/workspaces/autoload/workspaces.el b/modules/ui/workspaces/autoload/workspaces.el index d984f160b..c42f0bb8e 100644 --- a/modules/ui/workspaces/autoload/workspaces.el +++ b/modules/ui/workspaces/autoload/workspaces.el @@ -87,6 +87,15 @@ index. If NOERROR? is omitted, throws an error if NAME doesn't exist." (unless noerror? (user-error "No workspace found: %s" name)))) +;;;###autoload +(defun +workspaces-get-by-id (id) + "Return the tab by unique ID." + (catch 'result + (dolist (fr (frame-list)) + (dolist (tab (tab-bar-tabs fr)) + (when (equal id (alist-get 'id tab)) + (throw 'result tab)))))) + ;;;###autoload (defalias '+workspaces-exists-p #'tab-bar--tab-index-by-name) @@ -139,6 +148,43 @@ workspace." (tabspaces-remove-buffer buffer)) (tabspaces-remove-buffer buffer))) +;;;###autoload +(defun +workspaces-parameter (workspace param &optional default) + "Return a WORKSPACE's PARAM, otherwise DEFAULT." + (if-let* ((table (gethash (alist-get 'id (or workspace (+workspaces-current))) + +workspaces--parameters))) + (gethash param table default) + default)) + +;;;###autoload +(defun +workspaces-parameter-set (workspace param val) + "Set a WORKSPACE's PARAM to VAL" + (let* ((workspace (or workspace (+workspaces-current))) + (id (or (alist-get 'id workspace) + (error "Workspace has no id attribute: %S" workspace)))) + (puthash param val (or (gethash id +workspaces--parameters) + (error "Invalid workspace ID: %s" id))))) + + +;; +;;; Hooks + +;;;###autoload +(defun +workspaces-init-parameters-h (tab) + "Initialize the current workspace's parameters." + (puthash (alist-get 'id tab) (make-hash-table :test 'eq) + +workspaces--parameters)) + +;;;###autoload +(defun +workspaces-cleanup-parameters-h (_tab _last-tab?) + "Cleanup workspace parameters for forgotten workspaces." + (dolist (id (hash-table-keys +workspaces--parameters)) + (or (cl-loop for tab in tab-bar-closed-tabs + for tid = (map-nested-elt tab '(tab id)) + unless (eq (gethash tid +workspaces--parameters t) t) + return t) + (remhash id +workspaces--parameters)))) + ;; ;;; Interactive commands diff --git a/modules/ui/workspaces/config.el b/modules/ui/workspaces/config.el index 69efb7016..21abe3edd 100644 --- a/modules/ui/workspaces/config.el +++ b/modules/ui/workspaces/config.el @@ -3,6 +3,8 @@ (defvar +workspaces-dir (file-name-concat doom-profile-data-dir "workspaces/") "The directory where workspace session files are stored.") +(defvar +workspaces--parameters (make-hash-table :test 'equal)) + ;; ;;; Packages @@ -37,10 +39,26 @@ [remap delete-window] #'+workspaces/close-window-or-workspace [remap evil-window-delete] #'+workspaces/close-window-or-workspace) - ;; Per-workspace `winner-mode' history (add-to-list 'window-persistent-parameters '(winner-ring . t)) + + ;; HACK: Emacs tabs don't offer an easy way to associate data with a tab, + ;; since tab names aren't unique, so these advice is dedicated to providing + ;; that: + (autoload 'uuidgen-1 "uuidgen") + (defadvice! +workspaces--embed-id-a (tab) + :filter-return #'tab-bar--tab + :filter-return #'tab-bar--current-tab-make + (unless (alist-get 'id tab) + (setq tab (append tab `((id . ,(uuidgen-1)))))) + tab) + (add-to-list 'window-persistent-parameters '(id . writable)) + + (add-hook 'tab-bar-tab-post-open-functions #'+workspaces-init-parameters-h) + (add-hook 'tab-bar-tab-pre-close-functions #'+workspaces-cleanup-parameters-h) + + ;; HACK: Tabspaces is hardcoded to equate the root of a version controlled ;; project as the only kind of project root, and lacks integration with ;; project.el or projectile. This fixes that.