wip: feat: Defer many packages
Shaving MILLISECONDS off our startup time!!! Fuck yes! I've measured the average startup time to be 0.68s in the previous commit, and an average of 0.52 with this commit.
This commit is contained in:
29
README.org
29
README.org
@@ -95,6 +95,35 @@ On boot, ...
|
|||||||
|
|
||||||
sydnix-cli is a command-line utility written in Clojure wrapping various sydnix-related scripts.
|
sydnix-cli is a command-line utility written in Clojure wrapping various sydnix-related scripts.
|
||||||
|
|
||||||
|
** Deferring Emacs packages
|
||||||
|
|
||||||
|
Nearly all configuration of Emacs packages happens under the ~use-package~ macro. ~use-package~ has various keywords with special syntax for common tasks, such as instrumenting hooks, setting keybindings, and customising variables. You may be surprised to learn that these are not /just/ syntactic sugar }:) (I was).
|
||||||
|
|
||||||
|
As an example, this
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package which-key
|
||||||
|
:hook (on-first-input . which-key-mode)
|
||||||
|
:custom
|
||||||
|
(which-key-allow-evil-operators t)
|
||||||
|
(which-key-show-operator-state-maps t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
is not the same as this
|
||||||
|
|
||||||
|
#+begin_src emacs-lisp
|
||||||
|
(use-package which-key
|
||||||
|
:config
|
||||||
|
(add-hook 'on-first-input #'which-key-mode)
|
||||||
|
(setq which-key-allow-evil-operators t)
|
||||||
|
(setq which-key-show-operator-state-maps t)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
The difference connects to another silly obsession of the Emacs hacker: startup time. ~use-package~'s special keywords will /defer/ the loading of the package ([cite:@systemcrafters2021how]) . E.g., instead of loading ~which-key~ on startup, it will be loaded when the ~on-first-input~ hook is first called.
|
||||||
|
|
||||||
|
~on-first-input~ is one of many useful hooks provided by the package [[https://github.com/emacsmirror/on][on.el]] specialised for fine-grained control of package loading.
|
||||||
|
|
||||||
|
>>>>>>> Conflict 1 of 1 ends
|
||||||
* Tasks
|
* Tasks
|
||||||
|
|
||||||
** Begin setting up doomless Emacs
|
** Begin setting up doomless Emacs
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
"straight/repos/straight.el/bootstrap.el"))
|
"straight/repos/straight.el/bootstrap.el"))
|
||||||
(bootstrap-version 7))
|
(bootstrap-version 7))
|
||||||
(unless (file-exists-p bootstrap-file)
|
(unless (file-exists-p bootstrap-file)
|
||||||
|
(message "Could not find Straight's bootstrap file. Attempting to download it now.")
|
||||||
(let* ((url "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el")
|
(let* ((url "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el")
|
||||||
(url-buffer (url-retrieve-synchronously
|
(url-buffer (url-retrieve-synchronously
|
||||||
url 'silent 'inhibit-cookies)))
|
url 'silent 'inhibit-cookies)))
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
(add-to-list 'load-path (file-name-concat user-emacs-directory "modules"))
|
(add-to-list 'load-path (file-name-concat user-emacs-directory "modules"))
|
||||||
(add-to-list 'load-path (file-name-concat user-emacs-directory "lib"))
|
(add-to-list 'load-path (file-name-concat user-emacs-directory "lib"))
|
||||||
|
|
||||||
|
(require 'syd-autosave)
|
||||||
|
(require 'syd-display-startup-time)
|
||||||
(require 'syd-evil)
|
(require 'syd-evil)
|
||||||
(require 'syd-ui)
|
(require 'syd-ui)
|
||||||
(require 'syd-autosave)
|
|
||||||
|
|||||||
@@ -11,4 +11,9 @@
|
|||||||
(or (getenv "EMACS_CACHE_DIR")
|
(or (getenv "EMACS_CACHE_DIR")
|
||||||
(error "Need $EMACS_CACHE_DIR")))
|
(error "Need $EMACS_CACHE_DIR")))
|
||||||
|
|
||||||
|
;; `on.el' provies a collection of utility hooks and functions ported from Doom
|
||||||
|
;; Emacs. The hooks make it easier to speed up Emacs startup by providing
|
||||||
|
;; finer-grained control of the timing at which packages are loaded.
|
||||||
|
(use-package on)
|
||||||
|
|
||||||
(provide 'syd-prelude)
|
(provide 'syd-prelude)
|
||||||
|
|||||||
@@ -19,21 +19,18 @@
|
|||||||
(".*"
|
(".*"
|
||||||
,(file-name-concat syd-cache-dir "autosave") t))
|
,(file-name-concat syd-cache-dir "autosave") t))
|
||||||
kept-new-versions 5
|
kept-new-versions 5
|
||||||
delete-old-versions t
|
delete-old-versions t))
|
||||||
save-place-file (file-name-concat syd-cache-dir "places")
|
|
||||||
bookmark-default-file (file-name-concat syd-data-dir "bookmarks")
|
|
||||||
recentf-save-file (file-name-concat syd-data-dir "recentf")))
|
|
||||||
|
|
||||||
;; Save your cursor position in recently-opened files.
|
;; Save your cursor position in recently-opened files.
|
||||||
(use-package saveplace
|
(use-package saveplace
|
||||||
:config
|
:hook (on-first-file . save-place-mode)
|
||||||
(save-place-mode 1))
|
:custom (save-place-file (file-name-concat syd-cache-dir "places")))
|
||||||
|
|
||||||
;; Keep track of recently-visited files.
|
;; Keep track of recently-visited files.
|
||||||
(use-package recentf
|
(use-package recentf
|
||||||
:config
|
:hook ((on-first-file . recentf-mode)
|
||||||
(add-hook 'find-file-hook #'recentf-save-list)
|
(find-file-hook . recentf-save-list))
|
||||||
(recentf-mode 1))
|
:custom (recentf-save-file (file-name-concat syd-data-dir "recentf")))
|
||||||
|
|
||||||
|
|
||||||
(provide 'syd-autosave)
|
(provide 'syd-autosave)
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
;;; syd-display-startup-time.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(defun syd-display-startup-time ()
|
||||||
|
(message "Emacs loaded in %s with %d garbage collections."
|
||||||
|
(format "%.3f seconds"
|
||||||
|
(float-time
|
||||||
|
(time-subtract after-init-time before-init-time)))
|
||||||
|
gcs-done))
|
||||||
|
|
||||||
|
(use-package emacs
|
||||||
|
:hook
|
||||||
|
(emacs-startup-hook . syd-display-startup-time))
|
||||||
|
|
||||||
|
(provide 'syd-display-startup-time)
|
||||||
@@ -2,10 +2,26 @@
|
|||||||
|
|
||||||
;; Vim emulation.
|
;; Vim emulation.
|
||||||
(use-package evil
|
(use-package evil
|
||||||
:init
|
:preface
|
||||||
(setq evil-want-minibuffer t)
|
(setq evil-want-minibuffer t
|
||||||
(setq evil-move-beyond-eol t)
|
evil-move-beyond-eol t
|
||||||
(setq evil-vsplit-window-right t)
|
evil-vsplit-window-right t
|
||||||
|
evil-ex-search-vim-style-regexp t
|
||||||
|
evil-ex-visual-char-range t
|
||||||
|
evil-mode-line-format nil
|
||||||
|
evil-normal-state-cursor 'box
|
||||||
|
evil-emacs-state-cursor 'hbar
|
||||||
|
evil-operator-state-cursor 'evil-half-cursor
|
||||||
|
evil-insert-state-cursor 'bar
|
||||||
|
evil-visual-state-cursor 'hollow
|
||||||
|
;; Only do highlighting in selected window so that Emacs has less work
|
||||||
|
;; to do highlighting them all.
|
||||||
|
evil-ex-interactive-search-highlight 'selected-window
|
||||||
|
;; It's infuriating that innocuous "beginning of line" or "end of line"
|
||||||
|
;; errors will abort macros, so suppress them:
|
||||||
|
evil-kbd-macro-suppress-motion-error t
|
||||||
|
evil-undo-system (cond ((featurep 'undo-tree) 'undo-tree)
|
||||||
|
((featurep 'undo-fu) 'undo-fu)))
|
||||||
;; These two are required for evil-collection.
|
;; These two are required for evil-collection.
|
||||||
(setq evil-want-keybinding nil
|
(setq evil-want-keybinding nil
|
||||||
evil-want-integration t)
|
evil-want-integration t)
|
||||||
@@ -20,16 +36,18 @@
|
|||||||
;; integrations.
|
;; integrations.
|
||||||
(use-package evil-collection
|
(use-package evil-collection
|
||||||
:after evil
|
:after evil
|
||||||
:custom
|
:custom (evil-collection-setup-minibuffer t)
|
||||||
(evil-collection-setup-minibuffer t)
|
|
||||||
:config
|
:config
|
||||||
(evil-collection-init))
|
(evil-collection-init))
|
||||||
|
|
||||||
;; Tim Pope's famous `surround.vim' for Evil.
|
;; Tim Pope's famous `surround.vim' for Evil.
|
||||||
(use-package evil-surround
|
(use-package evil-surround
|
||||||
:ensure t
|
:commands (global-evil-surround-mode
|
||||||
|
evil-surround-edit
|
||||||
|
evil-Surround-edit
|
||||||
|
evil-surround-region)
|
||||||
|
:hook (on-first-input . global-evil-surround-mode)
|
||||||
:config
|
:config
|
||||||
(global-evil-surround-mode 1)
|
|
||||||
;; In `emacs-lisp-mode', `' is a much more common pair than ``.
|
;; In `emacs-lisp-mode', `' is a much more common pair than ``.
|
||||||
(add-hook 'emacs-lisp-mode-hook
|
(add-hook 'emacs-lisp-mode-hook
|
||||||
(lambda ()
|
(lambda ()
|
||||||
@@ -38,20 +56,21 @@
|
|||||||
;; TODO: I'd like JK to escape visual state. evil-escape only allows defining a
|
;; TODO: I'd like JK to escape visual state. evil-escape only allows defining a
|
||||||
;; single key sequence. Perhaps key-chord is capable of this?
|
;; single key sequence. Perhaps key-chord is capable of this?
|
||||||
(use-package evil-escape
|
(use-package evil-escape
|
||||||
:config
|
:hook (on-first-input . evil-escape-mode)
|
||||||
(setq-default evil-escape-key-sequence "jk"
|
:custom ((evil-escape-key-sequence "jk")
|
||||||
evil-escape-delay 0.15)
|
(evil-escape-delay 0.15)))
|
||||||
(evil-escape-mode 1))
|
|
||||||
|
|
||||||
;; `evil-nerd-commenter' has a bunch of cool functions[1]. Here, only the Evil
|
;; `evil-nerd-commenter' has a bunch of cool functions[1]. Here, only the Evil
|
||||||
;; operator is used. }:3
|
;; operator is used. }:3
|
||||||
;; [1]: https://github.com/redguardtoo/evil-nerd-commenter?tab=readme-ov-file#commands-and-hotkeys
|
;; [1]: https://github.com/redguardtoo/evil-nerd-commenter?tab=readme-ov-file#commands-and-hotkeys
|
||||||
(use-package evil-nerd-commenter
|
(use-package evil-nerd-commenter
|
||||||
:config
|
:commands (evilnc-comment-operator
|
||||||
(define-key evil-normal-state-map "#" #'evilnc-comment-operator)
|
evilnc-inner-comment
|
||||||
(define-key evil-visual-state-map "#" #'evilnc-comment-operator)
|
evilnc-outer-commenter)
|
||||||
(define-key evil-inner-text-objects-map "c" 'evilnc-inner-commenter)
|
:bind (:map evil-normal-state-map ("#" . evilnc-comment-operator)
|
||||||
(define-key evil-outer-text-objects-map "c" 'evilnc-outer-commenter))
|
:map evil-visual-state-map ("#" . evilnc-comment-operator)
|
||||||
|
:map evil-inner-text-objects-map ("c" . evilnc-inner-comment)
|
||||||
|
:map evil-outer-text-objects-map ("c" . evilnc-outer-comment)))
|
||||||
|
|
||||||
;; Enhance `evil-surround' with integration with `embrace'.
|
;; Enhance `evil-surround' with integration with `embrace'.
|
||||||
(use-package evil-embrace
|
(use-package evil-embrace
|
||||||
@@ -60,68 +79,60 @@
|
|||||||
:config
|
:config
|
||||||
(evil-embrace-enable-evil-surround-integration))
|
(evil-embrace-enable-evil-surround-integration))
|
||||||
|
|
||||||
;; Provides a command to swap two regions of text.
|
;; Provides an Evil operator to swap two spans of text.
|
||||||
(use-package evil-exchange
|
(use-package evil-exchange
|
||||||
:config
|
:bind (:map evil-normal-state-map ("gX" . evil-exchange)
|
||||||
(define-key evil-normal-state-map "gX" 'evil-exchange)
|
:map evil-visual-state-map ("gX" . evil-exchange)))
|
||||||
(define-key evil-visual-state-map "gX" 'evil-exchange))
|
|
||||||
|
|
||||||
;; Evil doesn't ship with support for Vim's 'g-'/'g+'. `evil-numbers'
|
;; Evil doesn't ship with support for Vim's 'g-'/'g+'. `evil-numbers'
|
||||||
;; implements this.
|
;; implements this.
|
||||||
(use-package evil-numbers
|
(use-package evil-numbers
|
||||||
:config
|
|
||||||
;; 'g=' is a bit more comfortable than 'g+', whilst preserving the analogy.
|
;; 'g=' is a bit more comfortable than 'g+', whilst preserving the analogy.
|
||||||
;; ('=' is '+' modulo shift)
|
;; ('=' is '+' modulo shift)
|
||||||
(define-key evil-normal-state-map "g=" 'evil-numbers/inc-at-pt)
|
:bind (:map evil-normal-state-map ("g=" . 'evil-numbers/inc-at-pt)
|
||||||
(define-key evil-normal-state-map "g-" 'evil-numbers/dec-at-pt))
|
:map evil-normal-state-map ("g-" . 'evil-numbers/dec-at-pt)))
|
||||||
|
|
||||||
;; Tree-sitter queries → Evil text objects.
|
;; Tree-sitter queries → Evil text objects.
|
||||||
(use-package evil-textobj-tree-sitter)
|
(use-package evil-textobj-tree-sitter
|
||||||
|
:defer t)
|
||||||
|
|
||||||
;; Visually "flash" the region acted upon by Evil-mode operations.
|
;; Visually "flash" the region acted upon by Evil-mode operations.
|
||||||
(use-package evil-goggles
|
(use-package evil-goggles
|
||||||
|
:hook (on-first-input . evil-goggles-mode)
|
||||||
;; The flash animation will delay actions, which can be very annoying for some
|
;; The flash animation will delay actions, which can be very annoying for some
|
||||||
;; operations. Disable `evil-goggles' for those ones.
|
;; operations. Disable `evil-goggles' for those ones.
|
||||||
:custom
|
:custom
|
||||||
(evil-goggles-enable-delete nil)
|
((evil-goggles-enable-delete nil)
|
||||||
(evil-goggles-enable-change nil)
|
(evil-goggles-enable-change nil)
|
||||||
(evil-goggles-duration 0.1)
|
(evil-goggles-duration 0.1)))
|
||||||
:config
|
|
||||||
(evil-goggles-mode 1))
|
|
||||||
|
|
||||||
;; Change cursor shape and color by evil state in terminal.
|
;; Change cursor shape and color by evil state in terminal.
|
||||||
(use-package evil-terminal-cursor-changer
|
(use-package evil-terminal-cursor-changer
|
||||||
|
;; This package is only useful in the terminal.
|
||||||
:if (not (display-graphic-p))
|
:if (not (display-graphic-p))
|
||||||
:config
|
:hook (on-first-input . evil-terminal-cursor-changer-activate))
|
||||||
(setq evil-motion-state-cursor 'box)
|
|
||||||
(setq evil-visual-state-cursor 'box)
|
|
||||||
(setq evil-normal-state-cursor 'box)
|
|
||||||
(setq evil-insert-state-cursor 'bar)
|
|
||||||
(setq evil-emacs-state-cursor 'hbar)
|
|
||||||
(evil-terminal-cursor-changer-activate))
|
|
||||||
|
|
||||||
;; Automatic alignment in region, by regexp.
|
;; Automatic alignment in region, by regexp.
|
||||||
(use-package evil-lion
|
(use-package evil-lion
|
||||||
:config
|
:hook (on-first-input . evil-lion-mode))
|
||||||
(evil-lion-mode 1))
|
|
||||||
|
|
||||||
;; Provides the 'g' text object which selects the entire buffer.
|
;; 'g' text object selecting the entire buffer.
|
||||||
(use-package evil-textobj-entire)
|
(with-eval-after-load 'evil
|
||||||
|
(evil-define-text-object
|
||||||
|
evil-entire-buffer (count &optional beg end type)
|
||||||
|
"Select entire buffer"
|
||||||
|
(evil-range (point-min) (point-max) type))
|
||||||
|
(define-key evil-inner-text-objects-map "g" #'evil-entire-buffer)
|
||||||
|
(define-key evil-outer-text-objects-map "g" #'evil-entire-buffer))
|
||||||
|
|
||||||
;; 2-character search.
|
;; 2-character search.
|
||||||
(use-package evil-snipe
|
(use-package evil-snipe
|
||||||
:commands evil-snipe-local-mode evil-snipe-override-local-mode
|
:commands (evil-snipe-local-mode evil-snipe-override-local-mode)
|
||||||
:hook (on-first-input . evil-snipe-override-mode)
|
:hook ((on-first-input . evil-snipe-override-mode)
|
||||||
:hook (on-first-input . evil-snipe-mode)
|
(on-first-input . evil-snipe-mode))
|
||||||
:init
|
:custom ((evil-snipe-smart-case t)
|
||||||
(setq evil-snipe-smart-case t
|
(evil-snipe-scope 'visible)
|
||||||
evil-snipe-scope 'visible
|
(evil-snipe-repeat-scope 'visible)
|
||||||
evil-snipe-repeat-scope 'visible
|
(evil-snipe-char-fold t)))
|
||||||
evil-snipe-char-fold t))
|
|
||||||
|
|
||||||
;; Extend the set of delimiters recognised by '%'.
|
|
||||||
(use-package evil-matchit
|
|
||||||
:config
|
|
||||||
(global-evil-matchit-mode 1))
|
|
||||||
|
|
||||||
(provide 'syd-evil)
|
(provide 'syd-evil)
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
|
|
||||||
;; Show possible completions for a partially-entered key sequence.
|
;; Show possible completions for a partially-entered key sequence.
|
||||||
(use-package which-key
|
(use-package which-key
|
||||||
:custom
|
:hook (on-first-input . which-key-mode)
|
||||||
(which-key-allow-evil-operators t)
|
:custom ((which-key-allow-evil-operators t)
|
||||||
(which-key-show-operator-state-maps t)
|
(which-key-show-operator-state-maps t)))
|
||||||
:config
|
|
||||||
(which-key-mode 1))
|
|
||||||
|
|
||||||
;; Beautiful theme in dark and light.
|
;; Beautiful theme in dark and light.
|
||||||
(use-package kanagawa-themes
|
(use-package kanagawa-themes
|
||||||
@@ -16,17 +14,20 @@
|
|||||||
(use-package emacs
|
(use-package emacs
|
||||||
:custom
|
:custom
|
||||||
;; Allow the opening of new minibuffers from inside existing minibuffers.
|
;; Allow the opening of new minibuffers from inside existing minibuffers.
|
||||||
(enable-recursive-minibuffers t)
|
((enable-recursive-minibuffers t)
|
||||||
;; Hide commands in M-x which do not work in the current mode.
|
;; Hide commands in M-x which do not work in the current mode.
|
||||||
(read-extended-command-predicate #'command-completion-default-include-p)
|
(read-extended-command-predicate #'command-completion-default-include-p))
|
||||||
:config
|
:config
|
||||||
;; Disable blinking cursor. I don't really like it, but it also doesn't play
|
;; Disable blinking cursor. Aesthetically, I personally don't fancy it;
|
||||||
;; well with `evil-terminal-cursor-changer'.
|
;; technically, it doesn't play well with `evil-terminal-cursor-changer'.
|
||||||
(blink-cursor-mode -1))
|
(blink-cursor-mode -1))
|
||||||
|
|
||||||
|
;; Vertico is a simple completion engine that replaces Emacs' built-in
|
||||||
|
;; completion engine, achieving Just Works™ compatibility. This is in contrast
|
||||||
|
;; to e.g. Helm and Ivy, which spawn ecosystems orthogonal to Emacs, and
|
||||||
|
;; diametrically-opposed to each other.
|
||||||
(use-package vertico
|
(use-package vertico
|
||||||
:init
|
:hook (on-first-input . vertico-mode))
|
||||||
(vertico-mode 1))
|
|
||||||
|
|
||||||
;; Orderless provides a completion style that divides the pattern into
|
;; Orderless provides a completion style that divides the pattern into
|
||||||
;; space-separated components, and matches candidates that match all of the
|
;; space-separated components, and matches candidates that match all of the
|
||||||
@@ -34,8 +35,8 @@
|
|||||||
;; ways: literally, as a regexp, as an initialism, in the flex style, or as
|
;; ways: literally, as a regexp, as an initialism, in the flex style, or as
|
||||||
;; multiple word prefixes. By default, regexp and literal matches are enabled.
|
;; multiple word prefixes. By default, regexp and literal matches are enabled.
|
||||||
(use-package orderless
|
(use-package orderless
|
||||||
:custom
|
:custom ((completion-styles '(orderless basic))
|
||||||
(completion-styles '(orderless basic))
|
(completion-category-overrides
|
||||||
(completion-category-overrides '((file (styles basic partial-completion)))))
|
'((file (styles basic partial-completion))))))
|
||||||
|
|
||||||
(provide 'syd-ui)
|
(provide 'syd-ui)
|
||||||
|
|||||||
Reference in New Issue
Block a user