Skip to content

An Emacs configuration focussing on in-build features and the need for speed (fast start-up time).

License

Notifications You must be signed in to change notification settings

echjansen/pure-emacs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

= P U R E - E M A C S =

A multi purpose Emacs configuration, appreciating the built-in features and exploring the future ones.

This configuration focuses on:

  • Use of the built-in Emacs features, unless it’s inferior or missing.
  • Fast startup time (0.05 seconds in TTY, 0.2 seconds in GUI)
  • Default Emacs keys

This configuration

Fast

This configuration has very fast startup times. It accomplishes this by maximizing the built-in features available to Emacs since version 28.1. So how is the fast start-up time achieved:

  1. Byte compilation of the Emacs configuration (make emacs)
  2. Utilise package.el to install external packages, but do not initialise package.el during runtime Emacs.
  3. Utilise use-package.el to configure features, but use expanded macros in byte-compiled files during runtime Emacs.
  4. Lazy loading of code, if you don’t need it - don’t load it
  5. Use builtin features of Emacs (who would have thought)

The result is that Emacs starts in a TTY in approx 0.05 seconds and Emacs graphical in 0.2 seconds.

Emacs builtin features

More often than not are we attracted by eye candy extensions to Emacs, without considering what Emacs has to offer directly out-of-the-box. With each new version of Emacs, new features are included and it is worthwhile reviewing these before looking for alternatives. This configuration uses builtin features before external packages, unless there is a clear advantage over using an external alternative. It’s your choice to enable such alternatives by including the pure-future.el module, or run built-in features only by requiring pure-Emacs.

Note: The variable package–builtins defined in package.el lists all Emacs built-in features!

These built-in features are configured:

;;;; Emacs
;;;;; = emacs - sensible defaults
;;;;; = cus-edit - Emacs customization
;;;; Appearance
;;;;; = timer - display time
;;;;; = simple - modeline info and line display
;;;;; = display-fill-column-indicator
;;;;; = display-line-numbers
;;;;; = hl-line - highlight line at point
;;;; Help and Information
;;;;; = help - always select the help windows
;;;;; = eldoc - echo area context at point information
;;;;; = transient - menus and options
;;;;; = apropos - find symbols, functions, variables, etc
;;;; File Management
;;;;; = files - files and backups
;;;;; = recentf - recently opened files
;;;;; = saveplace - last position in file
;;;;; = dired - file management
;;;;; = uniquify - files with the same name get directory included.
;;;; Buffer Management
;;;;; = ibuffer - buffer management
;;;; Window Management
;;;;; = windmove - reposition buffers
;;;;; = winner - undo / redo window order
;;;; Minibuffer and Completion
;;;;; = minibuffer - selection window
;;;;; = savehist - last minibuffer commands used
;;;;; = icomplete - vertical completion buffer
;;;; Search and Replace
;;;;; = isearch - find
;;;;; = replace - contains occur
;;;; Keys
;;;;; - repeat - why repeat complex key combinations
;;;; Editing
;;;;; = ispell - spell checking (install hunspell)
;;;;; = flyspell - on the fly spell checking
;;;;; = dictionary - look up words for meaning (on-line)
;;;;; = abbrev - replace acronims with full word
;;;;; = dabbrev - dynamic abbreviations
;;;;; = delsel - delete selected
;;;; Navigation
;;;;; = imenu - list content of a buffer in headers
;;;; Coding
;;;;; = project - project management
;;;;; = vc - version control
;;;;; = outline - code folding
;;;;; = hideshow - function and expression folding
;;;;; = reveal - open folded blocks when searching
;;;;; = elec-pair - parenthesis
;;;;; = whitespace - show whitespaces
;;;;; = flymake - identify code faults
;;;;; = treesit - Emacs language parser
;;;;; = eglot - Emacs client for the Language Server Protocol
;;;; Programming Languages
;;;;; = python - programming in python
;;;; Shells
;;;;; = eshell - the Emacs shell created with elsip. Runs everywhere.
;;;; Tools
;;;;; = calendar - calendar dialogue.
;;;;; = url
;;;; Security and Privacy
;;;;; = epg - Emacs GnuPG interface
;;;;; = epa - EasyPG file encryption and decryption
;;;;; = auth-source - handle username / passwords for accounts
;;;;; = auto-source-pass
;;;; Communication
;;;;; = eww - Emacs web wowser
;;;; Org Mode
;;;;; = org-mode - the one and only writing environment (and more)
;;;; Pure Functions
;;;;; = pure--suppress-messages
;;; pure-emacs.el ends here

