ui/doom-dashboard: major refactor

+ Fix default-directory not being set properly when switching
  perspectives. ie. Add persp-mode integration (#347, #360)
+ Ensure dashboard initializes properly, at the right time to ensure
  benchmark is properly reported (fix #361)
This commit is contained in:
Henrik Lissner 2018-01-20 02:53:06 -05:00
parent 381a4416ed
commit 0d83834ac7
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
3 changed files with 144 additions and 108 deletions

View file

@ -1,23 +1,35 @@
;;; ui/doom-dashboard/autoload.el -*- lexical-binding: t; -*- ;;; ui/doom-dashboard/autoload.el -*- lexical-binding: t; -*-
;;;###autoload
(defun +doom-dashboard/open (frame)
"Switch to the dashboard in the current window, of the current FRAME."
(interactive (list (selected-frame)))
(with-selected-frame frame
(switch-to-buffer (doom-fallback-buffer))
(+doom-dashboard-reload)))
;;;###autoload ;;;###autoload
(defun +doom-dashboard/next-button () (defun +doom-dashboard/next-button ()
"Jump to the next button after cursor."
(interactive) (interactive)
(ignore-errors (goto-char (next-button (point))))) (ignore-errors (goto-char (next-button (point)))))
;;;###autoload ;;;###autoload
(defun +doom-dashboard/previous-button () (defun +doom-dashboard/previous-button ()
"Jump to the previous button after cursor."
(interactive) (interactive)
(ignore-errors (goto-char (previous-button (point))))) (ignore-errors (goto-char (previous-button (point)))))
;;;###autoload ;;;###autoload
(defun +doom-dashboard/first-button () (defun +doom-dashboard/first-button ()
"Jump to the first button on the dashboard."
(interactive) (interactive)
(goto-char (point-min)) (goto-char (point-min))
(+doom-dashboard/next-button)) (+doom-dashboard/next-button))
;;;###autoload ;;;###autoload
(defun +doom-dashboard/last-button () (defun +doom-dashboard/last-button ()
"Jump to the last button on the dashboard."
(interactive) (interactive)
(goto-char (point-max)) (goto-char (point-max))
(+doom-dashboard/previous-button) (+doom-dashboard/previous-button)

View file

@ -3,15 +3,22 @@
(defvar +doom-dashboard-name " *doom*" (defvar +doom-dashboard-name " *doom*"
"The name to use for the dashboard buffer.") "The name to use for the dashboard buffer.")
(defvar +doom-dashboard-widgets '(banner shortmenu loaded) (defvar +doom-dashboard-functions '(doom-dashboard-widget-banner
"List of widgets to display in a blank scratch buffer.") doom-dashboard-widget-shortmenu
doom-dashboard-widget-loaded)
"List of widget functions to run in the dashboard buffer to construct the
dashboard. These functions take no arguments and the dashboard buffer is current
while they run.")
(defvar +doom-dashboard-inhibit-refresh nil (defvar +doom-dashboard-inhibit-refresh nil
"If non-nil, the doom buffer won't be refreshed.") "If non-nil, the doom buffer won't be refreshed.")
(defvar +doom-dashboard-inhibit-functions () (defvar +doom-dashboard-inhibit-functions ()
"A list of functions that determine whether to inhibit the dashboard from "A list of functions which take no arguments. If any of them return non-nil,
loading.") dashboard reloading is inhibited.")
(defvar +doom-dashboard-initial-pwd doom-emacs-dir
"The initial `default-directory' for the dashboard at startup.")
(defvar +doom-dashboard-pwd-policy 'last-project (defvar +doom-dashboard-pwd-policy 'last-project
"The policy to use when setting the `default-directory' in the dashboard. "The policy to use when setting the `default-directory' in the dashboard.
@ -31,92 +38,81 @@ Possible values:
(defvar +doom-dashboard--width 80) (defvar +doom-dashboard--width 80)
(defvar +doom-dashboard--height 0) (defvar +doom-dashboard--height 0)
(defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist) (defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist)
(defvar +doom-dashboard--pwd-alist ())
(defvar all-the-icons-scale-factor) (defvar all-the-icons-scale-factor)
(defvar all-the-icons-default-adjust) (defvar all-the-icons-default-adjust)
;; ;;
;; Bootstrap
;;
(setq doom-fallback-buffer +doom-dashboard-name (setq doom-fallback-buffer +doom-dashboard-name
initial-buffer-choice #'+doom-dashboard) initial-buffer-choice #'+doom-dashboard-initial-buffer)
(add-hook 'window-setup-hook #'+doom-dashboard|init)
;; ;;
;; Commands ;; Major mode
;;
(defun +doom-dashboard/open (frame &optional noswitch)
(interactive (list (selected-frame)))
(unless (run-hook-with-args-until-success '+doom-dashboard-inhibit-functions)
(prog1
(unless +doom-dashboard-inhibit-refresh
(with-selected-frame frame
(unless noswitch
(switch-to-buffer (doom-fallback-buffer)))
(+doom-dashboard-reload)))
(setq +doom-dashboard-inhibit-refresh nil)
(current-buffer))))
;;
;; Library
;; ;;
(define-derived-mode +doom-dashboard-mode special-mode (define-derived-mode +doom-dashboard-mode special-mode
(format "DOOM v%s" doom-version) (format "DOOM v%s" doom-version)
"Major mode for the DOOM dashboard buffer." "Major mode for the DOOM dashboard buffer."
(read-only-mode +1)
(when (featurep 'evil)
(evil-emacs-state))
(setq truncate-lines t) (setq truncate-lines t)
(setq-local whitespace-style nil) (setq-local whitespace-style nil)
(setq-local show-trailing-whitespace nil) (setq-local show-trailing-whitespace nil)
(cl-loop for (car . _cdr) in fringe-indicator-alist (cl-loop for (car . _cdr) in fringe-indicator-alist
collect (cons car nil) into alist collect (cons car nil) into alist
finally do (setq fringe-indicator-alist alist))) finally do (setq fringe-indicator-alist alist)))
(add-hook '+doom-dashboard-mode-hook #'read-only-mode)
(defun +doom-dashboard () (map! :map +doom-dashboard-mode-map
"Initialize doom-dashboard and set up its hooks. Meant to be used with "n" #'+doom-dashboard/next-button
`initial-buffer-choice'. Returns the resulting buffer." "p" #'+doom-dashboard/previous-button
(map! :map +doom-dashboard-mode-map "N" #'+doom-dashboard/last-button
"n" #'+doom-dashboard/next-button "P" #'+doom-dashboard/first-button
"p" #'+doom-dashboard/previous-button (:when (featurep! :feature evil)
"N" #'+doom-dashboard/last-button
"P" #'+doom-dashboard/first-button
:em "j" #'+doom-dashboard/next-button :em "j" #'+doom-dashboard/next-button
:em "k" #'+doom-dashboard/previous-button :em "k" #'+doom-dashboard/previous-button
:em "gg" #'+doom-dashboard/first-button :em "gg" #'+doom-dashboard/first-button
:em "G" #'+doom-dashboard/last-button :em "G" #'+doom-dashboard/last-button))
[remap evil-insert] #'evil-normal-state
[remap evil-change] #'evil-normal-state
[remap evil-visual-char] #'evil-normal-state
[remap evil-visual-line] #'evil-normal-state
[remap evil-delete] #'evil-normal-state
[remap evil-delete-char] #'evil-normal-state)
(add-hook 'window-configuration-change-hook #'+doom-dashboard-reload)
;;
;; Hooks
;;
(defun +doom-dashboard|init ()
"Initializes Doom's dashboard."
(add-hook 'focus-in-hook #'+doom-dashboard-reload) (add-hook 'focus-in-hook #'+doom-dashboard-reload)
(add-hook 'window-configuration-change-hook #'+doom-dashboard|resize)
(add-hook 'kill-buffer-query-functions #'+doom-dashboard|reload-on-kill) (add-hook 'kill-buffer-query-functions #'+doom-dashboard|reload-on-kill)
(when (daemonp) (when (daemonp)
(add-hook 'after-make-frame-functions #'+doom-dashboard|make-frame)) (add-hook 'after-make-frame-functions #'+doom-dashboard|make-frame))
(cond ((doom-real-buffer-p) ;; `persp-mode' integration: update `default-directory' when switching
(current-buffer)) (add-hook 'persp-created-functions #'+doom-dashboard|record-project)
(+doom-dashboard--first (add-hook 'persp-activated-functions #'+doom-dashboard|detect-project)
(prog1 (add-hook 'persp-before-switch-functions #'+doom-dashboard|record-project)
(let ((default-directory doom-emacs-dir)) (+doom-dashboard-reload t)
(+doom-dashboard/open (selected-frame) t)) (+doom-dashboard|resize))
(setq +doom-dashboard--first nil)))
(t
(+doom-dashboard/open (selected-frame) t))))
(defun +doom-dashboard|reload-on-kill () (defun +doom-dashboard|reload-on-kill ()
"If this isn't a dashboard buffer, move along, but record its "A `kill-buffer-query-functions' hook. If this isn't a dashboard buffer, move
`default-directory' if the buffer is real. See `doom-real-buffer-p' for an along, but record its `default-directory' if the buffer is real. See
explanation for what 'real' means. `doom-real-buffer-p' for an explanation for what 'real' means.
If this is the dashboard buffer, reload the dashboard." If this is the dashboard buffer, reload the dashboard."
(or (unless (+doom-dashboard-p) (or (let ((buf (current-buffer)))
(when (doom-real-buffer-p) (unless (+doom-dashboard-p buf)
(setq +doom-dashboard--last-cwd default-directory) (when (doom-real-buffer-p buf)
(+doom-dashboard-update-pwd)) (setq +doom-dashboard--last-cwd default-directory)
t) (+doom-dashboard-update-pwd))
t))
(ignore (ignore
(let (+doom-dashboard-inhibit-refresh) (let (+doom-dashboard-inhibit-refresh)
(ignore-errors (+doom-dashboard-reload)))))) (ignore-errors (+doom-dashboard-reload))))))
@ -124,59 +120,85 @@ If this is the dashboard buffer, reload the dashboard."
(defun +doom-dashboard|make-frame (frame) (defun +doom-dashboard|make-frame (frame)
"Reload the dashboard after a brief pause. This is necessary for new frames, "Reload the dashboard after a brief pause. This is necessary for new frames,
whose dimensions may not be fully initialized by the time this is run." whose dimensions may not be fully initialized by the time this is run."
(run-with-timer 0.1 nil #'+doom-dashboard frame)) (run-with-timer 0.1 nil #'+doom-dashboard/open frame))
(defun +doom-dashboard-p (&optional buffer) (defun +doom-dashboard|resize ()
"Resize the margins and fringes on dashboard windows."
(dolist (win (get-buffer-window-list (doom-fallback-buffer) nil t))
(set-window-fringes win 0 0)
(set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2)))))
(defun +doom-dashboard|detect-project (&rest _)
"Check for a `last-project-root' parameter in the perspective, and set the
dashboard's `default-directory' to it if it exists.
This and `+doom-dashboard|record-project' 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 pwd))))
(defun +doom-dashboard|record-project (&optional persp &rest _)
"Record the last `doom-project-root' for the current perspective. See
`+doom-dashboard|detect-project' for more information."
(when (bound-and-true-p persp-mode)
(set-persp-parameter
'last-project-root (doom-project-root)
(if (perspective-p persp) persp (get-current-persp)))))
;;
;; Library
;;
(defun +doom-dashboard-initial-buffer ()
"Returns buffer to display on startup. Designed for `initial-buffer-choice'."
(if (doom-real-buffer-p)
(current-buffer)
(doom-fallback-buffer)))
(defun +doom-dashboard-p (buffer)
"Returns t if BUFFER is the dashboard buffer." "Returns t if BUFFER is the dashboard buffer."
(eq (or buffer (current-buffer)) (eq buffer (doom-fallback-buffer)))
(doom-fallback-buffer)))
(defun +doom-dashboard-update-pwd () (defun +doom-dashboard-update-pwd (&optional pwd)
"Update `default-directory' in the Doom dashboard buffer. What it is set to is "Update `default-directory' in the Doom dashboard buffer. What it is set to is
controlled by `+doom-dashboard-pwd-policy'." controlled by `+doom-dashboard-pwd-policy'."
(with-current-buffer (doom-fallback-buffer) (with-current-buffer (doom-fallback-buffer)
(let ((new-pwd (+doom-dashboard--get-pwd))) (if pwd
(when (and new-pwd (file-directory-p new-pwd)) (setq-local default-directory pwd)
(unless (string-suffix-p "/" new-pwd) (let ((new-pwd (+doom-dashboard--get-pwd)))
(setq new-pwd (concat new-pwd "/"))) (when (and new-pwd (file-directory-p new-pwd))
(setq default-directory new-pwd))))) (unless (string-suffix-p "/" new-pwd)
(setq new-pwd (concat new-pwd "/")))
(setq-local default-directory new-pwd))))))
(defun +doom-dashboard-reload (&optional force) (defun +doom-dashboard-reload (&optional force)
"Update the DOOM scratch buffer (or create it, if it doesn't exist)." "Update the DOOM scratch buffer (or create it, if it doesn't exist)."
(let ((fallback-buffer (doom-fallback-buffer))) (when (or (and (not +doom-dashboard-inhibit-refresh)
(when (or (and after-init-time (get-buffer-window (doom-fallback-buffer))
(not +doom-dashboard-inhibit-refresh) (not (window-minibuffer-p (frame-selected-window)))
(get-buffer-window fallback-buffer) (not (run-hook-with-args-until-success '+doom-dashboard-inhibit-functions)))
(not (window-minibuffer-p (frame-selected-window)))) force)
force) (with-current-buffer (doom-fallback-buffer)
(with-current-buffer fallback-buffer (with-silent-modifications
(+doom-dashboard-update-pwd) (save-excursion
(with-silent-modifications
(unless (eq major-mode '+doom-dashboard-mode) (unless (eq major-mode '+doom-dashboard-mode)
(+doom-dashboard-mode)) (+doom-dashboard-mode))
(erase-buffer) (erase-buffer)
(let ((+doom-dashboard--height (save-excursion (mapc #'funcall +doom-dashboard-functions))
(window-height (get-buffer-window fallback-buffer))) (insert
(lines 1) (make-string (max 0 (- (/ (window-height (get-buffer-window)) 2)
content) (/ (count-lines (point-min) (point-max)) 2)))
(with-temp-buffer ?\n)))
(dolist (widget-name +doom-dashboard-widgets) (unless (button-at (point))
(funcall (intern (format "doom-dashboard-widget--%s" widget-name))) (goto-char (next-button (point-min)))))
(insert "\n")) (+doom-dashboard|detect-project)
(setq content (buffer-string) (+doom-dashboard|resize)
lines (count-lines (point-min) (point-max)))) (+doom-dashboard-update-pwd)
(insert (make-string (max 0 (- (/ +doom-dashboard--height 2) (current-buffer))))
(/ lines 2)))
?\n)
content))
(unless (button-at (point))
(goto-char (next-button (point-min)))))))
;; Update all dashboard windows
(dolist (win (get-buffer-window-list fallback-buffer nil t))
(set-window-fringes win 0 0)
(set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2))))
fallback-buffer))
;; helpers ;; helpers
(defun +doom-dashboard--center (len s) (defun +doom-dashboard--center (len s)
@ -186,7 +208,10 @@ controlled by `+doom-dashboard-pwd-policy'."
(defun +doom-dashboard--get-pwd () (defun +doom-dashboard--get-pwd ()
(let ((lastcwd +doom-dashboard--last-cwd) (let ((lastcwd +doom-dashboard--last-cwd)
(policy +doom-dashboard-pwd-policy)) (policy +doom-dashboard-pwd-policy))
(cond ((null policy) (cond (+doom-dashboard--first
(setq +doom-dashboard--first nil)
+doom-dashboard-initial-pwd)
((null policy)
default-directory) default-directory)
((stringp policy) ((stringp policy)
(expand-file-name policy lastcwd)) (expand-file-name policy lastcwd))
@ -211,7 +236,7 @@ controlled by `+doom-dashboard-pwd-policy'."
;; Widgets ;; Widgets
;; ;;
(defun doom-dashboard-widget--banner () (defun doom-dashboard-widget-banner ()
(mapc (lambda (line) (mapc (lambda (line)
(insert (propertize (+doom-dashboard--center +doom-dashboard--width line) (insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
'face 'font-lock-comment-face) " ") 'face 'font-lock-comment-face) " ")
@ -236,22 +261,23 @@ controlled by `+doom-dashboard-pwd-policy'."
"\\ _-' `-_ /" "\\ _-' `-_ /"
" `'' ``'"))) " `'' ``'")))
(defun doom-dashboard-widget--loaded () (defun doom-dashboard-widget-loaded ()
(insert (insert
"\n" "\n\n"
(propertize (propertize
(+doom-dashboard--center (+doom-dashboard--center
+doom-dashboard--width +doom-dashboard--width
(format "Loaded %d packages in %d modules in %.02fs" (format "Loaded %d packages in %d modules in %.02fs"
(length doom--package-load-path) (length doom--package-load-path)
(hash-table-size doom-modules) (hash-table-size doom-modules)
(if (floatp doom-init-time) doom-init-time 0.0))) doom-init-time))
'face 'font-lock-comment-face) 'face 'font-lock-comment-face)
"\n")) "\n\n"))
(defun doom-dashboard-widget--shortmenu () (defun doom-dashboard-widget-shortmenu ()
(let ((all-the-icons-scale-factor 1.45) (let ((all-the-icons-scale-factor 1.45)
(all-the-icons-default-adjust -0.02)) (all-the-icons-default-adjust -0.02))
(insert "\n")
(mapc (lambda (btn) (mapc (lambda (btn)
(when btn (when btn
(cl-destructuring-bind (label icon fn) btn (cl-destructuring-bind (label icon fn) btn

View file

@ -22,9 +22,7 @@
(def-test! dashboard-p (def-test! dashboard-p
(let ((fallback-buffer (doom-fallback-buffer))) (let ((fallback-buffer (doom-fallback-buffer)))
(should (equal (buffer-name fallback-buffer) +doom-dashboard-name)) (should (equal (buffer-name fallback-buffer) +doom-dashboard-name))
(should (+doom-dashboard-p fallback-buffer)) (should (+doom-dashboard-p fallback-buffer))))
(with-current-buffer fallback-buffer
(should (+doom-dashboard-p)))))
(def-test! get-pwd (def-test! get-pwd
:minor-mode projectile-mode :minor-mode projectile-mode