aboutsummaryrefslogtreecommitdiffstats
path: root/elpa/dashboard-20220409.620/dashboard.el
diff options
context:
space:
mode:
Diffstat (limited to 'elpa/dashboard-20220409.620/dashboard.el')
-rw-r--r--elpa/dashboard-20220409.620/dashboard.el472
1 files changed, 472 insertions, 0 deletions
diff --git a/elpa/dashboard-20220409.620/dashboard.el b/elpa/dashboard-20220409.620/dashboard.el
new file mode 100644
index 0000000..9c8b80e
--- /dev/null
+++ b/elpa/dashboard-20220409.620/dashboard.el
@@ -0,0 +1,472 @@
+;;; dashboard.el --- A startup screen extracted from Spacemacs -*- lexical-binding: t -*-
+
+;; Copyright (c) 2016-2022 emacs-dashboard maintainers
+;;
+;; Author : Rakan Al-Hneiti <rakan.alhneiti@gmail.com>
+;; Maintainer : Jesús Martínez <jesusmartinez93@gmail.com>
+;; Shen, Jen-Chieh <jcs090218@gmail.com>
+;; URL : https://github.com/emacs-dashboard/emacs-dashboard
+;;
+;; This file is not part of GNU Emacs.
+;;
+;;; License: GPLv3
+;;
+;; Created: October 05, 2016
+;; Package-Version: 1.8.0-SNAPSHOT
+;; Keywords: startup, screen, tools, dashboard
+;; Package-Requires: ((emacs "26.1"))
+;;; Commentary:
+
+;; An extensible Emacs dashboard, with sections for
+;; bookmarks, projects (projectile or project.el), org-agenda and more.
+
+;;; Code:
+
+(require 'ffap)
+(require 'recentf)
+
+(require 'dashboard-widgets)
+
+(declare-function bookmark-get-filename "ext:bookmark.el")
+(declare-function bookmark-all-names "ext:bookmark.el")
+(declare-function dashboard-ls--dirs "ext:dashboard-ls.el")
+(declare-function dashboard-ls--files "ext:dashboard-ls.el")
+(declare-function page-break-lines-mode "ext:page-break-lines.el")
+(declare-function project-forget-projects-under "ext:project.el")
+
+(defgroup dashboard nil
+ "Extensible startup screen."
+ :group 'applications)
+
+;; Custom splash screen
+(defvar dashboard-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-p") 'dashboard-previous-line)
+ (define-key map (kbd "C-n") 'dashboard-next-line)
+ (define-key map (kbd "<up>") 'dashboard-previous-line)
+ (define-key map (kbd "<down>") 'dashboard-next-line)
+ (define-key map (kbd "k") 'dashboard-previous-line)
+ (define-key map (kbd "j") 'dashboard-next-line)
+ (define-key map [tab] 'widget-forward)
+ (define-key map (kbd "C-i") 'widget-forward)
+ (define-key map [backtab] 'widget-backward)
+ (define-key map (kbd "RET") 'dashboard-return)
+ (define-key map [mouse-1] 'dashboard-mouse-1)
+ (define-key map (kbd "}") #'dashboard-next-section)
+ (define-key map (kbd "{") #'dashboard-previous-section)
+
+ (define-key map (kbd "<backspace>") #'dashboard-remove-item-under)
+ (define-key map (kbd "<delete>") #'dashboard-remove-item-under)
+ (define-key map (kbd "DEL") #'dashboard-remove-item-under)
+
+ (define-key map (kbd "1") #'dashboard-section-1)
+ (define-key map (kbd "2") #'dashboard-section-2)
+ (define-key map (kbd "3") #'dashboard-section-3)
+ (define-key map (kbd "4") #'dashboard-section-4)
+ (define-key map (kbd "5") #'dashboard-section-5)
+ (define-key map (kbd "6") #'dashboard-section-6)
+ (define-key map (kbd "7") #'dashboard-section-7)
+ (define-key map (kbd "8") #'dashboard-section-8)
+ (define-key map (kbd "9") #'dashboard-section-9)
+ map)
+ "Keymap for dashboard mode.")
+
+(defcustom dashboard-after-initialize-hook nil
+ "Hook that is run after dashboard buffer is initialized."
+ :group 'dashboard
+ :type 'hook)
+
+(define-derived-mode dashboard-mode special-mode "Dashboard"
+ "Dashboard major mode for startup screen."
+ :group 'dashboard
+ :syntax-table nil
+ :abbrev-table nil
+ (buffer-disable-undo)
+ (when (featurep 'whitespace) (whitespace-mode -1))
+ (when (featurep 'linum) (linum-mode -1))
+ (when (featurep 'display-line-numbers) (display-line-numbers-mode -1))
+ (when (featurep 'page-break-lines) (page-break-lines-mode 1))
+ (setq-local revert-buffer-function #'dashboard-refresh-buffer)
+ (setq inhibit-startup-screen t
+ buffer-read-only t
+ truncate-lines t))
+
+(defcustom dashboard-center-content nil
+ "Whether to center content within the window."
+ :type 'boolean
+ :group 'dashboard)
+
+(defconst dashboard-buffer-name "*dashboard*"
+ "Dashboard's buffer name.")
+
+(defvar dashboard-force-refresh nil
+ "If non-nil, force refresh dashboard buffer.")
+
+(defvar dashboard--section-starts nil
+ "List of section starting positions.")
+
+;;
+;; Util
+;;
+(defun dashboard--goto-line (line)
+ "Goto LINE."
+ (goto-char (point-min)) (forward-line (1- line)))
+
+(defmacro dashboard--save-excursion (&rest body)
+ "Execute BODY save window point."
+ (declare (indent 0) (debug t))
+ `(let ((line (line-number-at-pos nil t))
+ (column (current-column)))
+ ,@body
+ (dashboard--goto-line line)
+ (move-to-column column)))
+
+;;
+;; Core
+;;
+(defun dashboard--current-section ()
+ "Return section symbol in dashboard."
+ (save-excursion
+ (if (and (search-backward dashboard-page-separator nil t)
+ (search-forward dashboard-page-separator nil t))
+ (let ((ln (thing-at-point 'line)))
+ (cond ((string-match-p "Recent Files:" ln) 'recents)
+ ((string-match-p "Bookmarks:" ln) 'bookmarks)
+ ((string-match-p "Projects:" ln) 'projects)
+ ((string-match-p "Agenda for " ln) 'agenda)
+ ((string-match-p "Registers:" ln) 'registers)
+ ((string-match-p "List Directories:" ln) 'ls-directories)
+ ((string-match-p "List Files:" ln) 'ls-files)
+ (t (user-error "Unknown section from dashboard"))))
+ (user-error "Failed searching dashboard section"))))
+
+;;
+;; Navigation
+;;
+(defun dashboard-previous-section ()
+ "Navigate back to previous section."
+ (interactive)
+ (let ((current-position (point)) current-section-start previous-section-start)
+ (dolist (elt dashboard--section-starts)
+ (when (and current-section-start (not previous-section-start))
+ (setq previous-section-start elt))
+ (when (and (not current-section-start) (< elt current-position))
+ (setq current-section-start elt)))
+ (goto-char (if (eq current-position current-section-start)
+ previous-section-start
+ current-section-start))))
+
+(defun dashboard-next-section ()
+ "Navigate forward to next section."
+ (interactive)
+ (let ((current-position (point)) next-section-start
+ (section-starts (reverse dashboard--section-starts)))
+ (dolist (elt section-starts)
+ (when (and (not next-section-start)
+ (> elt current-position))
+ (setq next-section-start elt)))
+ (when next-section-start
+ (goto-char next-section-start))))
+
+(defun dashboard--section-lines ()
+ "Return a list of integer represent the starting line number of each section."
+ (let (pb-lst)
+ (save-excursion
+ (goto-char (point-min))
+ (while (search-forward dashboard-page-separator nil t)
+ (when (ignore-errors (dashboard--current-section))
+ (push (line-number-at-pos) pb-lst))))
+ (setq pb-lst (reverse pb-lst))
+ pb-lst))
+
+(defun dashboard--goto-section-by-index (index)
+ "Navigate to item section by INDEX."
+ (let* ((pg-lst (dashboard--section-lines))
+ (items-id (1- index))
+ (items-pg (nth items-id pg-lst))
+ (items-len (length pg-lst)))
+ (when (and items-pg (< items-id items-len))
+ (dashboard--goto-line items-pg))))
+
+(defun dashboard-section-1 ()
+ "Navigate to section 1." (interactive) (dashboard--goto-section-by-index 1))
+(defun dashboard-section-2 ()
+ "Navigate to section 2." (interactive) (dashboard--goto-section-by-index 2))
+(defun dashboard-section-3 ()
+ "Navigate to section 3." (interactive) (dashboard--goto-section-by-index 3))
+(defun dashboard-section-4 ()
+ "Navigate to section 4." (interactive) (dashboard--goto-section-by-index 4))
+(defun dashboard-section-5 ()
+ "Navigate to section 5." (interactive) (dashboard--goto-section-by-index 5))
+(defun dashboard-section-6 ()
+ "Navigate to section 6." (interactive) (dashboard--goto-section-by-index 6))
+(defun dashboard-section-7 ()
+ "Navigate to section 7." (interactive) (dashboard--goto-section-by-index 7))
+(defun dashboard-section-8 ()
+ "Navigate to section 8." (interactive) (dashboard--goto-section-by-index 8))
+(defun dashboard-section-9 ()
+ "Navigate to section 9." (interactive) (dashboard--goto-section-by-index 9))
+
+(defun dashboard-previous-line (arg)
+ "Move point up and position it at that line’s item.
+Optional prefix ARG says how many lines to move; default is one line."
+ (interactive "^p")
+ (dashboard-next-line (- arg)))
+
+(defun dashboard-next-line (arg)
+ "Move point down and position it at that line’s item.
+Optional prefix ARG says how many lines to move; default is one line."
+ ;; code heavily inspired by `dired-next-line'
+ (interactive "^p")
+ (let (line-move-visual goal-column)
+ (line-move arg t))
+ ;; We never want to move point into an invisible line. Dashboard doesn’t
+ ;; use invisible text currently but when it does we’re ready!
+ (while (and (invisible-p (point))
+ (not (if (and arg (< arg 0)) (bobp) (eobp))))
+ (forward-char (if (and arg (< arg 0)) -1 1)))
+ (beginning-of-line-text))
+
+;;
+;; ffap
+;;
+(defun dashboard--goto-section (section)
+ "Move to SECTION declares in variable `dashboard-item-shortcuts'."
+ (let ((fnc (intern (format "dashboard-jump-to-%s" section))))
+ (dashboard-funcall-fboundp fnc)))
+
+(defun dashboard--current-index (section &optional pos)
+ "Return the idex by SECTION from POS."
+ (let (target-ln section-line)
+ (save-excursion
+ (when pos (goto-char pos))
+ (setq target-ln (line-number-at-pos))
+ (dashboard--goto-section section)
+ (setq section-line (line-number-at-pos)))
+ (- target-ln section-line)))
+
+(defun dashboard--section-list (section)
+ "Return the list from SECTION."
+ (cl-case section
+ (`recents recentf-list)
+ (`bookmarks (bookmark-all-names))
+ (`projects (dashboard-projects-backend-load-projects))
+ (`ls-directories (dashboard-ls--dirs))
+ (`ls-files (dashboard-ls--files))
+ (t (user-error "Unknown section for search: %s" section))))
+
+(defun dashboard--current-item-in-path ()
+ "Return the path from current dashboard section in path."
+ (let ((section (dashboard--current-section)) path)
+ (cl-case section
+ (`bookmarks (setq path (bookmark-get-filename path)))
+ (t
+ (let ((lst (dashboard--section-list section))
+ (index (dashboard--current-index section)))
+ (setq path (nth index lst)))))
+ path))
+
+(defun dashboard--on-path-item-p ()
+ "Return non-nil if current point is on the item path from dashboard."
+ (save-excursion
+ (when (= (point) (line-end-position)) (ignore-errors (forward-char -1)))
+ (eq (get-char-property (point) 'face) 'dashboard-items-face)))
+
+(defun dashboard--ffap-guesser--adv (fnc &rest args)
+ "Advice execution around function `ffap-guesser'.
+
+Argument FNC is the adviced function.
+Optional argument ARGS adviced function arguments."
+ (cl-case major-mode
+ (`dashboard-mode
+ (or (and (dashboard--on-path-item-p)
+ (dashboard--current-item-in-path))
+ (apply fnc args))) ; fallback
+ (t (apply fnc args))))
+(advice-add 'ffap-guesser :around #'dashboard--ffap-guesser--adv)
+
+;;
+;; Removal
+;;
+(defun dashboard-remove-item-under ()
+ "Remove a item from the current item section."
+ (interactive)
+ (cl-case (dashboard--current-section)
+ (`recents (dashboard-remove-item-recentf))
+ (`bookmarks (dashboard-remove-item-bookmarks))
+ (`projects (dashboard-remove-item-projects))
+ (`agenda (dashboard-remove-item-agenda))
+ (`registers (dashboard-remove-item-registers)))
+ (dashboard--save-excursion (dashboard-refresh-buffer)))
+
+(defun dashboard-remove-item-recentf ()
+ "Remove a file from `recentf-list'."
+ (interactive)
+ (let ((path (save-excursion (end-of-line) (ffap-guesser))))
+ (setq recentf-list (delete path recentf-list)))
+ (dashboard-mute-apply (recentf-save-list)))
+
+(defun dashboard-remove-item-projects ()
+ "Remove a path from `project--list'."
+ (interactive)
+ (let ((path (save-excursion (end-of-line) (ffap-guesser))))
+ (dashboard-mute-apply
+ (cl-case dashboard-projects-backend
+ (`projectile ) ; TODO: ..
+ (`project-el (project-forget-projects-under path))))))
+
+(defun dashboard-remove-item-bookmarks ()
+ "Remove a bookmarks from `bookmark-alist'."
+ (interactive)) ; TODO: ..
+
+(defun dashboard-remove-item-agenda ()
+ "Remove an agenda from `org-agenda-files'."
+ (interactive "P")
+ (let ((agenda-file (get-text-property (point) 'dashboard-agenda-file))
+ (agenda-loc (get-text-property (point) 'dashboard-agenda-loc)))
+ (with-current-buffer (find-file-noselect agenda-file)
+ (goto-char agenda-loc)
+ (call-interactively 'org-todo))))
+
+(defun dashboard-remove-item-registers ()
+ "Remove a registers from `register-alist'."
+ (interactive)) ; TODO: ..
+
+;;
+;; Confirmation
+;;
+(defun dashboard-return ()
+ "Hit return key in dashboard buffer."
+ (interactive)
+ (let ((start-ln (line-number-at-pos)) (fd-cnt 0) diff-line entry-pt)
+ (save-excursion
+ (while (and (not diff-line)
+ (not (= (point) (point-min)))
+ (not (get-char-property (point) 'button))
+ (not (= (point) (point-max))))
+ (forward-char 1)
+ (setq fd-cnt (1+ fd-cnt))
+ (unless (= start-ln (line-number-at-pos))
+ (setq diff-line t)))
+ (unless (= (point) (point-max))
+ (setq entry-pt (point))))
+ (when (= fd-cnt 1)
+ (setq entry-pt (1- (point))))
+ (if entry-pt
+ (widget-button-press entry-pt)
+ (call-interactively #'widget-button-press))))
+
+(defun dashboard-mouse-1 ()
+ "Key for keymap `mouse-1'."
+ (interactive)
+ (let ((old-track-mouse track-mouse))
+ (when (call-interactively #'widget-button-click)
+ (setq track-mouse old-track-mouse))))
+
+;;
+;; Insertion
+;;
+(defun dashboard-maximum-section-length ()
+ "For the just-inserted section, calculate the length of the longest line."
+ (let ((max-line-length 0))
+ (save-excursion
+ (dashboard-previous-section)
+ (while (not (eobp))
+ (setq max-line-length
+ (max max-line-length
+ (- (line-end-position) (line-beginning-position))))
+ (forward-line 1)))
+ max-line-length))
+
+(defun dashboard-insert-startupify-lists ()
+ "Insert the list of widgets into the buffer."
+ (interactive)
+ (let ((buffer-exists (buffer-live-p (get-buffer dashboard-buffer-name)))
+ (recentf-is-on (recentf-enabled-p))
+ (origial-recentf-list recentf-list)
+ (dashboard-num-recents (or (cdr (assoc 'recents dashboard-items)) 0))
+ (max-line-length 0))
+ ;; disable recentf mode, so we don't flood the recent files list with org
+ ;; mode files do this by making a copy of the part of the list we'll use
+ ;; let dashboard widgets change that then restore the orginal list afterwards
+ ;; (this avoids many saves/loads that would result from disabling/enabling
+ ;; recentf-mode)
+ (when recentf-is-on
+ (setq recentf-list (dashboard-subseq recentf-list dashboard-num-recents)))
+ (when (or dashboard-force-refresh
+ (not (eq dashboard-buffer-last-width (window-width)))
+ (not buffer-exists))
+ (setq dashboard-banner-length (window-width)
+ dashboard-buffer-last-width dashboard-banner-length)
+ (with-current-buffer (get-buffer-create dashboard-buffer-name)
+ (let (buffer-read-only)
+ (erase-buffer)
+ (dashboard-insert-banner)
+ (dashboard-insert-page-break)
+ (setq dashboard--section-starts nil)
+ (mapc (lambda (els)
+ (let* ((el (or (car-safe els) els))
+ (list-size
+ (or (cdr-safe els)
+ dashboard-items-default-length))
+ (item-generator
+ (cdr-safe (assoc el dashboard-item-generators))))
+ (add-to-list 'dashboard--section-starts (point))
+ (funcall item-generator list-size)
+ (when recentf-is-on
+ (setq recentf-list origial-recentf-list))
+ (setq max-line-length
+ (max max-line-length (dashboard-maximum-section-length)))
+ (dashboard-insert-page-break)))
+ dashboard-items)
+ (when dashboard-center-content
+ (when dashboard--section-starts
+ (goto-char (car (last dashboard--section-starts))))
+ (let ((margin (floor (/ (max (- (window-width) max-line-length) 0) 2))))
+ (while (not (eobp))
+ (unless (string-suffix-p (thing-at-point 'line) dashboard-page-separator)
+ (insert (make-string margin ?\ )))
+ (forward-line 1))))
+ (dashboard-insert-footer))
+ (goto-char (point-min))
+ (dashboard-mode)))
+ (when recentf-is-on
+ (setq recentf-list origial-recentf-list))))
+
+(add-hook 'window-setup-hook
+ (lambda ()
+ (add-hook 'window-size-change-functions 'dashboard-resize-on-hook)
+ (dashboard-resize-on-hook)))
+
+(defun dashboard-refresh-buffer (&rest _)
+ "Refresh buffer."
+ (interactive)
+ (let ((dashboard-force-refresh t)) (dashboard-insert-startupify-lists))
+ (switch-to-buffer dashboard-buffer-name))
+
+(defun dashboard-resize-on-hook (&optional _)
+ "Re-render dashboard on window size change."
+ (let ((space-win (get-buffer-window dashboard-buffer-name))
+ (frame-win (frame-selected-window)))
+ (when (and space-win
+ (not (window-minibuffer-p frame-win)))
+ (with-selected-window space-win
+ (dashboard-insert-startupify-lists)))))
+
+;;;###autoload
+(defun dashboard-setup-startup-hook ()
+ "Setup post initialization hooks.
+If a command line argument is provided, assume a filename and skip displaying
+Dashboard."
+ (when (< (length command-line-args) 2)
+ (add-hook 'after-init-hook (lambda ()
+ ;; Display useful lists of items
+ (dashboard-insert-startupify-lists)))
+ (add-hook 'emacs-startup-hook (lambda ()
+ (switch-to-buffer dashboard-buffer-name)
+ (goto-char (point-min))
+ (redisplay)
+ (run-hooks 'dashboard-after-initialize-hook)))))
+
+(provide 'dashboard)
+;;; dashboard.el ends here