Modular

This configuration is modular. There are currently 5 modules of which two are compulsory:

  • pure-common - variables you might want to personalize.
  • pure-emacs - Emacs built-in features, good starting point for your Emacs setup.
  • pure-future - Emacs external packages that are popular and potential candidates for future integration in core Emacs.
  • pure-me - Emacs external packages that are of interest to me/you, because of your daily work

Dependencies

Some features in Emacs require external dependencies to be installed separately.Below is a list of dependencies by module:

  • pure-emacs.el (vanilla Emacs):
    • hunspell - spelling checker (or aspell, or ispell)
    • hunspell-en_au - spelling checker language (change to your region)
    • dict - dictionary application
    • dict-gcide - dictionary (there are options such as dict-wn. -gcide, etc)
    • gnupg - pretty good protection
    • python-lsp-server - python language server
  • (optional) pure-email (email client):
    • mu - mail utilities that include an Emacs client (Elisp)
    • mbsync - (or isync) mailbox synchronization
    • msmtp - SMTP client with sendmail compatibility

Installation

It is assumed you have installed the latest version of Emacs using your OS package manager, and your Emacs version is at least 29.1 or later.

Cloning pure-emacs

Use git to clone pure-emacs:

cd ~
git clone https://github.com/echjansen/pure-emacs ~/.emacs.d

Compiling pure-emacs

This Emacs configuration focuses on fast startup and execution times. This can be achieved using the provided native compilation introduced in Emacs 29. Unlike many other configurations pure-emacs utilities the built-in package manager package.el to download external packages. However, to maintain fast startup times Emacs features such as package.el and use-package are only loaded during compile time (make emacs) but not during run time. See more on this topic in Fast start-up time

To run this pure-emacs configuration, the user must compile it after configuration modifications are made, with:

cd ~/.emacs.d
# Option 1 : Download packages and compile the configuration
make install
# Option 2 : Clean the compiled files to run ~uncompiled~ (slower)
make emacs
# Option 3 : Report on package load time
make report

Configure the Common File

This configuration works out of the box, however a few variables used with Emacs should be personalized. These parameters are found in the pure-common.el file and should be visited before running Emacs for the first time.

(defconst pure-dir-emacs (expand-file-name user-emacs-directory)
  "The path to the emacs.d directory.")

;;;;; Pure Emacs modules directory
(defconst pure-dir-modules (concat user-emacs-directory "modules")
  "The path to the emacs.d modules directory.")

