This repository has been archived on 2022-11-18. You can view files and clone it, but cannot push or open issues or pull requests.
emacs/init-buffer/init-buffer.el

219 lines
7.7 KiB
EmacsLisp
Raw Normal View History

;;; init-buffer.el --- Initial buffer displayed at startup
2018-11-06 02:14:48 +01:00
;;
;; Copyright (C) 2018-2019 Wojciech Kozlowski
2018-11-06 02:14:48 +01:00
;;
;; Author: Wojciech Kozlowski <wk@wojciechkozlowski.eu>
;; Created: 2018-11-05
2018-11-06 02:14:48 +01:00
;;
;; This file is not part of GNU Emacs.
;;
;;; License: GPLv3
;;
;;; Commentary:
;;
;; The code in this file was heavily inspired by Spacemacs.
;;
;;; Code:
(defconst init-buffer/banner-file
(concat (file-name-as-directory user-emacs-directory)
"init-buffer/blue-robot.png")
2018-11-06 02:14:48 +01:00
"Location of the banner image to use.")
(defconst init-buffer/name "*GNU Emacs*"
2018-11-06 02:14:48 +01:00
"Name of the initial buffer.")
(defconst init-buffer/recentf-list-length 10
2018-11-06 02:14:48 +01:00
"Length used for recentf list.")
(defconst init-buffer/recentf-length-threshold 75
2018-11-06 02:14:48 +01:00
"Threshold of filename length to apply different centre rules.
If at least one file in recentf is longer than this, the list
will not be centered, but offset by a constant instead.")
(defconst init-buffer/buttons-recentf-offset 20
2018-11-06 02:14:48 +01:00
"Relative position between the home buffer buttons and startup lists.")
(defvar init-buffer/buttons-line nil
2018-11-06 02:14:48 +01:00
"Vertical position of the home buffer buttons.
Internal use, do not set this variable.")
(defvar init-buffer/buttons-position nil
2018-11-06 02:14:48 +01:00
"Horizontal position of the home buffer buttons.
Internal use, do not set this variable.")
(defvar init-buffer-mode-map
2018-11-06 02:14:48 +01:00
(let ((map (make-sparse-keymap)))
(define-key map (kbd "RET") 'widget-button-press)
(define-key map [tab] 'widget-forward)
(define-key map (kbd "f") 'widget-forward)
(define-key map (kbd "n") 'widget-forward)
(define-key map [backtab] 'widget-backward)
(define-key map (kbd "b") 'widget-backward)
(define-key map (kbd "p") 'widget-backward)
(define-key map (kbd "r") 'init-buffer/refresh)
2018-11-06 02:14:48 +01:00
(define-key map "q" 'quit-window)
map)
"Keymap for initial buffer mode.")
2020-04-09 14:10:47 +02:00
(define-derived-mode init-buffer-mode fundamental-mode "Init"
2018-11-06 02:14:48 +01:00
"Major mode for startup screen."
:group 'init-buffer
2018-11-06 02:14:48 +01:00
:syntax-table nil
:abbrev-table nil
(setq buffer-read-only t
truncate-lines t))
(defun init-buffer/insert-banner ()
2018-11-06 02:14:48 +01:00
"Display an image banner."
(let* ((spec (create-image init-buffer/banner-file))
2018-11-06 02:14:48 +01:00
(size (image-size spec))
(width (car size))
(left-margin (max 0 (floor (- (window-width) width) 2))))
(goto-char (point-min))
(insert "\n")
(insert (make-string left-margin ?\s))
(insert-image spec)
(insert "\n\n")))
(defun init-buffer/insert-buttons ()
2018-11-06 02:14:48 +01:00
"Create and insert the interactive buttons under the banner."
(goto-char (point-max))
(widget-create 'push-button
:help-echo "Upgrade ELPA packages to the latest versions."
:action (lambda (&rest ignore) (emodule/upgrade))
:mouse-face 'highlight
:follow-link "\C-m"
(propertize "Upgrade" 'face 'font-lock-keyword-face))
(insert " ")
(widget-create 'push-button
:help-echo
"Restore ELPA directory if something got borked."
:action (lambda (&rest ignore) (emodule/restore))
:mouse-face 'highlight
:follow-link "\C-m"
(propertize "Restore"
'face 'font-lock-keyword-face))
(let ((len (- (line-end-position)
(line-beginning-position))))
(init-buffer/center-line)
(setq init-buffer/buttons-line (count-lines 1 (point)))
(setq init-buffer/buttons-position (- (line-end-position)
2018-11-06 02:14:48 +01:00
(line-beginning-position)
len)))
(insert "\n"))
(defun init-buffer/center-line (&optional real-width)
2018-11-06 02:14:48 +01:00
"When point is at the end of a line, center it.
REAL-WIDTH: the real width of the line. If the line contains an image, the size
of that image will be considered to be 1 by the calculation method
used in this function. As a consequence, the caller must calculate
himself the correct length of the line taking into account the
images he inserted in it."
(let* ((width (or real-width (current-column)))
(margin (max 0 (floor (/ (- (window-width) width) 2)))))
(beginning-of-line)
(insert (make-string margin ?\s))
(end-of-line)))
(defun init-buffer/insert-file-list (list)
2018-11-06 02:14:48 +01:00
"Insert an interactive list of files in the home buffer.
LIST-DISPLAY-NAME: the displayed title of the list.
LIST: a list of string pathnames made interactive in this function."
(when (car list)
(mapc (lambda (el)
(insert "\n")
(widget-create 'push-button
:action `(lambda (&rest ignore)
(find-file-existing ,el))
:mouse-face 'highlight
:follow-link "\C-m"
:button-prefix ""
:button-suffix ""
:format "%[%t%]"
(abbreviate-file-name el)))
list)))
(defun init-buffer/subseq (seq start end)
2018-11-06 02:14:48 +01:00
"Adapted version of `cl-subseq'.
Use `cl-subseq', but accounting for end points greater than the size of the
list. Return entire list if end is omitted.
SEQ, START and END are the same arguments as for `cl-subseq'"
(let ((len (length seq)))
(cl-subseq seq start (and (number-or-marker-p end)
(min len end)))))
(defun init-buffer/get-buffer-width ()
2018-11-06 02:14:48 +01:00
"Return the length of longest line in the current buffer."
(save-excursion
(goto-char 0)
(let ((current-max 0))
(while (not (eobp))
(let ((line-length (- (line-end-position) (line-beginning-position))))
(if (< current-max line-length)
(setq current-max line-length)))
(forward-line 1))
current-max)))
(defun init-buffer/center-recentf ()
2018-11-06 02:14:48 +01:00
"Centre recentf list after it was inserted."
(let* ((lists-width (init-buffer/get-buffer-width))
(margin (max 0 (- init-buffer/buttons-position
init-buffer/buttons-recentf-offset)))
(final-padding (if (< lists-width init-buffer/recentf-length-threshold)
2018-11-06 02:14:48 +01:00
(max 0 (floor (/ (- (window-width) lists-width) 2)))
margin)))
(goto-char (point-min))
(while (not (eobp))
(beginning-of-line)
(insert (make-string final-padding ?\s))
(forward-line))))
(defun init-buffer/insert-recentf ()
2018-11-06 02:14:48 +01:00
"Insert startup lists in home buffer."
(goto-char (point-max))
(save-restriction
(narrow-to-region (point) (point))
(recentf-mode)
(when (init-buffer/insert-file-list
(init-buffer/subseq recentf-list 0 init-buffer/recentf-list-length)))
(init-buffer/center-recentf)))
2018-11-06 02:14:48 +01:00
(defun init-buffer/goto-buffer ()
2018-11-06 02:14:48 +01:00
"Create the initial buffer and switch to it."
(with-current-buffer (get-buffer-create init-buffer/name)
2018-11-06 02:14:48 +01:00
(let ((inhibit-read-only t))
(erase-buffer)
(init-buffer/insert-banner)
(init-buffer/insert-buttons)
(init-buffer/insert-recentf))
(init-buffer-mode)
2018-11-06 02:14:48 +01:00
(goto-char (point-min))
(forward-line (- init-buffer/buttons-line 1))
(move-to-column (- init-buffer/buttons-position 1))
2018-11-06 02:14:48 +01:00
(current-buffer)))
(add-hook 'window-setup-hook
(lambda ()
(add-hook 'window-configuration-change-hook
'init-buffer/resize-on-hook)))
2018-11-06 02:14:48 +01:00
(defun init-buffer/resize-on-hook ()
2018-11-06 02:14:48 +01:00
"Hook run on window resize events to redisplay the home buffer."
(let ((home-buffer (get-buffer-window init-buffer/name)))
2018-11-06 02:14:48 +01:00
(when home-buffer
(with-selected-window home-buffer
(init-buffer/goto-buffer)))))
2018-11-06 02:14:48 +01:00
(defun init-buffer/refresh ()
2018-11-06 02:14:48 +01:00
"Force recreation of the spacemacs buffer."
(interactive)
(init-buffer/goto-buffer))
2018-11-06 02:14:48 +01:00
(provide 'init-buffer)
2018-11-06 02:14:48 +01:00
;;; init-buffer.el ends here