doomemacs/modules/ui/doom-dashboard/config.el

348 lines
14 KiB
EmacsLisp
Raw Normal View History

;;; ui/doom-dashboard/config.el -*- lexical-binding: t; -*-
2017-02-20 16:33:14 -05:00
(defvar +doom-dashboard-name " *doom*"
2017-09-13 20:11:16 +02:00
"The name to use for the dashboard buffer.")
2017-02-20 16:33:14 -05:00
(defvar +doom-dashboard-functions '(doom-dashboard-widget-banner
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.")
2017-02-20 16:33:14 -05:00
(defvar +doom-dashboard-inhibit-refresh nil
"If non-nil, the doom buffer won't be refreshed.")
(defvar +doom-dashboard-inhibit-functions ()
"A list of functions which take no arguments. If any of them return non-nil,
dashboard reloading is inhibited.")
(defvar +doom-dashboard-pwd-policy 'last-project
"The policy to use when setting the `default-directory' in the dashboard.
Possible values:
'last-project the `doom-project-root' of the last open buffer
'last the `default-directory' of the last open buffer
a FUNCTION a function run with the `default-directory' of the last
open buffer, that returns a directory path
a STRING a fixed path
nil `default-directory' will never change")
;;
(defvar +doom-dashboard--last-cwd nil)
(defvar +doom-dashboard--width 80)
2017-09-13 20:11:16 +02:00
(defvar +doom-dashboard--height 0)
(defvar +doom-dashboard--old-fringe-indicator fringe-indicator-alist)
(defvar +doom-dashboard--pwd-alist ())
2017-09-13 20:11:16 +02:00
(defvar all-the-icons-scale-factor)
(defvar all-the-icons-default-adjust)
2017-09-13 20:11:16 +02:00
;;
;; Bootstrap
;;
(setq doom-fallback-buffer-name +doom-dashboard-name
initial-buffer-choice #'+doom-dashboard-initial-buffer)
(add-hook 'window-setup-hook #'+doom-dashboard|init)
;;
;; Major mode
;;
2017-06-25 02:01:05 +02:00
(define-derived-mode +doom-dashboard-mode special-mode
2017-09-29 02:41:21 +02:00
(format "DOOM v%s" doom-version)
2018-03-18 02:36:12 -04:00
:syntax-table nil
:abbrev-table nil
2017-06-25 02:01:05 +02:00
"Major mode for the DOOM dashboard buffer."
2018-03-18 02:36:12 -04:00
(setq truncate-lines t
buffer-read-only t)
(setq-local whitespace-style nil)
(setq-local show-trailing-whitespace nil)
2017-06-25 02:01:05 +02:00
(cl-loop for (car . _cdr) in fringe-indicator-alist
collect (cons car nil) into alist
finally do (setq fringe-indicator-alist alist))
(add-hook 'post-command-hook #'+doom-dashboard|reposition-point nil t))
(map! :map +doom-dashboard-mode-map
"n" #'forward-button
:gn [down] #'forward-button
:gn "C-n" #'forward-button
:gn [tab] #'forward-button
:gn "TAB" #'forward-button
"p" #'backward-button
:gn [up] #'backward-button
:gn "C-p" #'backward-button
:gn [backtab] #'backward-button
:gn "S-TAB" #'backward-button
(:when (featurep! :feature evil)
2018-03-18 15:17:40 -04:00
:m "j" #'forward-button
:m "k" #'backward-button
[remap evil-delete] #'ignore
[remap evil-delete-line] #'ignore
[remap evil-insert] #'ignore
[remap evil-append] #'ignore
[remap evil-replace] #'ignore
[remap evil-replace-state] #'ignore
[remap evil-change] #'ignore
[remap evil-change-line] #'ignore
[remap evil-visual-char] #'ignore
[remap evil-visual-line] #'ignore))
;;
;; Hooks
;;
(defun +doom-dashboard|reposition-point ()
"Trap the point in the buttons."
(when (region-active-p)
(deactivate-mark t)
(when (bound-and-true-p evil-mode)
(evil-change-to-previous-state)))
(or (ignore-errors
(if (button-at (point))
(forward-button 0)
(backward-button 1)))
(progn (goto-char (point-min))
(forward-button 1))))
(defun +doom-dashboard|init ()
"Initializes Doom's dashboard."
(unless noninteractive
(add-hook 'window-configuration-change-hook #'+doom-dashboard|resize)
(add-hook 'window-size-change-functions #'+doom-dashboard|resize)
(add-hook 'kill-buffer-query-functions #'+doom-dashboard|reload-on-kill)
(add-hook 'doom-after-switch-buffer-hook #'+doom-dashboard|reload-on-kill)
(unless (daemonp)
(add-hook 'after-make-frame-functions #'+doom-dashboard|make-frame))
;; `persp-mode' integration: update `default-directory' when switching
(add-hook 'persp-created-functions #'+doom-dashboard|record-project)
(add-hook 'persp-activated-functions #'+doom-dashboard|detect-project)
(add-hook 'persp-before-switch-functions #'+doom-dashboard|record-project))
(+doom-dashboard-reload t))
2017-02-20 16:33:14 -05:00
(defun +doom-dashboard|reload-on-kill ()
"A `kill-buffer-query-functions' hook. If this isn't a dashboard buffer, move
along, but record its `default-directory' if the buffer is real. See
`doom-real-buffer-p' for an explanation for what 'real' means.
If this is the dashboard buffer, reload the dashboard."
(or (let ((buf (current-buffer)))
(unless (+doom-dashboard-p buf)
(when (doom-real-buffer-p buf)
(setq +doom-dashboard--last-cwd default-directory)
(+doom-dashboard-update-pwd))
t))
(ignore
(let (+doom-dashboard-inhibit-refresh)
(ignore-errors (+doom-dashboard-reload))))))
(defun +doom-dashboard|make-frame (frame)
"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."
(run-with-timer 0.1 nil #'+doom-dashboard/open frame))
(defun +doom-dashboard|resize (&rest _)
"Recenter the dashboard, and reset its margins and fringes."
(let ((windows (get-buffer-window-list (doom-fallback-buffer) nil t)))
(dolist (win windows)
(set-window-start win 0)
(set-window-fringes win 0 0)
(set-window-margins
win (max 0 (/ (- (window-total-width win) +doom-dashboard--width) 2))))
(when windows
(with-current-buffer (doom-fallback-buffer)
(save-excursion
(with-silent-modifications
(goto-char (point-min))
(delete-region (line-beginning-position)
(save-excursion (skip-chars-forward "\n")
(point)))
(insert (make-string
(max 0 (- (/ (window-height (get-buffer-window)) 2)
(truncate (/ (count-lines (point-min) (point-max))
2))
2)) ?\n)
"\n")))))))
(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'."
2018-01-28 20:37:40 -05:00
(if (doom-real-buffer-p)
(current-buffer)
(doom-fallback-buffer)))
(defun +doom-dashboard-p (buffer)
"Returns t if BUFFER is the dashboard buffer."
(eq buffer (doom-fallback-buffer)))
(defun +doom-dashboard-update-pwd (&optional pwd)
"Update `default-directory' in the Doom dashboard buffer. What it is set to is
controlled by `+doom-dashboard-pwd-policy'."
(if pwd
(with-current-buffer (doom-fallback-buffer)
(setq-local default-directory pwd))
(let ((new-pwd (+doom-dashboard--get-pwd)))
(when (and new-pwd (file-directory-p new-pwd))
(unless (string-suffix-p "/" new-pwd)
(setq new-pwd (concat new-pwd "/")))
(+doom-dashboard-update-pwd new-pwd)))))
(defun +doom-dashboard-reload (&optional force)
"Update the DOOM scratch buffer (or create it, if it doesn't exist)."
(when (or (and (not +doom-dashboard-inhibit-refresh)
(get-buffer-window (doom-fallback-buffer))
(not (window-minibuffer-p (frame-selected-window)))
(not (run-hook-with-args-until-success '+doom-dashboard-inhibit-functions)))
force)
(with-current-buffer (doom-fallback-buffer)
(with-silent-modifications
(save-excursion
(unless (eq major-mode '+doom-dashboard-mode)
(+doom-dashboard-mode))
(erase-buffer)
(insert "\n")
(run-hooks '+doom-dashboard-functions)))
(+doom-dashboard|resize)
(+doom-dashboard|detect-project)
(+doom-dashboard-update-pwd)
(current-buffer))))
2017-02-20 16:33:14 -05:00
;; helpers
(defun +doom-dashboard--center (len s)
2017-06-25 02:01:05 +02:00
(concat (make-string (ceiling (max 0 (- len (length s))) 2) ? )
s))
(defun +doom-dashboard--get-pwd ()
(let ((lastcwd +doom-dashboard--last-cwd)
(policy +doom-dashboard-pwd-policy))
(cond ((null policy)
default-directory)
((stringp policy)
(expand-file-name policy lastcwd))
((functionp policy)
(funcall policy lastcwd))
((null lastcwd)
default-directory)
((eq policy 'last-project)
(let ((cwd default-directory)
(default-directory lastcwd))
(if (doom-project-p)
(doom-project-root)
cwd)))
((eq policy 'last)
lastcwd)
(t
(warn "`+doom-dashboard-pwd-policy' has an invalid value of '%s'"
policy)))))
;;
;; Widgets
;;
(defun doom-dashboard-widget-banner ()
2017-02-20 16:33:14 -05:00
(mapc (lambda (line)
(insert (propertize (+doom-dashboard--center +doom-dashboard--width line)
2017-02-20 16:33:14 -05:00
'face 'font-lock-comment-face) " ")
(insert "\n"))
'("================= =============== =============== ======== ========"
"\\\\ . . . . . . .\\\\ //. . . . . . .\\\\ //. . . . . . .\\\\ \\\\. . .\\\\// . . //"
"||. . ._____. . .|| ||. . ._____. . .|| ||. . ._____. . .|| || . . .\\/ . . .||"
"|| . .|| ||. . || || . .|| ||. . || || . .|| ||. . || ||. . . . . . . ||"
"||. . || || . .|| ||. . || || . .|| ||. . || || . .|| || . | . . . . .||"
"|| . .|| ||. _-|| ||-_ .|| ||. . || || . .|| ||. _-|| ||-_.|\\ . . . . ||"
"||. . || ||-' || || `-|| || . .|| ||. . || ||-' || || `|\\_ . .|. .||"
"|| . _|| || || || || ||_ . || || . _|| || || || |\\ `-_/| . ||"
"||_-' || .|/ || || \\|. || `-_|| ||_-' || .|/ || || | \\ / |-_.||"
"|| ||_-' || || `-_|| || || ||_-' || || | \\ / | `||"
"|| `' || || `' || || `' || || | \\ / | ||"
"|| .===' `===. .==='.`===. .===' /==. | \\/ | ||"
"|| .==' \\_|-_ `===. .===' _|_ `===. .===' _-|/ `== \\/ | ||"
"|| .==' _-' `-_ `=' _-' `-_ `=' _-' `-_ /| \\/ | ||"
"|| .==' _-' '-__\\._-' '-_./__-' `' |. /| | ||"
"||.==' _-' `' | /==.||"
"==' _-' E M A C S \\/ `=="
"\\ _-' `-_ /"
" `'' ``'")))
(defun doom-dashboard-widget-loaded ()
2017-02-20 16:33:14 -05:00
(insert
"\n\n"
2017-02-20 16:33:14 -05:00
(propertize
(+doom-dashboard--center
2017-06-25 02:01:05 +02:00
+doom-dashboard--width
(doom|display-benchmark 'return))
2017-02-20 16:33:14 -05:00
'face 'font-lock-comment-face)
"\n\n"))
2017-02-20 16:33:14 -05:00
(defun doom-dashboard-widget-shortmenu ()
(let ((all-the-icons-scale-factor 1.45)
(all-the-icons-default-adjust -0.02))
(insert "\n")
(mapc (lambda (btn)
(when btn
2017-07-18 22:12:50 +02:00
(cl-destructuring-bind (label icon fn) btn
(insert
(with-temp-buffer
2017-02-20 16:33:14 -05:00
(insert-text-button
2017-07-18 22:12:50 +02:00
(concat (all-the-icons-octicon icon :face 'font-lock-keyword-face)
(propertize (concat " " label) 'face 'font-lock-keyword-face))
2017-07-18 22:12:50 +02:00
'action `(lambda (_) ,fn)
'follow-link t)
(+doom-dashboard--center (- +doom-dashboard--width 2) (buffer-string)))
2017-07-18 22:12:50 +02:00
"\n\n"))))
`(("Homepage" "mark-github"
2017-09-13 20:11:16 +02:00
(browse-url "https://github.com/hlissner/doom-emacs"))
,(when (and (bound-and-true-p persp-mode)
2017-09-13 20:11:16 +02:00
(file-exists-p (expand-file-name persp-auto-save-fname persp-save-dir)))
'("Reload last session" "history"
(+workspace/load-session)))
,(when (fboundp 'org-agenda-list)
'("See agenda for this week" "calendar"
2018-02-18 20:50:30 -05:00
(call-interactively #'org-agenda-list)))
("Recently opened files" "file-text"
(call-interactively (or (command-remapping #'recentf-open-files)
#'recentf-open-files)))
("Open project" "briefcase"
(call-interactively (or (command-remapping #'projectile-switch-project)
#'projectile-switch-project)))
("Jump to bookmark" "bookmark"
(call-interactively (or (command-remapping #'bookmark-jump)
#'bookmark-jump)))
,(when (file-directory-p doom-private-dir)
'("Open private configuration" "tools"
(doom-project-find-file doom-private-dir)))
("Edit my modules list" "settings"
(progn (make-directory doom-private-dir t)
(find-file (expand-file-name "init.el" doom-private-dir))))))))