;;;;; Pure Emacs cache diretcory (info shared between Emacs instances
(defconst pure-dir-cache "~/.cache/emacs/"
  "The directory for Pure-Emacs littered files.")

;;;;; Pure Emacs backup directory
(defconst pure-dir-backup (concat pure-dir-cache "backup/")
  "The directory for Pure-Emacs backup files.")

;;;;; Pure Emacs private directory
(defconst pure-dir-private "~/.config/emacs/"
  "The directory for Pure-Emacs backup files.")

;;;;; Pure Emacs notes directory
(defconst pure-dir-notes "~/Projects/pure-notes/"
  "The directory for Pure-Emacs note files directory.")

;;;;; Create directories if non existing
(dolist (dir (list pure-dir-cache
                   pure-dir-backup
                   pure-dir-notes
                   pure-dir-private))
  (unless (file-directory-p dir)
    (make-directory dir t)))

;;;; Files
;;;;; Pure Emacs custom file
;; Some variables may contain ~secret~ information
;; The custom file can store these variables securely by saving them as .gpg
(defconst pure-custom-file "~/.config/emacs/pure-custom.el.gpg"
  "The custom file containing secrets")

Features

Note worthy

Some of the pure-future module introduce interesting features that are found under key-bindings uncommon. Here is a list of key-bindings introduced with pure-Emacs:

C-h Bembark-bindingsShows which-key like mini-buffer with keys available in current mode
C-x C-hShows which-key like mini-buffer with C-x key options available in current mode
C-c C-hShows which-key like mini-buffer with C-c key options available in current mode
C-c .embark-actPrompts user for action on object under cursor (like the right-mouse click)
C-c ;embark-dwimRun the default action on the current target
S-leftwindmove-leftMove focus to buffer to the left
S-rightwindmove-rightMove focus to buffer to the right
S-upwindmove-upMove focus to buffer above
S-downwindmove-downMove focus to buffer below
C-leftwindmove-swap-states-leftSwap current buffer with buffer to the left
C-rightwindmove-swap-states-rightSwap current buffer with buffer to the right
C-upwindmove-swap-states-upSwap current buffer with buffer above
C-downwindmove-swap-states-downSwap current buffer with buffer below
C-,flyspell-goto-next-errorSpell check goto next error
C-.flyspell-auto-correct-wordSpell check auto correct word
TABoutline-cycleIn Emacs-lisp-mode cycle outlines
S-TABoutline-cycle-bufferIn Emacs-lisp-mode cycle outline levels
C-c ieldocIn code, provide Information about function, variable, etc
C-c reglot-renameIn code, rename function, variable project wide
C-c-feglot-format-bufferIn code, format code in current buffer

Explore the built-in features of Emacs

Emacs has been around for a while. It is therefor not unimaginable that something about Emacs is in fact good and functional. New (and long term) Emacs users quite often install external packages, without fully understaning what vanilla Emacs has to offer. This configuration contains a configuration file that only facilitates the built-in features of the Emacs (currentl version 29+). To try pure-emacs, (after installation) execute the following shell command:

cd ~/.emacs.d/
emacs -Q -l early-init.el -l modules/pure-common.el -l modules/pure-emacs.el

Fast start-up time

This particular configuration on TTY starts (currently) in ~0.05 seconds (that is 50 ms) with all packages installed and configured. It is achieved with the built-in provided features:

  • package.el (for package installation)
  • use-package (for package configuration)
  • byte-compile (for removing package.el and use-package from the start-up code)
  • Not using auto-loads

Lets have a closer look at what is required to obtain a fast start-up time.

Emacs start-up reference time

To get an idea of how much time is being added by loading the Emacs configuration one needs to know how much time Emacs takes to load by itself. This can easily be measured on a Linux system with the following command:

For the TTY version on Emacs (0.18 seconds):

time -p emacs -nw -Q -e kill-emacs
time -p emacs -Q -e kill-emacs

For the GUI version on Emacs (0.54 seconds): Notes Some useful Emacs flags are: -Q means to load no configuration (ignore init.el) -e execute a function -l load a file -nw start Emacs in TTY mode (no GUI)

Package.el - package installation and package loading

Emacs comes with a built-in package installation tool called package.el. It takes car of:

  1. installing packages from remote repositories, and once installed.
  2. it takes care of maintaining the load-path requirements of the installed package and finally.
  3. it creates the package-autoloads.el file.
  4. it byte-compiles the package files.

It does more, but these are the important functions.

To use package.el it most be initialized with (package-initialize), so lets find out how much time is required to start the package manager by starting Emacs with the following minimal configuration:

;; Set sources for packages (recipes in this case)
(setq package-archives
    '(("melpa" . "https://melpa.org/packages/")
      ("gnu" . "http://elpa.gnu.org/packages/")
      ("nongnu" . "https://elpa.nongnu.org/nongnu/")))
;; Initialise the package manager
(package-initialize)

Execution for the TTY goes up (0.18 -> 0.38):

time -p emacs -nw -batch -l init.el

That’s a doubling of the load time, or an additional 200 ms to the startup time! And this time becomes longer once more packages have been installed. Although package.el is required for the installation of packages, we can do without during runtime. There are two variables that control the loading of package.el:

;; Whether to make installed packages available when Emacs starts.
;; If non-nil, packages are made available before reading the init
;; file (but after reading the early init file).  This means that if
;; you wish to set this variable, you must do so in the early init
;; file.
(setq package-enable-at-startup nil)

;; Some Emacs versions automatically insers (package-initialize in init.el)
;; Ask package.el to not add (package-initialize) to init.el.
(setq package--init-file-ensured t)

;; Or alternatively commen out (package-initialize) in the init.el file
;;(package-initialize)

Note that without package.el initialized, you can still install packages via M-x ‘package-list-packages’.

Note that without package.el initialized, the path’s to the packages are NOT added to ‘load-path’ and Emacs will NOT be able to locate and load the packages.

One the overcome the load-path issue, is to to manually code the load path of each package to the init.el, like this:

(setq package-enable-at-startup nil)
(setq package--init-file-ensured t)
(add-to-list 'load-path (concat package-user-dir "magit-20240101.1234"))

And this works perfectly, as Emacs looks trough all folders listed in ‘load-path’.

A simpler way is to automate the addition of the packages to ‘load-path with the code below, which is ONLY executed during compile time, and so the load-path is ‘hard-coded’ in the byte compiled file (hence the importance of byte compiling via the make command):

;; Traverse the installed packages and add their paths to load-path.
(mapc #'(lambda (add) (add-to-list 'load-path add))
      (eval-when-compile
        ;; (require 'package)
        (package-initialize)
        (let ((package-user-dir-real (file-truename package-user-dir)))
          ;; The reverse is necessary, because outside we mapc
          ;; add-to-list element-by-element, which reverses.
          (nreverse (apply #'nconc
                           ;; Only keep package.el provided loadpaths.
                           (mapcar #'(lambda (path)
                                       (if (string-prefix-p package-user-dir-real path)
                                           (list path)
                                         nil))
                                   load-path))))))

Use-package.el - package configuration

Use-package is the excellent macro written by John Wiegley. It became part of core Emacs from version 29. The purpose of use-package is to put all configuration for a certain package tightly together within one expression. When configured correctly it also allows for faster start-up times by applying lazy loading - loading of a package only when it is required.

One additional - lesser known - fact is that use-package is not required to be loaded during run time when byte-compiled, as all the use-package expressions expand to standard lisp code (with some minimal overhead)!

All that is required for this to happen, is the following statement early in the configuration:

(eval-when-compile
  (require 'use-package))

Email client with mu4e, mbsync and msmtp

A seperate module is availale to include email in your Emacs configuration. It is disabled by default, as not to throw errors during the Emacs startup process, as the email configuration requires multiple personalisations before it can function correctly. Below is an outline of what need to be configured i order for email to work. Note: pure-dotfiles includes an install script that performs all of the necessary operations.

Email secrets

Pure-email assumes that all secrets regarding your email configuration are stored in a Gnu pass password store. The following is an example of a multi-line email account configuration.

<password>
email: <email>
name: <name>
imap-server:<imap.server.com>
imap-port:<port no>
imap-ssl:IMAPS

Pure-email uses instructions as below to obtain the data from the password store:

(user-full-name  . ,(auth-source-pass-get "name" "email/user"))

Synchronizing mailbox

Mailbox synchronization (receiving email) is performed by an external application, not mu4e (or mu) There are two candidates for Synchronizing (receiving) mailboxes: mbsync which is part of the isync project, and Offlineimap. pure-email doesn’t care which utility is being used, as it solely functions on the offline mailbox and doesn’t perform the synchronization directly.

Alter the variable mu4e-get-mail-command if not using mbsync for mailbox synchronization.

(mu4e-get-mail-command "mbsync -a")

Assuming that mbsync is being used, a mbsynrc configuration file is required in the users home folder. The following is an example for outlook.com (or office365.com) Replace user with your email account identifier. Also, the block below can be duplicated multiple times for multiple email accounts

#===============================================================================
# Mailbox synchronisation with echjansen@outlook.com
#===============================================================================
IMAPAccount user
Host outlook.office365.com
Port 993
User user@outlook.com
PassCmd "pass email/user"
SSLType IMAPS
AuthMusers *
CertificateFile /etc/ssl/certs/ca-certificates.crt

IMAPStore user-remote
Account user

MaildirStore user-local
SubFolders Verbatim
Path ~/.mail/user/
Inbox ~/.mail/user/Inbox
Trash Deleted

Channel user
Far :user-remote:
Near :user-local:
Patterns *
SyncState *
Create Both
Expunge Both
CopyArrivalDate yes
Sync All

Sending email

Like mailbox synchronization, sending emails is also performed by an external application. The common application is msmtp. msmtp requires a .msmtprc configuration file to be located in the users home folder.

The following is an example for outlook.com (or office365.com)

# Set default values for all following accounts.
defaults
auth           on
tls            on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile        ~/.msmtp.log

# echjansen@outlook.com
account        user
host           smtp-mail.outlook.com
port           587
from           user@outlook.com
user           user@outlook.com
passwordeval   "pass email/user"
from_full_name "user full name"

The following configuration ensures that the data located in the .msmtprc is being used.

(message-send-mail-function 'message-send-mail-with-sendmail)

About

An Emacs configuration focussing on in-build features and the need for speed (fast start-up time).

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published