Skip to content

davidwuchn/minimal-emacs.d

 
 

Repository files navigation

minimal-emacs.d - A Customizable Emacs init.el and early-init.el for Better Defaults and Optimized Startup

Build Status License: GPL v3

Introduction

The minimal-emacs.d project is a fast and lightweight minimal Emacs starter kit (init.el and early-init.el) that gives you full control over your configuration. It provides better defaults, an optimized startup, and a clean foundation for building your own vanilla Emacs setup.

Each setting in minimal-emacs.d is carefully chosen to answer this question: does it provide a better default that modernizes Emacs while keeping it lightweight, fast and stable?

In just a few minutes of applying what's in this README.md file, you will have a fully functional, high-performance Emacs configuration ready for work. You will bypass hours of configuration and the heavy overhead of frameworks like Doom or Spacemacs, gaining access to optimized garbage collection, sensible defaults, and a fast startup.

If this helps your workflow, please show your support by ⭐ starring minimal-emacs.d on GitHub to help more Emacs users discover its benefits.

Ready to start? Install minimal-emacs.d

Building the minimal-emacs.d init.el and early-init.el was the result of extensive research and testing to fine-tune the best parameters and optimizations for an Emacs configuration. (More information about the minimal-emacs.d features can be found here: Features.)

Looking for the ideal starter kit to customize Emacs?

The minimal-emacs.d project is:

  • Minimal yet effective: A solid starting point.
  • Better defaults: Improved settings for usability, UI, garbage collection, and built-in packages. (Emacs comes with many well-designed defaults, but it also retains some less-than-ideal settings, often due to historical constraints or legacy compatibility.)
  • 0 packages loaded / No forced modes: Unlike other frameworks, minimal-emacs.d does not impose modes or require packages. You have full control over which global or minor modes to enable.
  • Customizable foundation: Designed to be extended, not replaced. This README offers extensive recommendations for customizing your configuration.

The minimal-emacs.d project includes two initialization files:

  • early-init.el: Loaded early in the Emacs startup process, before the graphical interface is initialized. Introduced in Emacs 27, this file configures settings that influence startup performance and GUI behavior prior to package loading.
  • init.el: Loaded after the graphical interface is initialized. This file contains user customizations, including variable settings, package loading, mode configurations, and keybindings.

Skip to: Install minimal-emacs.d

Excluding empty lines, comments, and docstrings, the minimal-emacs.d configuration is approximately 450 lines long. It does not introduce additional functionality beyond offering improved default settings. You retain full control over which packages to install and which modes to enable.

(The theme shown in the screenshot above is ef-melissa-light, which is part of the ef-themes collection available on MELPA.) (The theme shown in the screenshot above is doom-one, which is part of the doom-themes collection available on MELPA.) (The theme shown in the screenshot above is the tomorrow-night-deepblue-theme.el, available on MELPA.)

Startup Performance

The author uses minimal-emacs.d as his early-init.el and init.el, alongside 146 packages (See the packages that the author is using here). Yet, thanks to its efficient design, Emacs still starts in just 0.22 seconds:

Startup speed depends on hardware and disk speed. For consistent comparisons, test on the same computer and Emacs version. While startup time is significant, factors like native compilation are also important for long-term performance.

User Testimonials

  • gnudoc on Reddit: "That's a great learning resource. Thank you for your work on it and for sharing it!"
  • dewyke on Reddit: "Lots of good stuff in there, even for people who already have established ways of organising their configs."
  • JamesBrickley (Shout out to this starter-kit: Minimal-Emacs ) appreciates that minimal-emacs.d provides an optimized early-init.el and init.el for fast startup times and sensible default settings. He highlights that the project includes all the essential configurations needed for a well-tuned Emacs setup, eliminating the need to sift through conflicting advice on topics like garbage collection optimization. While he has encountered similar settings before, he also discovered new optimizations he had not seen elsewhere.
  • Brandon Schneider (skarekrow): "...the minimal-emacs project is incredible. I love how documented it is as a beginner to learn from. Thank you for all the effort you've put into that and the other packages you maintain. It's a huge boon to new users."
  • Leading_Ad6415 commented on Reddit that after switching to minimal-emacs.d, their configuration execution time decreased from 3 seconds to just 1 second by simply replacing their init.el and early-init.el files with those from the project.
  • Another user commented on Reddit, highlighting how a minimal-emacs.d significantly enhanced their Emacs performance. They reported substantial startup time reductions on both their main machine (from ~2.25 to ~0.95 seconds) and an older laptop (from ~2.95 to ~1.27 seconds) while also experiencing a generally snappier performance within Emacs. The user expressed gratitude for the project, calling it fantastic.
  • Cyneox commented on Reddit, expressing gratitude for the resource and sharing their experience. They mentioned it was their fourth attempt to set up a vanilla configuration and highlighted that they had been using the repository as a foundation for their customizations over the past few days. They appreciated the absence of unexplained behavior and the clear instructions on where to place files. The user reported successful testing on both Linux and macOS, noting that everything functioned smoothly, including in the terminal.
  • Sebagabones on GitHub: "...let me say that I am loving minimal-emacs.d, it has been brilliant so far! :)"
  • Mlepnos1984 on Reddit: "I give you an A+ on documentation, the readme is great!"
  • rrajath on Reddit has been using the minimal-emacs.d config for the past several months and loves it. His previous setup used to take around 4 seconds to load, but with minimal-emacs.d, it now loads in just 1 second.
  • LionyxML on Reddit considers that minimal-emacs.d contains one of the best README files he has ever read. The author of minimal-emacs.d found his comment encouraging. Reading this README.md is highly recommended for anyone looking to start customizing their minimal-emacs.d configuration.
  • cyneox on Reddit: "Still using it and loving it! Thanks for the regular updates."
  • panchoh on GitHub: "...thank you, @jamescherti! Keep up the fantastic work you are doing!"
  • xzway on Reddit: "The minimal-emacs.d configuration is very well-designed and non-intrusive. I'm also using it to refactor my configuration."
  • jeenajeena on Reddit: "Thank you. Plenty of inspiring settings. Worth to be read line by line."
  • uutangohotel on Reddit: "I get a lot out of minimal-emacs.d — thank you! I use stow to manage my dotfiles in a git repo. I created a submodule in one dir for minimal-emacs.d and another for my “overrides”, e.g. post-init.el. Easy and works great."
  • sunng on Reddit: "Nice work! I just created a nix flake to using it on my dev servers"
  • zackattackz287 on Reddit: "Congrats and thank you (and the community around minimal.d) for your work! I've been using it for quite a while now and I've not ever had any breakages when merging changes from main..."
  • utility on Reddit: "Excellent. I use this and I'm very happy with it!"

Please share your configuration. It could serve as inspiration for other users.

Table of Contents

Install minimal-emacs.d

  • Important: Ensure that the ~/.emacs and ~/.emacs.el files do not exist. These files cause Emacs to ignore ~/.emacs.d/init.el. This behavior is due to the way Emacs searches for initialization files (more information). Simply delete the ~/.emacs and ~/.emacs.el files avoid this issue.
  • Debug: If a package or any other functionality is not working as expected, start Emacs with emacs --debug-init to enable debug mode and obtain the backtrace.
  • Prerequisite: git

Install minimal-emacs.d into ~/.emacs.d

Execute the following command install this repository into ~/.emacs.d:

git clone --depth 1 https://github.com/jamescherti/minimal-emacs.d ~/.emacs.d

Alternative: Install minimal-emacs.d into ~/.minimal-emacs.d

To install minimal-emacs.d in a non-default directory, use the --init-directory Emacs option to specify your desired configuration path. For example, to install minimal-emacs.d in ~/.minimal-emacs.d/, follow these steps:

  1. Clone the repository into ~/.minimal-emacs.d/ using:

    git clone --depth 1 https://github.com/jamescherti/minimal-emacs.d ~/.minimal-emacs.d
    
  2. Start Emacs with the new configuration directory:

    emacs --init-directory ~/.minimal-emacs.d/
    

Update minimal-emacs.d

To keep your Emacs configuration up to date, you can pull the latest changes from the repository. Run the following command in your terminal:

git -C ~/.emacs.d pull

Customizations: Never modify init.el and early-init.el. Modify these instead...

The init.el and early-init.el files should never be modified directly because they are intended to be managed by Git during an update.

The minimal-emacs.d init files support additional customization files that are loaded at different stages of the Emacs startup process. These files allow you to further customize the initialization sequence:

  • ~/.emacs.d/pre-init.el: This file is loaded before init.el. Use it to set up variables or configurations that need to be available early in the initialization process but after early-init.el.

  • ~/.emacs.d/post-init.el: This file is loaded after init.el. It is useful for additional configurations or package setups that depend on the configurations in init.el.

  • ~/.emacs.d/pre-early-init.el: This file is loaded before early-init.el. Use it for configurations that need to be set even earlier in the startup sequence, typically affecting the initial setup of the Emacs environment.

  • ~/.emacs.d/post-early-init.el: This file is loaded after early-init.el but before init.el. It is useful for setting up configurations that depend on the early initialization but need to be set before the main initialization begins.

Always begin your pre-init.el, post-init.el, post-early-init.el, and pre-early-init.el files with the following header to prevent them from being byte-compiled and to activate lexical binding:

;;; FILENAME.el --- DESCRIPTION -*- no-byte-compile: t; lexical-binding: t; -*-

Replace FILENAME.el with the actual name and DESCRIPTION with a brief description of its purpose.

(Only if you know what you're doing: Removing no-byte-compile: t; from your init files allows Emacs to compile them, improving load and execution speed. However, if you do so, you may need to add required dependencies. For example, if you're using use-package, add (require 'use-package) at the top of post-init.el to ensure all necessary use-package variables and functions are loaded. The only init file where no-byte-compile: t should never be removed is early-init.el, because if this file is compiled, Emacs may load an outdated compiled version.)

Important: The examples in this README reference pre/post init files in the ~/.emacs.d/ directory, but the files pre-early-init.el, post-early-init.el, pre-init.el, and post-init.el should be placed in the same directory as init.el and early-init.el, regardless of their location.

Recommendations

Always defer package loading

All use-package declarations in this README use deferred loading, so you can safely copy and paste them into your configuration.

To ensure your configuration remains fast and responsive, always defer package loading so that libraries are initialized only when they are needed. The use-package macro makes this effortless; simply adding :commands or :bind to your package declarations automatically configures them for deferred loading.

Customizations: UI (File: pre-early-init.el)

How to enable the menu-bar, the tool-bar, dialogs, the contextual menu, and tooltips?

Note: Enabling the tool-bar or menu-bar may slightly increase your startup time.

To customize your Emacs setup to include various user interface elements, you can use the following settings in your ~/.emacs.d/pre-early-init.el:

(setq minimal-emacs-ui-features '(context-menu tool-bar menu-bar dialogs tooltips))

These settings control the visibility of dialogs, context menus, toolbars, menu bars, and tooltips.

Reducing clutter in ~/.emacs.d by redirecting files to ~/.emacs.d/var/

Emacs, by default, stores various configuration files, caches, backups, and other data in the ~/.emacs.d directory. Over time, this directory can become cluttered with numerous files, making it difficult to manage and maintain.

A common solution to this issue is installing the no-littering package; however, this package is not essential.

An alternative lightweight approach is to simply change the default ~/.emacs.d directory to ~/.emacs.d/var/, which will contain all the files that Emacs typically stores in the base directory. This can be accomplished by adding the following code to ~/.emacs.d/pre-early-init.el:

;;; Reducing clutter in ~/.emacs.d by redirecting files to ~/.emacs.d/var/
;; NOTE: This must be placed in 'pre-early-init.el'.
(setq user-emacs-directory (expand-file-name "var/" minimal-emacs-user-directory))
(setq package-user-dir (expand-file-name "elpa" user-emacs-directory))

IMPORTANT: The code above should be added to ~/.emacs.d/pre-early-init.el, not the other files, as it modifies the behavior of all subsequent init files.

Customizations: Packages (File: post-init.el)

This README.md offers guidance on installing optional external packages. While Emacs and minimal-emacs.d are fully functional without them, the recommended packages can enhance your experience and introduce additional features, which is why they are suggested.

Optimization: Native Compilation

Native compilation enhances Emacs performance by converting Elisp code into native machine code, resulting in faster execution and improved responsiveness.

  1. To check if native compilation is enabled, evaluate:

    (native-comp-available-p)

    (A non-nil result indicates that native compilation is available.)

  2. Ensure all libraries are byte-compiled and native-compiled using compile-angel.el. To install compile-angel, add the following code to the ~/.emacs.d/post-init.el file:

;; Native compilation enhances Emacs performance by converting Elisp code into
;; native machine code, resulting in faster execution and improved
;; responsiveness.
;;
;; Ensure adding the following compile-angel code at the very beginning
;; of your `~/.emacs.d/post-init.el` file, before all other packages.
(use-package compile-angel
  :demand t
  :config
  ;; The following disables compilation of packages during installation;
  ;; compile-angel will handle it.
  (setq package-native-compile nil)

  ;; Set `compile-angel-verbose' to nil to disable compile-angel messages.
  ;; (When set to nil, compile-angel won't show which file is being compiled.)
  (setq compile-angel-verbose t)

  ;; The following directive prevents compile-angel from compiling your init
  ;; files. If you choose to remove this push to `compile-angel-excluded-files'
  ;; and compile your pre/post-init files, ensure you understand the
  ;; implications and thoroughly test your code. For example, if you're using
  ;; the `use-package' macro, you'll need to explicitly add:
  ;; (eval-when-compile (require 'use-package))
  ;; at the top of your init file.
  (push "/init.el" compile-angel-excluded-files)
  (push "/early-init.el" compile-angel-excluded-files)
  (push "/pre-init.el" compile-angel-excluded-files)
  (push "/post-init.el" compile-angel-excluded-files)
  (push "/pre-early-init.el" compile-angel-excluded-files)
  (push "/post-early-init.el" compile-angel-excluded-files)

  ;; A local mode that compiles .el files whenever the user saves them.
  ;; (add-hook 'emacs-lisp-mode-hook #'compile-angel-on-save-local-mode)

  ;; A global mode that compiles .el files prior to loading them via `load' or
  ;; `require'. Additionally, it compiles all packages that were loaded before
  ;; the mode `compile-angel-on-load-mode' was activated.
  (compile-angel-on-load-mode 1))

Environment Variable Synchronization (Essential for macOS users)

On macOS, GUI applications (launched from the Finder, Dock, or Spotlight) do not inherit the user's shell environment variables by default. This often causes errors where Emacs cannot find external tools like git, grep, pip, or language servers (LSP), even if they work perfectly in your terminal.

To fix this, add exec-path-from-shell to ~/.emacs.d/post-init.el:

(use-package exec-path-from-shell
  :if (and (or (display-graphic-p) (daemonp))
           (eq system-type 'darwin)) ; macOS only
  :demand t
  :functions exec-path-from-shell-initialize
  :config
  (dolist (var '("TMPDIR"
                 "SSH_AUTH_SOCK" "SSH_AGENT_PID"
                 "GPG_AGENT_INFO"
                 ;; "FZF_DEFAULT_COMMAND" "FZF_DEFAULT_OPTS" ; fzf
                 ;; "VIRTUAL_ENV" ; Python
                 ;; "GOPATH" "GOROOT" "GOBIN" ; Go
                 ;; "CARGO_HOME" "RUSTUP_HOME" ; Rust
                 ;; "NVM_DIR" "NODE_PATH" ; Node/JS
                 "LANG" "LC_CTYPE"))
    (add-to-list 'exec-path-from-shell-variables var))
  ;; Initialize
  (exec-path-from-shell-initialize))

File Management & History: recentf, savehist, saveplace, and auto-revert?

The recentf, savehist, saveplace, and auto-revert built-in packages are already configured by minimal-emacs.d. All you need to do is activate them by adding the following to ~/.emacs.d/post-init.el:

;; Auto-revert in Emacs is a feature that automatically updates the
;; contents of a buffer to reflect changes made to the underlying file
;; on disk.
(use-package autorevert
  :ensure nil
  :commands (auto-revert-mode global-auto-revert-mode)
  :hook
  (after-init . global-auto-revert-mode)
  :init
  ;; (setq auto-revert-verbose t)
  (setq auto-revert-interval 3)
  (setq auto-revert-remote-files nil)
  (setq auto-revert-use-notify t)
  (setq auto-revert-avoid-polling nil))

;; Recentf is an Emacs package that maintains a list of recently
;; accessed files, making it easier to reopen files you have worked on
;; recently.
(use-package recentf
  :ensure nil
  :commands (recentf-mode recentf-cleanup)
  :hook
  (after-init . recentf-mode)

  :init
  (setq recentf-auto-cleanup (if (daemonp) 300 'never))
  (setq recentf-exclude
        (list "\\.tar$" "\\.tbz2$" "\\.tbz$" "\\.tgz$" "\\.bz2$"
              "\\.bz$" "\\.gz$" "\\.gzip$" "\\.xz$" "\\.zip$"
              "\\.7z$" "\\.rar$"
              "COMMIT_EDITMSG\\'"
              "\\.\\(?:gz\\|gif\\|svg\\|png\\|jpe?g\\|bmp\\|xpm\\)$"
              "-autoloads\\.el$" "autoload\\.el$"))

  :config
  ;; A cleanup depth of -90 ensures that `recentf-cleanup' runs before
  ;; `recentf-save-list', allowing stale entries to be removed before the list
  ;; is saved by `recentf-save-list', which is automatically added to
  ;; `kill-emacs-hook' by `recentf-mode'.
  (add-hook 'kill-emacs-hook #'recentf-cleanup -90))

;; savehist is an Emacs feature that preserves the minibuffer history between
;; sessions. It saves the history of inputs in the minibuffer, such as commands,
;; search strings, and other prompts, to a file. This allows users to retain
;; their minibuffer history across Emacs restarts.
(use-package savehist
  :ensure nil
  :commands (savehist-mode savehist-save)
  :hook
  (after-init . savehist-mode)
  :init
  (setq history-length 300)
  (setq savehist-autosave-interval 600))

;; save-place-mode enables Emacs to remember the last location within a file
;; upon reopening. This feature is particularly beneficial for resuming work at
;; the precise point where you previously left off.
(use-package saveplace
  :ensure nil
  :commands (save-place-mode save-place-local-mode)
  :hook
  (after-init . save-place-mode)
  :init
  (setq save-place-limit 400))

Safety: Auto-Save

auto-save-mode (Prevent data loss in case of crashes)

Enabling auto-save-mode mitigates the risk of data loss in the event of a crash. Auto-saved data can be recovered using the recover-file or recover-session functions.

To enable autosave, add the following to ~/.emacs.d/post-init.el:

;; Enable `auto-save-mode' to prevent data loss. Use `recover-file' or
;; `recover-session' to restore unsaved changes.
(setq auto-save-default t)

;; Trigger an auto-save after 300 keystrokes
(setq auto-save-interval 300)

;; Trigger an auto-save 30 seconds of idle time.
(setq auto-save-timeout 30)

auto-save-visited-mode (Save file buffers after a few seconds of inactivity)

When auto-save-visited-mode is enabled, Emacs will auto-save file-visiting buffers after a certain amount of idle time if the user forgets to save it with save-buffer or C-x s for example.

This is different from auto-save-mode: auto-save-mode periodically saves all modified buffers, creating backup files, including those not associated with a file, while auto-save-visited-mode only saves file-visiting buffers after a period of idle time, directly saving to the file itself without creating backup files.

;; When auto-save-visited-mode is enabled, Emacs will auto-save file-visiting
;; buffers after a certain amount of idle time if the user forgets to save it
;; with save-buffer or C-x s for example.
;;
;; This is different from auto-save-mode: auto-save-mode periodically saves
;; all modified buffers, creating backup files, including those not associated
;; with a file, while auto-save-visited-mode only saves file-visiting buffers
;; after a period of idle time, directly saving to the file itself without
;; creating backup files.
(setq auto-save-visited-interval 5)   ; Save after 5 seconds if inactivity
(auto-save-visited-mode 1)

Completion System (Corfu, Vertico, Consult)

Corfu enhances in-buffer completion by displaying a compact popup with current candidates, positioned either below or above the point. Candidates can be selected by navigating up or down.

Cape, or Completion At Point Extensions, extends the capabilities of in-buffer completion. It integrates with Corfu or the default completion UI, by providing additional backends through completion-at-point-functions.

To configure corfu and cape, add the following to ~/.emacs.d/post-init.el:

;; Corfu enhances in-buffer completion by displaying a compact popup with
;; current candidates, positioned either below or above the point. Candidates
;; can be selected by navigating up or down.
(use-package corfu
  :commands (corfu-mode global-corfu-mode)

  :hook ((prog-mode . corfu-mode)
         (shell-mode . corfu-mode)
         (eshell-mode . corfu-mode))

  :custom
  ;; Hide commands in M-x which do not apply to the current mode.
  (read-extended-command-predicate #'command-completion-default-include-p)
  ;; Disable Ispell completion function. As an alternative try `cape-dict'.
  (text-mode-ispell-word-completion nil)
  (tab-always-indent 'complete)

  ;; Enable Corfu
  :config
  (global-corfu-mode))

;; Cape, or Completion At Point Extensions, extends the capabilities of
;; in-buffer completion. It integrates with Corfu or the default completion UI,
;; by providing additional backends through completion-at-point-functions.
(use-package cape
  :commands (cape-dabbrev cape-file cape-elisp-block)
  :bind ("C-c p" . cape-prefix-map)
  :init
  ;; Add to the global default value of `completion-at-point-functions' which is
  ;; used by `completion-at-point'.
  (add-hook 'completion-at-point-functions #'cape-dabbrev)
  (add-hook 'completion-at-point-functions #'cape-file)
  (add-hook 'completion-at-point-functions #'cape-elisp-block))

Vertico, Consult, Marginalia, and Embark

Vertico, Consult, and Embark collectively enhance Emacs' completion and navigation capabilities.

Vertico provides a vertical completion interface, making it easier to navigate and select from completion candidates (e.g., when M-x is pressed).

Consult offers a suite of commands for efficient searching, previewing, and interacting with buffers, file contents, and more, improving various tasks.

Embark integrates with these tools to provide context-sensitive actions and quick access to commands based on the current selection, further improving user efficiency and workflow within Emacs. Together, they create a cohesive and powerful environment for managing completions and interactions.

Add the following to ~/.emacs.d/post-init.el to set up Vertico, Consult, and Embark:

;; Vertico provides a vertical completion interface, making it easier to
;; navigate and select from completion candidates (e.g., when `M-x` is pressed).
(use-package vertico
  ;; (Note: It is recommended to also enable the savehist package.)
  :config
  (vertico-mode))

;; Vertico leverages Orderless' flexible matching capabilities, allowing users
;; to input multiple patterns separated by spaces, which Orderless then
;; matches in any order against the candidates.
(use-package orderless
  :custom
  (completion-styles '(orderless basic))
  (completion-category-defaults nil)
  (completion-category-overrides '((file (styles partial-completion)))))

;; Marginalia allows Embark to offer you preconfigured actions in more contexts.
;; In addition to that, Marginalia also enhances Vertico by adding rich
;; annotations to the completion candidates displayed in Vertico's interface.
(use-package marginalia
  :commands (marginalia-mode marginalia-cycle)
  :hook (after-init . marginalia-mode))

;; Embark integrates with Consult and Vertico to provide context-sensitive
;; actions and quick access to commands based on the current selection, further
;; improving user efficiency and workflow within Emacs. Together, they create a
;; cohesive and powerful environment for managing completions and interactions.
(use-package embark
  ;; Embark is an Emacs package that acts like a context menu, allowing
  ;; users to perform context-sensitive actions on selected items
  ;; directly from the completion interface.
  :commands (embark-act
             embark-dwim
             embark-export
             embark-collect
             embark-bindings
             embark-prefix-help-command)
  :bind
  (("C-." . embark-act)         ;; pick some comfortable binding
   ("C-;" . embark-dwim)        ;; good alternative: M-.
   ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'

  :init
  (setq prefix-help-command #'embark-prefix-help-command)

  :config
  ;; Hide the mode line of the Embark live/completions buffers
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))

(use-package embark-consult
  :hook
  (embark-collect-mode . consult-preview-at-point-mode))

;; Consult offers a suite of commands for efficient searching, previewing, and
;; interacting with buffers, file contents, and more, improving various tasks.
(use-package consult
  :bind (;; C-c bindings in `mode-specific-map'
         ("C-c M-x" . consult-mode-command)
         ("C-c h" . consult-history)
         ("C-c k" . consult-kmacro)
         ("C-c m" . consult-man)
         ("C-c i" . consult-info)
         ([remap Info-search] . consult-info)
         ;; C-x bindings in `ctl-x-map'
         ("C-x M-:" . consult-complex-command)
         ("C-x b" . consult-buffer)
         ("C-x 4 b" . consult-buffer-other-window)
         ("C-x 5 b" . consult-buffer-other-frame)
         ("C-x t b" . consult-buffer-other-tab)
         ("C-x r b" . consult-bookmark)
         ("C-x p b" . consult-project-buffer)
         ;; Custom M-# bindings for fast register access
         ("M-#" . consult-register-load)
         ("M-'" . consult-register-store)
         ("C-M-#" . consult-register)
         ;; Other custom bindings
         ("M-y" . consult-yank-pop)
         ;; M-g bindings in `goto-map'
         ("M-g e" . consult-compile-error)
         ("M-g f" . consult-flymake)
         ("M-g g" . consult-goto-line)
         ("M-g M-g" . consult-goto-line)
         ("M-g o" . consult-outline)
         ("M-g m" . consult-mark)
         ("M-g k" . consult-global-mark)
         ("M-g i" . consult-imenu)
         ("M-g I" . consult-imenu-multi)
         ;; M-s bindings in `search-map'
         ("M-s d" . consult-find)
         ("M-s c" . consult-locate)
         ("M-s g" . consult-grep)
         ("M-s G" . consult-git-grep)
         ("M-s r" . consult-ripgrep)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ("M-s k" . consult-keep-lines)
         ("M-s u" . consult-focus-lines)
         ;; Isearch integration
         ("M-s e" . consult-isearch-history)
         :map isearch-mode-map
         ("M-e" . consult-isearch-history)
         ("M-s e" . consult-isearch-history)
         ("M-s l" . consult-line)
         ("M-s L" . consult-line-multi)
         ;; Minibuffer history
         :map minibuffer-local-map
         ("M-s" . consult-history)
         ("M-r" . consult-history))

  ;; Enable automatic preview at point in the *Completions* buffer.
  :hook (completion-list-mode . consult-preview-at-point-mode)

  :init
  ;; Optionally configure the register formatting. This improves the register
  (setq register-preview-delay 0.5
        register-preview-function #'consult-register-format)

  ;; Optionally tweak the register preview window.
  (advice-add #'register-preview :override #'consult-register-window)

  ;; Use Consult to select xref locations with preview
  (setq xref-show-xrefs-function #'consult-xref
        xref-show-definitions-function #'consult-xref)

  ;; Aggressive asynchronous that yield instantaneous results. (suitable for
  ;; high-performance systems.) Note: Minad, the author of Consult, does not
  ;; recommend aggressive values.
  ;; Read: https://github.com/minad/consult/discussions/951
  ;;
  ;; However, the author of minimal-emacs.d uses these parameters to achieve
  ;; immediate feedback from Consult.
  ;; (setq consult-async-input-debounce 0.02
  ;;       consult-async-input-throttle 0.05
  ;;       consult-async-refresh-delay 0.02)

  :config
  (consult-customize
   consult-theme :preview-key '(:debounce 0.2 any)
   consult-ripgrep consult-git-grep consult-grep
   consult-bookmark consult-recent-file consult-xref
   consult-source-bookmark consult-source-file-register
   consult-source-recent-file consult-source-project-recent-file
   ;; :preview-key "M-."
   :preview-key '(:debounce 0.4 any))
  (setq consult-narrow-key "<"))

Enhancing undo/redo

The undo-fu package is a lightweight wrapper around Emacs' built-in undo system, providing more convenient undo/redo functionality while preserving access to the full undo history. The undo-fu-session package complements undo-fu by enabling the saving and restoration of undo history across Emacs sessions, even after restarting.

The default undo system in Emacs has two main issues that undo-fu fixes:

  1. Redo requires two steps: To redo an action after undoing, you need to press a key twice, which can be annoying and inefficient.
  2. Accidental over-redo: When redoing, it's easy to go too far back, past the point where you started the undo, which makes it hard to return to the exact state you wanted to restore.

To install and configure these packages, add the following to ~/.emacs.d/post-init.el:

;; The undo-fu package is a lightweight wrapper around Emacs' built-in undo
;; system, providing more convenient undo/redo functionality.
(use-package undo-fu
  :commands (undo-fu-only-undo
             undo-fu-only-redo
             undo-fu-only-redo-all
             undo-fu-disable-checkpoint)
  :config
  (global-unset-key (kbd "C-z"))
  (global-set-key (kbd "C-z") 'undo-fu-only-undo)
  (global-set-key (kbd "C-S-z") 'undo-fu-only-redo))

;; The undo-fu-session package complements undo-fu by enabling the saving
;; and restoration of undo history across Emacs sessions, even after restarting.
(use-package undo-fu-session
  :commands undo-fu-session-global-mode
  :hook (after-init . undo-fu-session-global-mode))

Changing the default theme

For instance, to switch to a another theme than the default one, add the following to the ~/.emacs.d/post-init.el file:

(let ((inhibit-redisplay t))
  ;; Disable all active themes
  (mapc #'disable-theme custom-enabled-themes)
  ;; Load the built-in theme
  (load-theme 'modus-operandi t))

(If you prefer dark themes, replace modus-operandi with modus-vivendi.)

Emacs includes several built-in themes that you can use without installing additional packages:

  • tango-dark (Face colors using the Tango palette. Dark background.)
  • tango (Face colors using the Tango palette. Light background.)
  • modus-operandi
  • modus-operandi-deuteranopia
  • modus-operandi-tinted
  • modus-operandi-tritanopia
  • modus-vivendi
  • modus-vivendi-deuteranopia
  • modus-vivendi-tinted
  • modus-vivendi-tritanopia
  • tsdh-dark (A dark theme used and created by Tassilo Horn.)
  • tsdh-light (A light Emacs theme.)
  • adwaita (Face colors similar to the default theme of Gnome 3 / Adwaita.)
  • deeper-blue (Face colors using a deep blue background.)
  • dichromacy (Face colors suitable for red/green color-blind users.)
  • leuven-dark (Face colors with a dark background.)
  • leuven (Face colors with a light background.)
  • light-blue (Face colors utilizing a light blue background.)
  • manoj-dark (Very high contrast faces with a black background.)
  • misterioso (Predominantly blue/cyan faces on a dark cyan background.)
  • wheatgrass (High-contrast green/blue/brown faces on a black background.)
  • whiteboard (Face colors similar to markers on a whiteboard.)
  • wombat (Medium-contrast faces with a dark gray background.)

(To experiment with different themes, use M-x customize-themes.)

If you're interested in exploring third-party Emacs themes, consider the following:

  • ef-themes (available on MELPA): A collection of light and dark themes for GNU Emacs, designed to offer colorful yet highly legible options. They are aimed at users seeking something with more visual flair compared to the more minimalist modus-themes.
  • doom-themes (available on MELPA): An extensive collection of high-quality, visually appealing themes for Emacs, designed to offer a sleek and modern aesthetic, while drawing inspiration from popular community themes.
  • tomorrow-night-deepblue-theme (available on MELPA): A beautiful deep blue variant of the Tomorrow Night theme, which is renowned for its elegant color palette. It features a deep blue background color that creates a calming atmosphere. This theme is a great choice for those who miss the blue themes that were trendy a few years ago. (The theme was inspired by classic text editors such as QuickBASIC, RHIDE, and Turbo Pascal, as well as tools such as Midnight Commander.)

Configuring Vim keybindings using Evil?

Configuring Vim keybindings in Emacs can greatly enhance your editing efficiency if you are accustomed to Vim's modal editing style. Add the following to ~/.emacs.d/post-init.el to set up Evil mode:

;; Uncomment the following if you are using undo-fu
;; (setq evil-undo-system 'undo-fu)

;; Vim emulation
(use-package evil
  :commands (evil-mode evil-define-key)
  :hook (after-init . evil-mode)

  :init
  ;; It has to be defined before evil
  (setq evil-want-integration t)
  (setq evil-want-keybinding nil)

  :custom
  ;; Make :s in visual mode operate only on the actual visual selection
  ;; (character or block), instead of the full lines covered by the selection
  (evil-ex-visual-char-range t)
  ;; Use Vim-style regular expressions in search and substitute commands,
  ;; allowing features like \v (very magic), \zs, and \ze for precise matches
  (evil-ex-search-vim-style-regexp t)
  ;; Enable automatic horizontal split below
  (evil-split-window-below t)
  ;; Enable automatic vertical split to the right
  (evil-vsplit-window-right t)
  ;; Disable echoing Evil state to avoid replacing eldoc
  (evil-echo-state nil)
  ;; Do not move cursor back when exiting insert state
  (evil-move-cursor-back nil)
  ;; Make `v$` exclude the final newline
  (evil-v$-excludes-newline t)
  ;; Allow C-h to delete in insert state
  (evil-want-C-h-delete t)
  ;; Enable C-u to delete back to indentation in insert state
  (evil-want-C-u-delete t)
  ;; Enable fine-grained undo behavior
  (evil-want-fine-undo t)
  ;; Allow moving cursor beyond end-of-line in visual block mode
  (evil-move-beyond-eol t)
  ;; Disable wrapping of search around buffer
  (evil-search-wrap nil)
  ;; Whether Y yanks to the end of the line
  (evil-want-Y-yank-to-eol t))

(use-package evil-collection
  :after evil
  :init
  ;; It has to be defined before evil-colllection
  (setq evil-collection-setup-minibuffer t)
  :config
  (evil-collection-init))

;; The goto-chg package is useful with Evil to jump directly to the most recent
;; edit location. This mirrors Vim's change navigation, allowing fast return to
;; where text was last modified without relying on the jump list or search.
;;
;; The goto-chg commands are bound to g; and g,
(use-package goto-chg
  :commands (goto-last-change
             goto-last-change-reverse))

You can also install the vim-tab-bar package to enhance the built-in Emacs tab-bar with a minimalist, Vim-inspired design that automatically adapts to the active Emacs theme. Beyond its Vim-inspired design, the vim-tab-bar package is valued by users who prioritize theme consistency, as it integrates the Emacs tab-bar with any Emacs theme, producing a visually coherent and polished interface:

;; Give Emacs tab-bar a style similar to Vim's
(use-package vim-tab-bar
  :commands vim-tab-bar-mode
  :hook (after-init . vim-tab-bar-mode))

(The screenshot above showcases how vim-tab-bar modifies the built-in Emacs tab-bar.)

The evil-surround package simplifies handling surrounding characters, such as parentheses, brackets, quotes, etc. It provides key bindings to easily add, change, or delete these surrounding characters in pairs. For instance, you can surround the currently selected text with double quotes in visual state using S" or gS":

;; The evil-surround package simplifies handling surrounding characters, such as
;; parentheses, brackets, quotes, etc. It provides key bindings to easily add,
;; change, or delete these surrounding characters in pairs. For instance, you
;; can surround the currently selected text with double quotes in visual state
;; using S" or gS".
(use-package evil-surround
  :after evil
  :commands global-evil-surround-mode
  :custom
  (evil-surround-pairs-alist
   '((?\( . ("(" . ")"))
     (?\[ . ("[" . "]"))
     (?\{ . ("{" . "}"))

     (?\) . ("(" . ")"))
     (?\] . ("[" . "]"))
     (?\} . ("{" . "}"))

     (?< . ("<" . ">"))
     (?> . ("<" . ">"))))
  :hook (after-init . global-evil-surround-mode))

You can also add the following code to enable commenting and uncommenting by pressing gcc in normal mode and gc in visual mode (thanks you to the Reddit user u/mistakenuser for this contribution, which replaces the evil-commentary package):

;; The following code enables commenting and uncommenting by pressing gcc in
;; normal mode and gc in visual mode.
(with-eval-after-load "evil"
  (evil-define-operator my-evil-comment-or-uncomment (beg end)
    "Toggle comment for the region between BEG and END."
    (interactive "<r>")
    (comment-or-uncomment-region beg end))
  (evil-define-key 'normal 'global (kbd "gc") 'my-evil-comment-or-uncomment))

Persisting and Restoring all buffers, windows/split, tab-bar, frames...

The easysession package provides a comprehensive session management for Emacs. It is capable of persisting and restoring file-visiting buffers, indirect buffers (clones), buffer narrowing, Dired buffers, window configurations, the built-in tab-bar (including tabs, their buffers, and associated windows), as well as entire Emacs frames.

With easysession, your Emacs setup is restored automatically when you restart. All files, Dired buffers, and window layouts come back as they were, so you can continue working right where you left off. While editing, you can also switch to another session, switch back, rename sessions, or delete them, giving you full control over multiple work environments.

Easysession also supports extensions, enabling the restoration of Magit buffers and the scratch buffer. Custom extensions can also be created to extend its functionality.

To configure easysession, add the following to ~/.emacs.d/post-init.el:

;; The easysession Emacs package is a session manager for Emacs that can persist
;; and restore file editing buffers, indirect buffers/clones, Dired buffers,
;; windows/splits, the built-in tab-bar (including tabs, their buffers, and
;; windows), and Emacs frames. It offers a convenient and effortless way to
;; manage Emacs editing sessions and utilizes built-in Emacs functions to
;; persist and restore frames.
(use-package easysession
  :commands (easysession-switch-to
             easysession-save-as
             easysession-save-mode
             easysession-load-including-geometry)

  :custom
  (easysession-mode-line-misc-info t)  ; Display the session in the modeline
  (easysession-save-interval (* 10 60))  ; Save every 10 minutes

  :init
  ;; Key mappings
  (global-set-key (kbd "C-c ss") #'easysession-save)
  (global-set-key (kbd "C-c sl") #'easysession-switch-to)
  (global-set-key (kbd "C-c sL") #'easysession-switch-to-and-restore-geometry)
  (global-set-key (kbd "C-c sr") #'easysession-rename)
  (global-set-key (kbd "C-c sR") #'easysession-reset)
  (global-set-key (kbd "C-c sd") #'easysession-delete)

  (if (fboundp 'easysession-setup)
      ;; The `easysession-setup' function adds hooks:
      ;; - To enable automatic session loading during `emacs-startup-hook', or
      ;;   `server-after-make-frame-hook' when running in daemon mode.
      ;; - To automatically save the session at regular intervals, and when
      ;;   Emacs exits.
      (easysession-setup)
    ;; Legacy
    ;; The depth 102 and 103 have been added to to `add-hook' to ensure that the
    ;; session is loaded after all other packages. (Using 103/102 is
    ;; particularly useful for those using minimal-emacs.d, where some
    ;; optimizations restore `file-name-handler-alist` at depth 101 during
    ;; `emacs-startup-hook`.)
    (add-hook 'emacs-startup-hook #'easysession-load-including-geometry 102)
    (add-hook 'emacs-startup-hook #'easysession-save-mode 103)))

Configuring markdown-mode (e.g., README.md syntax)

The markdown-mode package provides a major mode for Emacs for syntax highlighting, editing commands, and preview support for Markdown documents. It supports core Markdown syntax as well as extensions like GitHub Flavored Markdown (GFM).

To configure markdown-mode, add the following to ~/.emacs.d/post-init.el:

;; The markdown-mode package provides a major mode for Emacs for syntax
;; highlighting, editing commands, and preview support for Markdown documents.
;; It supports core Markdown syntax as well as extensions like GitHub Flavored
;; Markdown (GFM).
(use-package markdown-mode
  :commands (gfm-mode
             gfm-view-mode
             markdown-mode
             markdown-view-mode)
  :mode (("\\.markdown\\'" . markdown-mode)
         ("\\.md\\'" . markdown-mode)
         ("README\\.md\\'" . gfm-mode))
  :bind
  (:map markdown-mode-map
        ("C-c C-e" . markdown-do)))

This configuration sets up markdown-mode with deferred loading to improve startup performance. The :commands and :mode keywords ensure that the mode is loaded only when needed—for example, when opening .md, .markdown, or README.md files. Files named README.md are specifically associated with gfm-mode, which is for GitHub Flavored Markdown syntax. The markdown-command variable is set to "multimarkdown" to specify the Markdown processor used for previews and exports. Additionally, a keybinding (C-c C-e) is defined in markdown-mode-map to invoke markdown-do, which can be customized to perform common Markdown-related actions.

Table of contents: To generate a table of contents when editing Markdown files, add the following to your ~/.emacs.d/post-init.el:

;; Automatically generate a table of contents when editing Markdown files
(use-package markdown-toc
  :commands (markdown-toc-generate-toc
             markdown-toc-generate-or-refresh-toc
             markdown-toc-delete-toc
             markdown-toc--toc-already-present-p)
  :custom
  (markdown-toc-header-toc-title "**Table of Contents**"))

Once installed:

  • To insert a table of contents for the first time, run: M-x markdown-toc-generate-toc
  • To update an existing table of contents, run: M-x markdown-toc-generate-or-refresh-toc
  • To remove an existing table of contents, run: M-x markdown-toc-delete-toc

These commands work on any Markdown buffer and rely on properly formatted headers (e.g., #, ##) to build the table of contents.

The author also recommends reading the following article: Emacs: Automating Table of Contents Update for Markdown Documents (e.g., README.md).

Code folding

Kirigami: A unified interface for opening and closing folds

The kirigami package provides a unified method to fold and unfold text in Emacs across a diverse set of Emacs modes.

Supported modes include: outline-mode, outline-minor-mode, outline-indent-minor-mode, org-mode, markdown-mode, gfm-mode, vdiff-mode, vdiff-3way-mode, hide-ifdef-mode, vimish-fold-mode, TeX-fold-mode (AUCTeX), fold-this-mode, origami-mode, yafolding-mode, folding-mode, ts-fold-mode, treesit-fold-mode, and hs-minor-mode (hideshow).

With Kirigami, folding key bindings only need to be configured once. After that, the same keys work consistently across all supported major and minor modes, providing a unified and predictable experience for opening and closing folds. The available commands include:

  • kirigami-open-fold: Open the fold at point.
  • kirigami-open-fold-rec: Open the fold at point recursively.
  • kirigami-close-fold: Close the fold at point.
  • kirigami-open-folds: Open all folds in the buffer.
  • kirigami-close-folds: Close all folds in the buffer.
  • kirigami-toggle-fold: Toggle the fold at point.

To configure kirigami, add the following to ~/.emacs.d/post-init.el:

(use-package kirigami
  :commands (kirigami-open-fold
             kirigami-open-fold-rec
             kirigami-close-fold
             kirigami-toggle-fold
             kirigami-open-folds
             kirigami-close-folds-except-current
             kirigami-close-folds)

  :bind
  (("C-c z o" . kirigami-open-fold)          ; Open fold at point
   ("C-c z O" . kirigami-open-fold-rec)      ; Open fold recursively
   ("C-c z r" . kirigami-open-folds)         ; Open all folds
   ("C-c z c" . kirigami-close-fold)         ; Close fold at point
   ("C-c z m" . kirigami-close-folds)        ; Close all folds
   ("C-c z <tab>" . kirigami-toggle-fold)))  ; Toggle fold at point

;; Uncomment the following if you are an `evil-mode' user:
;; (with-eval-after-load 'evil
;;   (define-key evil-normal-state-map "zo" 'kirigami-open-fold)
;;   (define-key evil-normal-state-map "zO" 'kirigami-open-fold-rec)
;;   (define-key evil-normal-state-map "zc" 'kirigami-close-fold)
;;   (define-key evil-normal-state-map "za" 'kirigami-toggle-fold)
;;   (define-key evil-normal-state-map "zr" 'kirigami-open-folds)
;;   (define-key evil-normal-state-map "zm" 'kirigami-close-folds))

With Kirigami, folding key bindings only need to be configured once. After that, the same keys work consistently across all supported major and minor modes, providing a unified and predictable experience for opening and closing folds.

In addition to unified interface for opening and closing folds, the kirigami package:

  • Enhances Visual Stability on Fold Opening and Closing: Preserves the cursor's exact vertical position when expanding or collapsing headings, maintaining a constant relative distance between the cursor and the window start. This Kirigami enhancement avoids the disruptive window jump or forced re-centering commonly observed during bulk folding operations.
  • Enhances outline: Kirigami improves folding behavior in outline-mode, outline-minor-mode, markdown-mode, gfm-mode, and org-mode. It ensures that deep folds open reliably and permits closing folds even when the cursor is positioned within the content body. Additionally, it maintains window-start heading stability by automatically adjusting the scroll position to keep folded headings visible, preventing the context from disappearing when closing a fold that is partially scrolled off-screen.
  • Hooks for Folding Actions: Two hooks, kirigami-pre-action-predicates and kirigami-post-action-functions, let external code run before and after every folding operation. The pre-action hook runs just before a fold is opened or closed and can allow or block the action. The post-action hook runs once the change is complete and can be used to update UI elements or keep external packages in sync with the new folding state.

outline-minor-mode and hs-minor-mode

One of the modes that provide code folding is outline-minor-mode provides structured code folding in modes such as Emacs Lisp and Python, allowing users to collapse and expand sections based on headings or indentation levels. This feature enhances navigation and improves the management of large files with hierarchical structures.

Alternatively, hs-minor-mode offers basic code folding for blocks defined by curly braces, functions, or other language-specific delimiters. However, for more flexible folding that supports multiple nested levels, outline-minor-mode is generally the preferred choice, as it enables finer control over section visibility in deeply structured code.

For example, to enable outline-minor-mode in Emacs Lisp:

;; The built-in outline-minor-mode provides structured code folding in modes
;; such as Emacs Lisp and Python, allowing users to collapse and expand sections
;; based on headings or indentation levels. This feature enhances navigation and
;; improves the management of large files with hierarchical structures.
(use-package outline
  :ensure nil
  :commands outline-minor-mode
  :hook
  ((emacs-lisp-mode . outline-minor-mode)
   ;; Use " ▼" instead of the default ellipsis "..." for folded text to make
   ;; folds more visually distinctive and readable.
   (outline-minor-mode
    .
    (lambda()
      (let* ((display-table (or buffer-display-table (make-display-table)))
             (face-offset (* (face-id 'shadow) (ash 1 22)))
             (value (vconcat (mapcar (lambda (c) (+ face-offset c)) ""))))
        (set-display-table-slot display-table 'selective-display value)
        (setq buffer-display-table display-table))))))

outline-indent-minor-mode: Folding based on indentation levels

For folding based on indentation levels, the outline-indent Emacs package provides a minor mode that enables folding according to the indentation structure:

;; The outline-indent Emacs package provides a minor mode that enables code
;; folding based on indentation levels.
;;
;; In addition to code folding, *outline-indent* allows:
;; - Moving indented blocks up and down
;; - Indenting/unindenting to adjust indentation levels
;; - Inserting a new line with the same indentation level as the current line
;; - Move backward/forward to the indentation level of the current line
;; - and other features.
(use-package outline-indent
  :commands outline-indent-minor-mode

  :custom
  (outline-indent-ellipsis "")

  :init
  ;; The minor mode can also be automatically activated for a certain modes.
  (add-hook 'python-mode-hook #'outline-indent-minor-mode)
  (add-hook 'python-ts-mode-hook #'outline-indent-minor-mode)

  (add-hook 'yaml-mode-hook #'outline-indent-minor-mode)
  (add-hook 'yaml-ts-mode-hook #'outline-indent-minor-mode))

treesit-fold

It is also recommended to install treesit-fold, which provides intelligent code folding by leveraging the structural understanding of the built-in tree-sitter parser. Unlike traditional folding methods that rely on regular expressions or indentation, treesit-fold uses the actual syntax tree of the code to accurately identify foldable regions such as functions, classes, comments, and documentation strings. This allows for faster and more precise folding behavior that respects the grammar of the programming language, ensuring that fold boundaries are always syntactically correct even in complex or nested code structures.

;; Intelligent code folding by leveraging the structural understanding of the
;; built-in tree-sitter parser. Unlike traditional folding methods that rely on
;; regular expressions or indentation, treesit-fold uses the actual syntax tree
;; of the code to accurately identify foldable regions such as functions,
;; classes, comments, and documentation strings. This allows for faster and more
;; precise folding behavior that respects the grammar of the programming
;; language, ensuring that fold boundaries are always syntactically correct even
;; in complex or nested code structures.
(use-package treesit-fold
  :commands (treesit-fold-close
             treesit-fold-close-all
             treesit-fold-open
             treesit-fold-toggle
             treesit-fold-open-all
             treesit-fold-mode
             global-treesit-fold-mode
             treesit-fold-open-recursively
             treesit-fold-line-comment-mode)

  :custom
  (treesit-fold-line-count-show t)
  (treesit-fold-line-count-format "")

  :config
  (set-face-attribute 'treesit-fold-replacement-face nil
                      :foreground "#808080"
                      :box nil
                      :weight 'bold))

The treesit-fold mode can be enabled using treesit-fold-mode or a hook such as:

(add-hook 'python-ts-mode-hook #'treesit-fold-mode)

Asynchronous code formatting without cursor disruption

Apheleia is an Emacs package designed to run code formatters asynchronously without disrupting the cursor position. Code formatters like Shfmt, Black and Prettier ensure consistency and improve collaboration by automating formatting, but running them on save can introduce latency (e.g., Black takes around 200ms on an empty file) and unpredictably move the cursor when modifying nearby text.

Apheleia solves both problems across all languages, replacing language-specific packages like Blacken and prettier-js. It does this by invoking formatters in an after-save-hook, ensuring changes are applied only if the buffer remains unmodified.

To maintain cursor stability, Apheleia generates an RCS patch, applies it selectively, and employs a dynamic programming algorithm to reposition the cursor if necessary. If the formatting alters the vertical position of the cursor in the window, Apheleia adjusts the scroll position to preserve visual continuity across all displayed instances of the buffer. This allows enjoying automated code formatting without sacrificing editor responsiveness or usability.

To configure apheleia, add the following to ~/.emacs.d/post-init.el:

;; Apheleia is an Emacs package designed to run code formatters (e.g., Shfmt,
;; Black and Prettier) asynchronously without disrupting the cursor position.
(use-package apheleia
  :commands (apheleia-mode
             apheleia-global-mode)
  :hook ((prog-mode . apheleia-mode)))

Context-aware 'go to definition' functionality for 50+ programming languages

The dumb-jump package provides context-aware 'go to definition' functionality for 50+ programming languages without requiring a language server. It works by using simple heuristics and regular expression searches to locate the definitions of functions, variables, and symbols across project files.

Unlike more sophisticated language-aware tools (e.g., eglot or lsp-mode), dumb-jump' does not parse code semantically, which makes it lightweight and fast, but sometimes less precise. It integrates with popular navigation packages like xref', allowing users to jump to definitions or references.

To configure dumb-jump, add the following to ~/.emacs.d/post-init.el:

(use-package dumb-jump
  :commands dumb-jump-xref-activate
  :init
  ;; Register `dumb-jump' as an xref backend so it integrates with
  ;; `xref-find-definitions'. A priority of 90 ensures it is used only when no
  ;; more specific backend is available.
  (add-hook 'xref-backend-functions #'dumb-jump-xref-activate 90)

  (setq dumb-jump-aggressive nil)
  ;; (setq dumb-jump-quiet t)

  ;; Number of seconds a rg/grep/find command can take before being warned to
  ;; use ag and config.
  (setq dumb-jump-max-find-time 3)

  ;; Use `completing-read' so that selection of jump targets integrates with the
  ;; active completion framework (e.g., Vertico, Ivy, Helm, Icomplete),
  ;; providing a consistent minibuffer-based interface whenever multiple
  ;; definitions are found.
  (setq dumb-jump-selector 'completing-read)

  ;; If ripgrep is available, force `dumb-jump' to use it because it is
  ;; significantly faster and more accurate than the default searchers (grep,
  ;; ag, etc.).
  (when (executable-find "rg")
    (setq dumb-jump-force-searcher 'rg)
    (setq dumb-jump-prefer-searcher 'rg)))

Efficient template expansion with snippets

The yasnippet package provides a template system that enhances text editing by enabling users to define and use snippets, which are predefined templates of code or text. The user triggers snippet expansion by pressing the Tab key after typing an abbreviation, such as if. Upon pressing Tab, YASnippet replaces the abbreviation with the corresponding full template, allowing the user to fill in placeholders or fields within the expanded snippet.

The yasnippet-snippets package with a comprehensive collection of bundled templates for numerous programming and markup languages, including C, C++, C#, Perl, Python, Ruby, SQL, LaTeX, HTML, CSS...

(NOTE: Users of UltiSnips, a popular snippet engine for Vim, can export their snippets to YASnippet format using the tool ultyas)

;; The official collection of snippets for yasnippet.
(use-package yasnippet-snippets
  :after yasnippet)

;; YASnippet is a template system designed that enhances text editing by
;; enabling users to define and use snippets. When a user types a short
;; abbreviation, YASnippet automatically expands it into a full template, which
;; can include placeholders, fields, and dynamic content.
(use-package yasnippet
  :commands (yas-minor-mode
             yas-global-mode)

  :hook
  (after-init . yas-global-mode)

  :custom
  (yas-also-auto-indent-first-line t)  ; Indent first line of snippet
  (yas-also-indent-empty-lines t)
  (yas-snippet-revival nil)  ; Setting this to t causes issues with undo
  (yas-wrap-around-region nil) ; Do not wrap region when expanding snippets
  ;; (yas-triggers-in-field nil)  ; Disable nested snippet expansion
  ;; (yas-indent-line 'fixed) ; Do not auto-indent snippet content
  ;; (yas-prompt-functions '(yas-no-prompt))  ; No prompt for snippet choices

  :init
  ;; Suppress verbose messages
  (setq yas-verbosity 0))

Spell checker

The flyspell package is a built-in Emacs minor mode that provides on-the-fly spell checking. It highlights misspelled words as you type, offering interactive corrections. In text modes, it checks the entire buffer, while in programming modes, it typically checks only comments and strings. It integrates with external spell checkers like aspell, hunspell, or ispell to provide suggestions and corrections.

NOTE: flyspell-mode can become slow when using Aspell, especially with large buffers or aggressive suggestion settings like --sug-mode=ultra. This slowdown occurs because Flyspell checks words dynamically as you type or navigate text, requiring frequent communication between Emacs and the external Aspell process. Each check involves sending words to Aspell and receiving results, which introduces overhead from process invocation and inter-process communication.

To configure flyspell, add the following to ~/.emacs.d/post-init.el:

;; The flyspell package is a built-in Emacs minor mode that provides
;; on-the-fly spell checking. It highlights misspelled words as you type,
;; offering interactive corrections. In text modes, it checks the entire buffer,
;; while in programming modes, it typically checks only comments and strings. It
;; integrates with external spell checkers like aspell, hunspell, or
;; ispell to provide suggestions and corrections.
;;
;; NOTE: flyspell-mode can become slow when using Aspell, especially with large
;; buffers or aggressive suggestion settings like --sug-mode=ultra. This
;; slowdown occurs because Flyspell checks words dynamically as you type or
;; navigate text, requiring frequent communication between Emacs and the
;; external Aspell process. Each check involves sending words to Aspell and
;; receiving results, which introduces overhead from process invocation and
;; inter-process communication.
(use-package ispell
  :ensure nil
  :commands (ispell ispell-minor-mode)
  :custom
  ;; Set the ispell program name to aspell
  (ispell-program-name "aspell")

  ;; Define the "en_US" spell-check dictionary locally, telling Emacs to use
  ;; UTF-8 encoding, match words using alphabetic characters, allow apostrophes
  ;; inside words, treat non-alphabetic characters as word boundaries, and pass
  ;; -d en_US to the underlying spell-check program.
  (ispell-local-dictionary-alist
   '(("en_US" "[[:alpha:]]" "[^[:alpha:]]" "[']" nil ("-d" "en_US") nil utf-8)))

  ;; Configures Aspell's suggestion mode to "ultra", which provides more
  ;; aggressive and detailed suggestions for misspelled words. The language
  ;; is set to "en_US" for US English, which can be replaced with your desired
  ;; language code (e.g., "en_GB" for British English, "de_DE" for German).
  (ispell-extra-args '(; "--sug-mode=ultra"
                       "--lang=en_US")))

;; The flyspell package is a built-in Emacs minor mode that provides
;; on-the-fly spell checking. It highlights misspelled words as you type,
;; offering interactive corrections.
(use-package flyspell
  :ensure nil
  :commands flyspell-mode
  :hook
  (; (prog-mode . flyspell-prog-mode)
   (text-mode . (lambda()
                  (if (or (derived-mode-p 'yaml-mode)
                          (derived-mode-p 'yaml-ts-mode)
                          (derived-mode-p 'ansible-mode))
                      (flyspell-prog-mode 1)
                    (flyspell-mode 1)))))
  :config
  ;; Remove strings from Flyspell
  (setq flyspell-prog-text-faces (delq 'font-lock-string-face
                                       flyspell-prog-text-faces))

  ;; Remove doc from Flyspell
  (setq flyspell-prog-text-faces (delq 'font-lock-doc-face
                                       flyspell-prog-text-faces)))

Automatic removal of trailing whitespace on save

Trailing whitespace refers to any spaces or tabs that appear after the last non-whitespace character on a line. These characters have no semantic value and can lead to unnecessary diffs in version control, inconsistent formatting, or visual clutter. Removing them improves code clarity and consistency.

The stripspace Emacs package provides stripspace-local-mode, a minor mode that automatically removes trailing whitespace and blank lines at the end of the buffer when saving.

To enable stripspace and automatically delete trailing whitespace, add the following configuration to ~/.emacs.d/post-init.el:

;; The stripspace Emacs package provides stripspace-local-mode, a minor mode
;; that automatically removes trailing whitespace and blank lines at the end of
;; the buffer when saving.
(use-package stripspace
  :commands stripspace-local-mode

  ;; Enable for prog-mode-hook, text-mode-hook, conf-mode-hook
  :hook ((prog-mode . stripspace-local-mode)
         (text-mode . stripspace-local-mode)
         (conf-mode . stripspace-local-mode))

  :custom
  ;; The `stripspace-only-if-initially-clean' option:
  ;; - nil to always delete trailing whitespace.
  ;; - Non-nil to only delete whitespace when the buffer is clean initially.
  ;; (The initial cleanliness check is performed when `stripspace-local-mode'
  ;; is enabled.)
  (stripspace-only-if-initially-clean nil)

  ;; Enabling `stripspace-restore-column' preserves the cursor's column position
  ;; even after stripping spaces. This is useful in scenarios where you add
  ;; extra spaces and then save the file. Although the spaces are removed in the
  ;; saved file, the cursor remains in the same position, ensuring a consistent
  ;; editing experience without affecting cursor placement.
  (stripspace-restore-column t))

Highlighting uncommitted changes in the buffer margin (e.g., Git changes)

The diff-hl package highlights uncommitted changes in the window margin, enabling navigation between them. Also known as source control gutter indicators, it displays added, modified, and deleted lines in real time. In Git-controlled buffers, changes can be staged and unstaged directly, providing a clear view of version-control changes without running git diff. By default, the module does not start diff-hl-mode automatically.

To configure the diff-hl package, add the following to your ~/.emacs.d/post-init.el:

(use-package diff-hl
  :commands (diff-hl-mode
             global-diff-hl-mode)
  :hook (prog-mode . diff-hl-mode)
  :init
  (setq diff-hl-flydiff-delay 0.4)  ; Faster
  (setq diff-hl-show-staged-changes nil)  ; Realtime feedback
  (setq diff-hl-update-async t)  ; Do not block Emacs
  (setq diff-hl-global-modes '(not pdf-view-mode image-mode)))

Configuring org-mode

Org mode is a major mode designed for organizing notes, planning, task management, and authoring documents using plain text with a simple and expressive markup syntax. It supports hierarchical outlines, TODO lists, scheduling, deadlines, time tracking, and exporting to multiple formats including HTML, LaTeX, PDF, and Markdown.

To configure org-mode, add the following to ~/.emacs.d/post-init.el:

;; Org mode is a major mode designed for organizing notes, planning, task
;; management, and authoring documents using plain text with a simple and
;; expressive markup syntax. It supports hierarchical outlines, TODO lists,
;; scheduling, deadlines, time tracking, and exporting to multiple formats
;; including HTML, LaTeX, PDF, and Markdown.
(use-package org
  :commands (org-mode org-version)
  :mode
  ("\\.org\\'" . org-mode)
  :custom
  (org-hide-leading-stars t)
  (org-startup-indented t)
  (org-adapt-indentation nil)
  (org-edit-src-content-indentation 0)
  ;; (org-fontify-done-headline t)
  ;; (org-fontify-todo-headline t)
  ;; (org-fontify-whole-heading-line t)
  ;; (org-fontify-quote-and-verse-blocks t)
  (org-startup-truncated t))

The org-appear package temporarily reveals normally hidden elements (such as emphasis markers, links, or entities) when the cursor enters them, and hides them again when the cursor leaves. To configure org-appear, add the following to ~/.emacs.d/post-init.el:

(use-package org-appear
  :commands org-appear-mode
  :hook (org-mode . org-appear-mode))

Configuring LSP Servers with Eglot (built-in)

To set up Language Server Protocol (LSP) servers using Eglot, you can configure it, add the following to ~/.emacs.d/post-init.el:

;; Set up the Language Server Protocol (LSP) servers using Eglot.
(use-package eglot
  :ensure nil
  :commands (eglot-ensure
             eglot-rename
             eglot-format-buffer))

Here is an example of how to configure Eglot to enable or disable certain options for the pylsp server in Python development. (Note that a third-party tool, python-lsp-server, must be installed):

;; Configure Eglot to enable or disable certain options for the pylsp server
;; in Python development. (Note that a third-party tool,
;; https://github.com/python-lsp/python-lsp-server, must be installed),
(add-hook 'python-mode-hook #'eglot-ensure)
(add-hook 'python-ts-mode-hook #'eglot-ensure)
(setq-default eglot-workspace-configuration
              `(:pylsp (:plugins
                        (;; Fix imports and syntax using `eglot-format-buffer`
                         :isort (:enabled t)
                         :autopep8 (:enabled t)

                         ;; Syntax checkers (works with Flymake)
                         :pylint (:enabled t)
                         :pycodestyle (:enabled t)
                         :flake8 (:enabled t)
                         :pyflakes (:enabled t)
                         :pydocstyle (:enabled t)
                         :mccabe (:enabled t)

                         :yapf (:enabled :json-false)
                         :rope_autoimport (:enabled :json-false)))))

Auto upgrade Emacs packages

The auto-package-update automates the process of updating installed packages managed by package.el. Instead of requiring users to manually invoke package-list-packages and update each package, auto-package-update can check for available updates at regular intervals, perform updates in the background, and optionally hide the results buffer or prompt before applying changes.

To configure auto-package-update, add the following to ~/.emacs.d/post-init.el:

;; This automates the process of updating installed packages
(use-package auto-package-update
  :custom
  ;; Set the number of days between automatic updates.
  ;; Here, packages will only be updated if at least 7 days have passed
  ;; since the last successful update.
  (auto-package-update-interval 7)

  ;; Suppress display of the *auto-package-update results* buffer after updates.
  ;; This keeps the user interface clean and avoids unnecessary interruptions.
  (auto-package-update-hide-results t)

  ;; Automatically delete old package versions after updates to reduce disk
  ;; usage and keep the package directory clean. This prevents the accumulation
  ;; of outdated files in Emacs’s package directory, which consume
  ;; unnecessary disk space over time.
  (auto-package-update-delete-old-versions t)

  ;; Uncomment the following line to enable a confirmation prompt
  ;; before applying updates. This can be useful if you want manual control.
  ;; (auto-package-update-prompt-before-update t)

  :config
  ;; Run package updates automatically at startup, but only if the configured
  ;; interval has elapsed.
  (auto-package-update-maybe)

  ;; Schedule a background update attempt daily at 10:00 AM.
  ;; This uses Emacs' internal timer system. If Emacs is running at that time,
  ;; the update will be triggered. Otherwise, the update is skipped for that
  ;; day. Note that this scheduled update is independent of
  ;; `auto-package-update-maybe` and can be used as a complementary or
  ;; alternative mechanism.
  (auto-package-update-at-time "10:00"))

Safely terminating unused buffers

The buffer-terminator Emacs package automatically and safely kills buffers, ensuring a clean and efficient workspace while enhancing the performance of Emacs by reducing open buffers, which minimizes active modes, timers, processes...

Beyond performance, buffer-terminator provides other benefits. For instance, if you occasionally need to close annoying or unused buffers, buffer-terminator can handle this automatically, eliminating the need for manual intervention. (The default configuration is suitable for most users. However, the buffer-terminator package is highly customizable. You can define specific rules for retaining or terminating buffers by modifying the buffer-terminator-rules-alist with your preferred set of rules.)

To configure buffer-terminator, add the following to ~/.emacs.d/post-init.el:

(use-package buffer-terminator
  :custom
  ;; Enable/Disable verbose mode to log buffer cleanup events
  (buffer-terminator-verbose nil)

  ;; Set the inactivity timeout (in seconds) after which buffers are considered
  ;; inactive (default is 30 minutes):
  (buffer-terminator-inactivity-timeout (* 30 60)) ; 30 minutes

  ;; Define how frequently the cleanup process should run (default is every 10
  ;; minutes):
  (buffer-terminator-interval (* 10 60)) ; 10 minutes

  :config
  (buffer-terminator-mode 1))

(By default, buffer-terminator automatically determines which buffers are safe to terminate. However, if you need to define specific rules for keeping or terminating certain buffers, you can configure them using buffer-terminator-rules-alist.)

Treemacs, a tree layout file explorer (Sidebar file explorer)

The treemacs package is a file and project explorer for Emacs that provides a visually structured tree layout similar to file browsers in modern IDEs. It integrates well with various Emacs packages such as projectile, lsp-mode, and magit, allowing users to navigate their project structure efficiently.

To configure treemacs, add the following to ~/.emacs.d/post-init.el:

;; A file and project explorer for Emacs that displays a structured tree
;; layout, similar to file browsers in modern IDEs. It functions as a sidebar
;; in the left window, providing a persistent view of files, projects, and
;; other elements.
(use-package treemacs
  :commands (treemacs
             treemacs-select-window
             treemacs-delete-other-windows
             treemacs-select-directory
             treemacs-bookmark
             treemacs-find-file
             treemacs-find-tag)

  :bind
  (:map global-map
        ("M-0"       . treemacs-select-window)
        ("C-x t 1"   . treemacs-delete-other-windows)
        ("C-x t t"   . treemacs)
        ("C-x t d"   . treemacs-select-directory)
        ("C-x t B"   . treemacs-bookmark)
        ("C-x t C-t" . treemacs-find-file)
        ("C-x t M-t" . treemacs-find-tag))

  :init
  (with-eval-after-load 'winum
    (define-key winum-keymap (kbd "M-0") #'treemacs-select-window))

  :config
  (setq treemacs-collapse-dirs                   (if treemacs-python-executable 3 0)
        treemacs-deferred-git-apply-delay        0.5
        treemacs-directory-name-transformer      #'identity
        treemacs-display-in-side-window          t
        treemacs-eldoc-display                   'simple
        treemacs-file-event-delay                2000
        treemacs-file-extension-regex            treemacs-last-period-regex-value
        treemacs-file-follow-delay               0.2
        treemacs-file-name-transformer           #'identity
        treemacs-follow-after-init               t
        treemacs-expand-after-init               t
        treemacs-find-workspace-method           'find-for-file-or-pick-first
        treemacs-git-command-pipe                ""
        treemacs-goto-tag-strategy               'refetch-index
        treemacs-header-scroll-indicators        '(nil . "^^^^^^")
        treemacs-hide-dot-git-directory          t
        treemacs-indentation                     2
        treemacs-indentation-string              " "
        treemacs-is-never-other-window           nil
        treemacs-max-git-entries                 5000
        treemacs-missing-project-action          'ask
        treemacs-move-files-by-mouse-dragging    t
        treemacs-move-forward-on-expand          nil
        treemacs-no-png-images                   nil
        treemacs-no-delete-other-windows         t
        treemacs-project-follow-cleanup          nil
        treemacs-persist-file                    (expand-file-name ".cache/treemacs-persist" user-emacs-directory)
        treemacs-position                        'left
        treemacs-read-string-input               'from-child-frame
        treemacs-recenter-distance               0.1
        treemacs-recenter-after-file-follow      nil
        treemacs-recenter-after-tag-follow       nil
        treemacs-recenter-after-project-jump     'always
        treemacs-recenter-after-project-expand   'on-distance
        treemacs-litter-directories              '("/node_modules" "/.venv" "/.cask")
        treemacs-project-follow-into-home        nil
        treemacs-show-cursor                     nil
        treemacs-show-hidden-files               t
        treemacs-silent-filewatch                nil
        treemacs-silent-refresh                  nil
        treemacs-sorting                         'alphabetic-asc
        treemacs-select-when-already-in-treemacs 'move-back
        treemacs-space-between-root-nodes        t
        treemacs-tag-follow-cleanup              t
        treemacs-tag-follow-delay                1.5
        treemacs-text-scale                      nil
        treemacs-user-mode-line-format           nil
        treemacs-user-header-line-format         nil
        treemacs-wide-toggle-width               70
        treemacs-width                           35
        treemacs-width-increment                 1
        treemacs-width-is-initially-locked       t
        treemacs-workspace-switch-cleanup        nil)

  ;; The default width and height of the icons is 22 pixels. If you are
  ;; using a Hi-DPI display, uncomment this to double the icon size.
  ;; (treemacs-resize-icons 44)

  (treemacs-follow-mode t)
  (treemacs-filewatch-mode t)
  (treemacs-fringe-indicator-mode 'always)

  ;;(when treemacs-python-executable
  ;;  (treemacs-git-commit-diff-mode t))

  (pcase (cons (not (null (executable-find "git")))
               (not (null treemacs-python-executable)))
    (`(t . t)
     (treemacs-git-mode 'deferred))
    (`(t . _)
     (treemacs-git-mode 'simple)))

  (treemacs-hide-gitignored-files-mode nil))

;; (use-package treemacs-evil
;;   :after (treemacs evil)
;;
;; (use-package treemacs-icons-dired
;;   :hook (dired-mode . treemacs-icons-dired-enable-once)
;;
;; (use-package treemacs-tab-bar  ; treemacs-tab-bar if you use tab-bar-mode
;;   :after (treemacs)
;;   :config (treemacs-set-scope-type 'Tabs))
;;
;; (treemacs-start-on-boot)

A better Emacs help buffer

Helpful is an alternative to the built-in Emacs help that provides much more contextual information.

To configure helpful, add the following to ~/.emacs.d/post-init.el:

;; Helpful is an alternative to the built-in Emacs help that provides much more
;; contextual information.
(use-package helpful
  :commands (helpful-callable
             helpful-variable
             helpful-key
             helpful-command
             helpful-at-point
             helpful-function)
  :bind
  ([remap describe-command] . helpful-command)
  ([remap describe-function] . helpful-callable)
  ([remap describe-key] . helpful-key)
  ([remap describe-symbol] . helpful-symbol)
  ([remap describe-variable] . helpful-variable)
  :custom
  (helpful-max-buffers 7))

Efficient jumps

The avy package is a navigation framework designed for jumping directly to any visible text on the screen with minimal keystrokes. The primary benefit of avy is a substantial increase in navigational efficiency, as it minimizes keystrokes compared to iterative methods like arrow keys or standard search.

It operates by generating a dynamic, temporary mapping: upon invocation, such as with the command avy-goto-char or avy-goto-char-2, the user inputs a target character, and avy highlights all visible instances on the screen with unique key sequences. Typing the short sequence corresponding to the desired location instantly moves the point directly there.

To configure avy, add the following to ~/.emacs.d/post-init.el:

(use-package avy
  :commands (avy-goto-char
             avy-goto-char-2
             avy-next)
  :init
  (global-set-key (kbd "C-'") 'avy-goto-char-2))

The author recommends using avy-goto-char-2 (typically bound to C-'). Upon invocation, avy prompts the user to input a two-character sequence. Subsequently, all visible instances of this sequence are highlighted with unique, concise labels (e.g., single letters or numbers). The user then simply presses the key corresponding to the desired label, and avy instantly transports the cursor to that specific occurrence.

Renaming and deleting files

This bufferfile.el package provides helper functions to delete, rename, or copy buffer files:

  • bufferfile-rename: Renames the file visited by the current buffer, ensures that the destination directory exists, and updates the buffer name for all associated buffers, including clones/indirect buffers. It also ensures that buffer-local features referencing the file, such as Eglot or dired buffers, are correctly updated to reflect the new file name.
  • bufferfile-delete: Delete the file associated with a buffer and kill all buffers visiting the file, including clones/indirect buffers.
  • bufferfile-copy: Ensures that the destination directory exists and copies the file visited by the current buffer to a new file.

The functions above also ensures that any modified buffers are saved prior to executing operations like renaming, deleting, or copying.

To configure bufferfile, add the following to ~/.emacs.d/post-init.el:

(use-package bufferfile
  :commands (bufferfile-copy
             bufferfile-rename
             bufferfile-delete)
  :custom
  ;; If non-nil, display messages during file renaming operations
  (bufferfile-verbose nil)

  ;; If non-nil, enable using version control (VC) when available
  (bufferfile-use-vc nil)

  ;; Specifies the action taken after deleting a file and killing its buffer.
  (bufferfile-delete-switch-to 'parent-directory))

The bufferfile package overcomes limitations in Emacs' built-in functions:

  • Emacs built-in renaming: While indirect buffers continue to reference the correct file path, their buffer names can become outdated.
  • Emacs built-in deleting: Indirect buffers are not automatically removed when the base buffer or another indirect buffer is deleted.

The bufferfile package resolves these issues by updating buffer names when a file is renamed and removing all related buffers, including indirect ones, when a file is deleted.

Enhancing the Elisp development experience

To enhance the Elisp development experience, add the following to ~/.emacs.d/post-init.el:

;; Enables automatic indentation of code while typing
(use-package aggressive-indent
  :commands aggressive-indent-mode
  :hook
  (emacs-lisp-mode . aggressive-indent-mode))

;; Highlights function and variable definitions in Emacs Lisp mode
(use-package highlight-defined
  :commands highlight-defined-mode
  :hook
  (emacs-lisp-mode . highlight-defined-mode))

Other optional packages that may be useful include:

;; Prevent parenthesis imbalance
(use-package paredit
  :commands paredit-mode
  :hook
  (emacs-lisp-mode . paredit-mode)
  :config
  (define-key paredit-mode-map (kbd "RET") nil))

;; For paredit+Evil mode users: enhances paredit with Evil mode compatibility
;; --------------------------------------------------------------------------
;; (use-package enhanced-evil-paredit
;;   :commands enhanced-evil-paredit-mode
;;   :hook
;;   (paredit-mode . enhanced-evil-paredit-mode))

;; Displays visible indicators for page breaks
(use-package page-break-lines
  :commands (page-break-lines-mode
             global-page-break-lines-mode)
  :hook
  (emacs-lisp-mode . page-break-lines-mode))

;; Provides functions to find references to functions, macros, variables,
;; special forms, and symbols in Emacs Lisp
(use-package elisp-refs
  :commands (elisp-refs-function
             elisp-refs-macro
             elisp-refs-variable
             elisp-refs-special
             elisp-refs-symbol))

Inhibiting the mouse

The inhibit-mouse package disables mouse input in Emacs.

This package is useful for users who want to disable the mouse to:

  • Prevent accidental clicks or cursor movements that may unexpectedly change the cursor position.
  • Reinforce a keyboard-centric workflow by discouraging reliance on the mouse for navigation.

To configure inhibit-mouse, add the following to ~/.emacs.d/post-init.el:

;; This package is useful for users who want to disable the mouse to:
;; - Prevent accidental clicks or cursor movements that may unexpectedly change
;;   the cursor position.
;; - Reinforce a keyboard-centric workflow by discouraging reliance on the mouse
;;   for navigation.
(use-package inhibit-mouse
  :config
  (if (daemonp)
      (add-hook 'server-after-make-frame-hook #'inhibit-mouse-mode)
    (inhibit-mouse-mode 1)))

NOTE: inhibit-mouse-mode allows users to disable and re-enable mouse functionality, giving them the flexibility to use the mouse when needed.

Showing the tab-bar

Configure the tab-bar-show variable to 1 to display the tab bar exclusively when multiple tabs are open:

;; Configure the `tab-bar-show` variable to 1 to display the tab bar exclusively
;; when multiple tabs are open:
(setopt tab-bar-show 1)

Offline Dictionary

The quick-sdcv.el package serves as a lightweight Emacs interface for the sdcv command-line interface, which is the console version of the StarDict dictionary application.

This package enables Emacs to function as an offline dictionary.

To enable quick-sdcv, add the following to your ~/.emacs.d/post-init.el:

(use-package quick-sdcv
  :custom
  (quick-sdcv-unique-buffers t)
  (quick-sdcv-dictionary-prefix-symbol "")
  (quick-sdcv-ellipsis ""))

Here are the main interactive functions:

  • M-x quick-sdcv-search-at-point: Searches the word around the cursor and displays the result in a buffer.
  • M-x quick-sdcv-search-input: Searches the input word and displays the result in a buffer.

Prerequisite:

  • The sdcv command. (On Linux systems, it can usually be installed by using the system's package manager to install the sdcv package.)
  • Download dictionaries from: http://download.huzheng.org/ . Once the dictionaries are downloaded, extract them into /usr/share/stardict/dic/, or configure the variable quick-sdcv-dictionary-data-dir in the Emacs configuration to specify an alternative dictionary path.

Changing the Default Font

To customize the default font, add the following expression to your ~/.emacs.d/post-init.el:

;; Set the default font to DejaVu Sans Mono with specific size and weight
(set-face-attribute 'default nil
                    :height 130 :weight 'normal :family "DejaVu Sans Mono")
  • Modify the ':weight' value to control the font thickness/boldness. It must be one of the following symbols: 'ultra-heavy, 'heavy (a.k.a. 'black), 'ultra-bold (a.k.a. 'extra-bold), 'bold, 'semi-bold (a.k.a. 'demi-bold), 'medium, 'normal (a.k.a. 'regular, a.k.a. 'book), 'semi-light (a.k.a. 'demi-light), 'light, 'extra-light (a.k.a. 'ultra-light), or 'thin.
  • Modify the :height value to set the font size, where 100 corresponds to 10 pt, 130 to 13 pt, and so on.
  • Modify the :family value to specify a different font, according to your preference. You can replace it with, for example, "Iosevka Term", "Inconsolata", "JetBrains Mono", "Source Code Pro", or "Hack". (The authors preferred font family is "Iosevka Term", medium weight.)

On Linux, you can display a comprehensive list of all installed font families by executing the following command:

fc-list : family | sed 's/,/\n/g' | sort -u

Persisting and Restoring Text Scale

The persist-text-scale Emacs package provides persist-text-scale-mode, which ensures that all adjustments made with text-scale-increase and text-scale-decrease are persisted and restored across sessions. As a result, the text size in each buffer remains consistent, even after restarting Emacs.

This package also facilitates grouping buffers into categories, allowing buffers within the same category to share a consistent text scale. This ensures uniform font sizes when adjusting text scaling. By default:

  • Each file-visiting buffer has its own independent text scale.
  • Special buffers, identified by their buffer names, each retain their own text scale setting.
  • All Dired buffers maintain the same font size, treating Dired as a unified "file explorer" where the text scale remains consistent across different buffers.

This category-based behavior can be further customized by assigning a function to the persist-text-scale-buffer-category-function variable. The function determines how buffers are categorized by returning a category identifier (string) based on the buffer's context. Buffers within the same category will share the same text scale.

To configure the persist-text-scale package, add the following to your ~/.emacs.d/post-init.el:

(use-package persist-text-scale
  :commands (persist-text-scale-mode
             persist-text-scale-restore)

  :hook (after-init . persist-text-scale-mode)

  :custom
  (text-scale-mode-step 1.07))

A Faster Terminal Emulator

NOTE: The vterm package requires external system dependencies, specifically cmake (>= 3.11), libtool-bin, and libvterm. Because it contains a C component, Emacs will prompt you to compile the module the first time you run it. Ensure your environment variables are correctly configured so Emacs can locate your C compiler and build tools.

The vterm package provides is an Emacs terminal emulator that provides a fully interactive shell experience within Emacs, supporting features such as color, cursor movement, and advanced terminal capabilities.

Unlike standard Emacs terminal modes, vterm utilizes the libvterm C library for high-performance emulation. This ensures accurate terminal behavior when running shell programs, text-based applications, and REPLs.

To configure the vterm package, add the following to your ~/.emacs.d/post-init.el:

;; `vterm' is an Emacs terminal emulator that provides a fully interactive shell
;; experience within Emacs, supporting features such as color, cursor movement,
;; and advanced terminal capabilities. Unlike standard Emacs terminal modes,
;; `vterm' utilizes the libvterm C library for high-performance emulation. This
;; ensures accurate terminal behavior when running shell programs, text-based
;; applications, and REPLs.
(use-package vterm
  :if (bound-and-true-p module-file-suffix)
  :commands (vterm
             vterm-send-string
             vterm-send-return
             vterm-send-key
             vterm-module-compile)

  :preface
  (when noninteractive
    ;; vterm unnecessarily triggers compilation of vterm-module.so upon loading.
    ;; This prevents that during byte-compilation (`use-package' eagerly loads
    ;; packages when compiling).
    (advice-add #'vterm-module-compile :override #'ignore))

  (defun my-vterm--setup ()
    ;; Hide the mode-line
    (setq mode-line-format nil)

    ;; Inhibit early horizontal scrolling
    (setq-local hscroll-margin 0)

    ;; Suppress prompts for terminating active processes when closing vterm
    (setq-local confirm-kill-processes nil))

  :init
  (add-hook 'vterm-mode-hook #'my-vterm--setup)

  (setq vterm-timer-delay 0.05)  ; Faster vterm
  (setq vterm-kill-buffer-on-exit t)
  (setq vterm-max-scrollback 5000))

The vterm terminal emulator can be started with M-x vterm.

Loading the custom.el file

NOTE: The author advises against loading custom.el. Users are instead encouraged to define their configuration programmatically in files such as post-init.el. Maintaining configuration programmatically offers several advantages: it ensures reproducibility and facilitates version control. This makes it easier to understand, audit, and evolve the configuration over time.

In Emacs, customization variables modified via the UI (e.g., M-x customize) are typically stored in a separate file, commonly named custom.el. To ensure these settings are loaded during Emacs initialization, it is necessary to explicitly load this file if it exists. To accomplish this, add the following form to your ~/.emacs.d/post-init.el:

;; In Emacs, customization variables modified via the UI (e.g., M-x customize)
;; are typically stored in a separate file, commonly named 'custom.el'. To
;; ensure these settings are loaded during Emacs initialization, it is necessary
;; to explicitly load this file if it exists.
(load custom-file 'noerror 'no-message)

Which other customizations can be interesting to add?

  1. Read the following article from the same author: Essential Emacs Packages for Efficient Software Development and Text Editing

  2. You can also add the following to ~/.emacs.d/post-init.el:

;;; Enable automatic insertion and management of matching pairs of characters
;;; (e.g., (), {}, "") globally using `electric-pair-mode'.
(use-package elec-pair
  :ensure nil
  :commands (electric-pair-mode
             electric-pair-local-mode
             electric-pair-delete-pair)
  :hook (after-init . electric-pair-mode))

;; Allow Emacs to upgrade built-in packages, such as Org mode
(setq package-install-upgrade-built-in t)

;; When Delete Selection mode is enabled, typed text replaces the selection
;; if the selection is active.
(delete-selection-mode 1)

;; Display the current line and column numbers in the mode line
(setq line-number-mode t)
(setq column-number-mode t)
(setq mode-line-position-column-line-format '("%l:%C"))

;; Display of line numbers in the buffer:
(setq-default display-line-numbers-type 'relative)
(dolist (hook '(prog-mode-hook text-mode-hook conf-mode-hook))
  (add-hook hook #'display-line-numbers-mode))

;; Set the maximum level of syntax highlighting for Tree-sitter modes
(setq treesit-font-lock-level 4)

(use-package which-key
  :ensure nil ; builtin
  :commands which-key-mode
  :hook (after-init . which-key-mode)
  :custom
  (which-key-idle-delay 1.5)
  (which-key-idle-secondary-delay 0.25)
  (which-key-add-column-padding 1)
  (which-key-max-description-length 40))

(unless (and (eq window-system 'mac)
             (bound-and-true-p mac-carbon-version-string))
  ;; Enables `pixel-scroll-precision-mode' on all operating systems and Emacs
  ;; versions, except for emacs-mac.
  ;;
  ;; Enabling `pixel-scroll-precision-mode' is unnecessary with emacs-mac, as
  ;; this version of Emacs natively supports smooth scrolling.
  ;; https://bitbucket.org/mituharu/emacs-mac/commits/65c6c96f27afa446df6f9d8eff63f9cc012cc738
  (setq pixel-scroll-precision-use-momentum nil) ; Precise/smoother scrolling
  (pixel-scroll-precision-mode 1))

;; Display the time in the modeline
(add-hook 'after-init-hook #'display-time-mode)

;; Paren match highlighting
(add-hook 'after-init-hook #'show-paren-mode)

;; Track changes in the window configuration, allowing undoing actions such as
;; closing windows.
(setq winner-boring-buffers '("*Completions*"
                                "*Minibuf-0*"
                                "*Minibuf-1*"
                                "*Minibuf-2*"
                                "*Minibuf-3*"
                                "*Minibuf-4*"
                                "*Compile-Log*"
                                "*inferior-lisp*"
                                "*Fuzzy Completions*"
                                "*Apropos*"
                                "*Help*"
                                "*cvs*"
                                "*Buffer List*"
                                "*Ibuffer*"
                                "*esh command on file*"))
(add-hook 'after-init-hook #'winner-mode)

(use-package uniquify
  :ensure nil
  :custom
  (uniquify-buffer-name-style 'reverse)
  (uniquify-separator "")
  (uniquify-after-kill-buffer-p t))

;; Window dividers separate windows visually. Window dividers are bars that can
;; be dragged with the mouse, thus allowing you to easily resize adjacent
;; windows.
;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Window-Dividers.html
(add-hook 'after-init-hook #'window-divider-mode)

;; Constrain vertical cursor movement to lines within the buffer
(setq dired-movement-style 'bounded-files)

;; Dired buffers: Automatically hide file details (permissions, size,
;; modification date, etc.) and all the files in the `dired-omit-files' regular
;; expression for a cleaner display.
(add-hook 'dired-mode-hook #'dired-hide-details-mode)

;; Hide files from dired
(setq dired-omit-files (concat "\\`[.]\\'"
                               "\\|\\(?:\\.js\\)?\\.meta\\'"
                               "\\|\\.\\(?:elc|a\\|o\\|pyc\\|pyo\\|swp\\|class\\)\\'"
                               "\\|^\\.DS_Store\\'"
                               "\\|^\\.\\(?:svn\\|git\\)\\'"
                               "\\|^\\.ccls-cache\\'"
                               "\\|^__pycache__\\'"
                               "\\|^\\.project\\(?:ile\\)?\\'"
                               "\\|^flycheck_.*"
                               "\\|^flymake_.*"))
(add-hook 'dired-mode-hook #'dired-omit-mode)

;; dired: Group directories first
(with-eval-after-load 'dired
  (let ((args "--group-directories-first -ahlv"))
    (when (or (eq system-type 'darwin) (eq system-type 'berkeley-unix))
      (if-let* ((gls (executable-find "gls")))
          (setq insert-directory-program gls)
        (setq args nil)))
    (when args
      (setq dired-listing-switches args))))

;; Enables visual indication of minibuffer recursion depth after initialization.
(add-hook 'after-init-hook #'minibuffer-depth-indicate-mode)

;; Configure Emacs to ask for confirmation before exiting
(setq confirm-kill-emacs 'y-or-n-p)

;; Enabled backups save your changes to a file intermittently
(setq make-backup-files t)
(setq vc-make-backup-files t)
(setq kept-old-versions 10)
(setq kept-new-versions 10)

;; When tooltip-mode is enabled, certain UI elements (e.g., help text,
;; mouse-hover hints) will appear as native system tooltips (pop-up windows),
;; rather than as echo area messages. This is useful in graphical Emacs sessions
;; where tooltips can appear near the cursor.
(setq tooltip-hide-delay 20)    ; Time in seconds before a tooltip disappears (default: 10)
(setq tooltip-delay 0.4)        ; Delay before showing a tooltip after mouse hover (default: 0.7)
(setq tooltip-short-delay 0.08) ; Delay before showing a short tooltip (Default: 0.1)
(tooltip-mode 1)

;; Configure the built-in Emacs server to start after initialization,
;; allowing the use of the emacsclient command to open files in the
;; current session.
(use-package server
  :ensure nil
  :commands server-start
  :hook
  (after-init . server-start))

It is also recommended to read the following articles:

File types (Yaml, Dockerfile, Lua, Jinja2, CSV, Vimrc...)

The following additional file types may be enabled to extend language support beyond the core set.

These modes are optional and can be added selectively to ~/.emacs.d/post-init.el, depending on the languages and formats commonly encountered in a given workflow.

;; Support for Git files (.gitconfig, .gitignore, .gitattributes...)
(use-package git-modes
  :commands (gitattributes-mode
             gitconfig-mode
             gitignore-mode)
  :mode (("/\\.gitignore\\'" . gitignore-mode)
         ("/info/exclude\\'" . gitignore-mode)
         ("/git/ignore\\'" . gitignore-mode)
         ("/.gitignore_global\\'" . gitignore-mode)  ; jc-dotfiles

         ("/\\.gitconfig\\'" . gitconfig-mode)
         ("/\\.git/config\\'" . gitconfig-mode)
         ("/modules/.*/config\\'" . gitconfig-mode)
         ("/git/config\\'" . gitconfig-mode)
         ("/\\.gitmodules\\'" . gitconfig-mode)
         ("/etc/gitconfig\\'" . gitconfig-mode)

         ("/\\.gitattributes\\'" . gitattributes-mode)
         ("/info/attributes\\'" . gitattributes-mode)
         ("/git/attributes\\'" . gitattributes-mode)))

;; Configure built-in sgml-mode to automatically enable
;; `sgml-electric-tag-pair-mode' in `html-mode' and `mhtml-mode', providing
;; automatic insertion of matching closing tags.
(use-package sgml-mode
  :ensure nil
  :commands (sgml-mode sgml-electric-tag-pair-mode)
  :hook ((html-mode mhtml-mode) . sgml-electric-tag-pair-mode))

;; Support for YAML files.
;;
;; NOTE: Prefer the tree-sitter-based yaml-ts-mode over yaml-mode when
;; available, as it provides more accurate syntax parsing and enhanced editing
;; features.
(use-package yaml-mode
  :commands yaml-mode
  :mode (("\\.yaml\\'" . yaml-mode)
         ("\\.yml\\'" . yaml-mode)))

;; Support for Dockerfile files.
;;
;; NOTE: Prefer the tree-sitter-based dockerfile-ts-mode over dockerfile-mode
;; when available, as it provides more accurate syntax parsing and enhanced
;; editing features.
(use-package dockerfile-mode
  :commands dockerfile-mode
  :mode ("Dockerfile\\'" . dockerfile-mode))

;; Support for Gnuplot files
(use-package gnuplot
  :commands gnuplot-mode
  :mode ("\\.gp\\'" . gnuplot-mode))

;; Support for *.lua files.
;;
;; Prefer the tree-sitter-based lua-ts-mode over lua-mode when available, as it
;; provides more accurate syntax parsing and enhanced editing features.
(use-package lua-mode
  :commands lua-mode
  :mode ("\\.lua\\'" . lua-mode))

;; Jinja2 template support for files commonly used in configuration management
;; systems and web frameworks. This mode enables syntax highlighting and basic
;; editing facilities for templates written using the Jinja2 templating
;; language.
(use-package jinja2-mode
  :commands jinja2-mode
  :mode ("\\.j2\\'" . jinja2-mode))

;; CSV file support with automatic column alignment. This configuration enables
;; csv-align-mode whenever a CSV file is opened, improving readability by
;; keeping columns visually aligned according to a configurable maximum width
;; and a set of recognized field separators.
(use-package csv-mode
  :commands (csv-mode
             csv-align-mode
             csv-guess-set-separator)
  :mode ("\\.csv\\'" . csv-mode)
  :hook ((csv-mode . csv-align-mode)
         (csv-mode . csv-guess-set-separator))
  :custom
  (csv-align-max-width 100)
  (csv-separators '("," ";" " " "|" "\t")))

;; Support for Go
;;
;; NOTE: Prefer the tree-sitter-based go-ts-mode over go-mode
;; when available, as it provides more accurate syntax parsing and enhanced
;; editing features.
(use-package go-mode
  :commands go-mode
  :mode ("\\.go\\'" . go-mode))

;; Support for Rust
(use-package rust-mode
  :commands rust-mode
  :mode ("\\.rs\\'" . rust-mode)
  :custom
  (rust-indent-offset 2))

;; Major mode for editing crontab files
(use-package crontab-mode
  :commands crontab-mode
  :mode ("/crontab\\(\\.X*[[:alnum:]]+\\)?\\'"  . crontab-mode))

;; Major mode for editing Nginx configuration files
(use-package nginx-mode
  :commands nginx-mode
  :mode (("nginx\\.conf\\'" . nginx-mode)
         ("/nginx/.+\\.conf\\'" . nginx-mode)))

;; Major mode for HashiCorp Configuration Language (HCL) files
(use-package hcl-mode
  :commands hcl-mode
  :mode ("\\.hcl\\'" . hcl-mode))

;; Major mode for Nix expression language files
(use-package nix-mode
  :commands nix-mode
  :mode ("\\.nix\\'" . nix-mode))

;; Major mode for editing Fish shell scripts
(use-package fish-mode
  :commands fish-mode
  :mode ("\\.fish\\'" . fish-mode))

;; Vim configuration file support. This mode provides syntax highlighting and
;; editing support for various Vim configuration files, including vimrc, gvimrc,
;; local overrides, and project-specific configuration files.
(use-package vimrc-mode
  :commands vimrc-mode
  :mode ("\\.vim\\(rc\\)?\\'" . vimrc-mode))

;; Support for Jenkinsfile files
(use-package jenkinsfile-mode
  :commands jenkinsfile-mode
  :mode ("Jenkinsfile\\'" . jenkinsfile-mode))

;; Support for Haskell
;; (use-package haskell-mode
;;   :commands haskell-mode
;;   :mode ("\\.hs\\'" . haskell-mode))

Customizations: Before init (File: pre-init.el)

NOTE: Using straight.el or Elpaca is optional. Emacs already has a built-in package manager.

Configuring straight.el

The straight.el package is a declarative package manager for Emacs that aims to replace traditional systems like package.el by providing more precise control over package installation and management. Unlike package.el, which relies on downloading pre-built packages from ELPA archives, straight.el clones packages directly from their source repositories (typically Git), enabling reproducible and fully source-controlled package configurations.

Add the straight.el bootstrap code to ~/.emacs.d/pre-init.el:

;; Straight bootstrap
(defvar bootstrap-version)
(let ((bootstrap-file
       (expand-file-name
        "straight/repos/straight.el/bootstrap.el"
        (or (bound-and-true-p straight-base-dir)
            user-emacs-directory)))
      (bootstrap-version 7))
  (unless (file-exists-p bootstrap-file)
    (with-current-buffer
        (url-retrieve-synchronously
         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
         'silent 'inhibit-cookies)
      (goto-char (point-max))
      (eval-print-last-sexp)))
  (load bootstrap-file nil 'nomessage))

(setq straight-use-package-by-default t)

Configuring Elpaca (package manager)

NOTE: When using the :hook keyword with use-package, replace after-init and emacs-startup with elpaca-after-init. Similarly, when using add-hook, replace after-init-hook, emacs-startup-hook with elpaca-after-init-hook to ensure they execute only after Elpaca has activated all queued packages.

Elpaca is a modern, asynchronous package manager for Emacs designed to be a drop-in replacement for package.el and straight.el, with enhanced performance and flexibility. Unlike traditional Emacs package managers, Elpaca installs packages asynchronously, allowing Emacs to remain responsive during installation and updates.

Add to ~/.emacs.d/pre-early-init.el:

;; By default, minimal-emacs-package-initialize-and-refresh is set to t, which
;; makes minimal-emacs.d call the built-in package manager. Since Elpaca will
;; replace the package manager, there is no need to call it.
(setq minimal-emacs-package-initialize-and-refresh nil)

And add the Elpaca bootstrap code to ~/.emacs.d/pre-init.el:

;; Elpaca bootstrap
(defvar elpaca-installer-version 0.11)
(defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory))
(defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory))
(defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory))
(defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git"
                              :ref nil :depth 1 :inherit ignore
                              :files (:defaults "elpaca-test.el" (:exclude "extensions"))
                              :build (:not elpaca--activate-package)))
(let* ((repo  (expand-file-name "elpaca/" elpaca-repos-directory))
       (build (expand-file-name "elpaca/" elpaca-builds-directory))
       (order (cdr elpaca-order))
       (default-directory repo))
  (add-to-list 'load-path (if (file-exists-p build) build repo))
  (unless (file-exists-p repo)
    (make-directory repo t)
    (when (<= emacs-major-version 28) (require 'subr-x))
    (condition-case-unless-debug err
        (if-let* ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*"))
                  ((zerop (apply #'call-process `("git" nil ,buffer t "clone"
                                                  ,@(when-let* ((depth (plist-get order :depth)))
                                                      (list (format "--depth=%d" depth) "--no-single-branch"))
                                                  ,(plist-get order :repo) ,repo))))
                  ((zerop (call-process "git" nil buffer t "checkout"
                                        (or (plist-get order :ref) "--"))))
                  (emacs (concat invocation-directory invocation-name))
                  ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch"
                                        "--eval" "(byte-recompile-directory \".\" 0 'force)")))
                  ((require 'elpaca))
                  ((elpaca-generate-autoloads "elpaca" repo)))
            (progn (message "%s" (buffer-string)) (kill-buffer buffer))
          (error "%s" (with-current-buffer buffer (buffer-string))))
      ((error) (warn "%s" err) (delete-directory repo 'recursive))))
  (unless (require 'elpaca-autoloads nil t)
    (require 'elpaca)
    (elpaca-generate-autoloads "elpaca" repo)
    (let ((load-source-file-function nil)) (load "./elpaca-autoloads"))))
(add-hook 'after-init-hook #'elpaca-process-queues)
(elpaca `(,@elpaca-order))

;; Enable 'elpaca-no-symlink-mode' on Windows, as symlink creation
;; often fails without Administrator privileges or Developer Mode.
(when (eq system-type 'windows-nt)
  (elpaca-no-symlink-mode 1))

;; Install use-package support
(elpaca elpaca-use-package
  ;; Enable use-package :ensure support for Elpaca.
  (elpaca-use-package-mode))

Frequently asked questions

How to debug my configuration?

During the development of your init files, the author strongly recommends adding the following line at the very beginning of your ~/.emacs.d/pre-early-init.el file:

(setq debug-on-error t)

Enabling debug-on-error at this stage allows you to catch errors that might otherwise cause Emacs to fail silently or behave unpredictably.

Customizing Scroll Recentering

By default, minimal-emacs.d sets scroll-conservatively to 20:

(setq scroll-conservatively 20)  ; Default minimal-emacs.d value

This makes Emacs recenters the window when the cursor moves past scroll-conservatively lines beyond the window edge.

You can override this in your post-init.el file. Setting it to 0 forces Emacs to recenter the point aggressively, typically positioning it in the middle of the window (NOT RECOMMENDED):

(setq scroll-conservatively 0)  ; NOT RECOMMENDED

Although this offers more surrounding context, it results in frequent and pronounced screen movement, which can disrupt navigation. A value of 0 is generally discouraged unless this behavior is explicitly desired.

A value of 101 minimizes screen movement and maintains point visibility with minimal adjustment:

(setq scroll-conservatively 101)

The main drawback of 101 is that Emacs will avoid recentering almost entirely, only adjusting the window just enough to keep point visible at the very top or very bottom of the screen. Point can stick to the top or bottom edge of the window, giving you very little context above or below, which can make editing harder if you want surrounding lines visible.

How to display Emacs startup duration?

To measure and display the time taken for Emacs to start, you can use the following Emacs Lisp function. This function will report both the startup duration and the number of garbage collections that occurred during initialization.

Add the following to your ~/.emacs.d/pre-early-init.el file:

(defun display-startup-time ()
  "Display the startup time and number of garbage collections."
  (message "Emacs init loaded in %.2f seconds (Full emacs-startup: %.2fs) with %d garbage collections."
           (float-time (time-subtract after-init-time before-init-time))
           (time-to-seconds (time-since before-init-time))
           gcs-done))

(add-hook 'emacs-startup-hook #'display-startup-time 100)

(Alternatively, you may use the built-in M-x emacs-init-time command to obtain the startup duration. However, emacs-init-time does not account for the portion of the startup process that occurs after after-init-time.)

Optimization: Disabling site-run-file and inhibit-default-init

Emacs performs a multi-stage initialization sequence that may include system-level configuration before and after user configuration. For a minimal and fully deterministic setup, these stages can be disabled.

Emacs can load two optional system-wide files:

  1. site-start.el: Executed before the user configuration. Controlled by the variable site-run-file.
  2. default.el: Executed after the user configuration. Controlled by the variable inhibit-default-init.

Both files are typically maintained by operating systems or system administrators to provide global defaults, package path adjustments, or distribution-specific behavior.

Disable site-start.el (Pre-Initialization Stage)

By default, Emacs evaluates site-start.el early in the startup process. While useful in managed environments, this introduces two disadvantages for a minimal configuration:

  • Startup overhead: Additional I/O and evaluation during the earliest phase of initialization.
  • Loss of determinism: External configuration may modify variables, alter load-path, or introduce behavior that differs across machines.

To ensure a clean and reproducible startup, disable this stage in ~/.emacs.d/pre-early-init.el:

(setq site-run-file nil)

This guarantees that no system-level configuration executes before the user configuration.

Note: On conventional GNU/Linux distributions such as Ubuntu, Fedora, or Arch Linux, site-start.el is often optional and may only introduce distribution defaults. However, on functional systems such as NixOS or Guix System, it may be required to populate essential load-path entries. Disabling it in such environments can prevent Emacs from locating required libraries.

Disable default.el (Post-Initialization Stage)

After loading the user configuration, Emacs may evaluate default.el. This file can override user-defined settings or introduce additional global behavior.

To prevent any system configuration from executing after the user initialization, add the following to pre-early-init.el:

(setq inhibit-default-init t)

Disabling both site-run-file and default.el removes system-level interference, reduces startup variability, and establishes a fully controlled initialization environment suitable for minimal and reproducible configurations.

How to get the latest version of all packages? (unstable)

By default, minimal-emacs.d is configured to prioritize packages from GNU ELPA and NonGNU ELPA repositories over MELPA, ensuring greater stability.

If you prefer to obtain the latest packages from MELPA to access new features and improvements, you can adjust the priority so that Emacs use-package retrieves the newest versions from MELPA before consulting the stable GNU and NonGNU repositories. While MELPA packages are generally regarded as less stable, actual breakages are uncommon; over the past year, only a single package (package-lint) out of 146 packages in the author’s configuration experienced a brief disruption, which was quickly resolved.

Benefit:

  • Ensures access to the most recent package versions, enabling early adoption of new features, performance improvements, and upstream bug fixes.
  • Prioritizing MELPA provides a broader selection of cutting-edge packages, including experimental or niche tools that may not yet exist in stable archives.

Drawback:

  • Exposure to potential instability, as MELPA packages are often built from the latest commits without extensive regression testing.
  • May require periodic maintenance, such as resolving dependency conflicts or adapting to API changes in packages that evolve rapidly. (actual breakages are uncommon.)

To ensure that Emacs always installs or updates to the newest versions of all packages, add the following configuration to ~/.emacs.d/post-early-init.el:

;; Obtain the latest packages from MELPA to access new features and
;; improvements. While MELPA packages are generally regarded as less stable,
;; actual breakages are uncommon; over the past year, only a single package
;; (package-lint) out of 146 packages in the minimal-emacs.d author’s
;; configuration experienced a brief disruption, which was quickly resolved.
(setq package-archive-priorities '(("melpa"        . 90)
                                   ("gnu"          . 70)
                                   ("nongnu"       . 60)
                                   ("melpa-stable" . 50)))

This setup prioritizes MELPA over the stable GNU and NonGNU repositories. When multiple archives provide the same package, Emacs will choose the version from the archive with the highest priority. As a result, you will consistently receive the latest available versions from MELPA while still having access to stable GNU and NonGNU packages when MELPA does not provide them.

In the event of a package breakage, you can direct Emacs to install a package from a specific repository. For instance, to ensure that evil and evil-collection are installed from melpa-stable, add the following configuration to ~/.emacs.d/post-early-init.el:

(setq package-pinned-packages
      '((evil            . "melpa-stable")
        (evil-collection . "melpa-stable")))

Here is a comprehensive package-pinned-packages configuration to guarantee that essential packages, such as consult or corfu, are retrieved from a stable repository, while all remaining packages are obtained from MELPA according to the `package-archive-priorities' priorities above:

(setq package-pinned-packages
      '((annalist                      . "melpa-stable")
        (ansible-doc                   . "melpa-stable")
        (apheleia                      . "melpa-stable")
        (basic-mode                    . "melpa-stable")
        (consult-dir                   . "melpa-stable")
        (corfu-prescient               . "melpa-stable")
        (dtrt-indent                   . "melpa-stable")
        (dumb-jump                     . "melpa-stable")
        (elisp-refs                    . "melpa-stable")
        (evil-collection               . "melpa-stable")
        (f                             . "melpa-stable")
        (flymake-quickdef              . "melpa-stable")
        (groovy-mode                   . "melpa-stable")
        (highlight-defined             . "melpa-stable")
        (markdown-toc                  . "melpa-stable")
        (org-appear                    . "melpa-stable")
        (package-lint-flymake          . "melpa-stable")
        (parent-mode                   . "melpa-stable")
        (php-mode                      . "melpa-stable")
        (prescient                     . "melpa-stable")
        (s                             . "melpa-stable")
        (tocus                         . "melpa-stable")
        (treesit-auto                  . "melpa-stable")
        (vertico-prescient             . "melpa-stable")
        (visual-fill-column            . "melpa-stable")
        (yasnippet-snippets            . "melpa-stable")
        (aggressive-indent             . "gnu")
        (cape                          . "gnu")
        (compat                        . "gnu")
        (consult                       . "gnu")
        (corfu                         . "gnu")
        (csv-mode                      . "gnu")
        (dash                          . "gnu")
        (diff-hl                       . "gnu")
        (diminish                      . "gnu")
        (easy-escape                   . "gnu")
        (embark                        . "gnu")
        (embark-consult                . "gnu")
        (expand-region                 . "gnu")
        (gcmh                          . "gnu")
        (indent-bars                   . "gnu")
        (marginalia                    . "gnu")
        (modus-themes                  . "gnu")
        (orderless                     . "gnu")
        (org                           . "gnu")
        (rainbow-mode                  . "gnu")
        (transient                     . "gnu")
        (vertico                       . "gnu")
        (yasnippet                     . "gnu")
        (ztree                         . "gnu")
        (eat                           . "nongnu")
        (edit-indirect                 . "nongnu")
        (evil-visualstar               . "nongnu")
        (exec-path-from-shell          . "nongnu")
        (git-modes                     . "nongnu")
        (golden-ratio                  . "nongnu")
        (goto-chg                      . "nongnu")
        (gptel                         . "nongnu")
        (lua-mode                      . "nongnu")
        (magit                         . "nongnu")
        (markdown-mode                 . "nongnu")
        (package-lint                  . "nongnu")
        (page-break-lines              . "nongnu")
        (paredit                       . "nongnu")
        (popup                         . "nongnu")
        (rainbow-delimiters            . "nongnu")
        (undo-fu                       . "nongnu")
        (undo-fu-session               . "nongnu")
        (wgrep                         . "nongnu")
        (with-editor                   . "nongnu")
        (ws-butler                     . "nongnu")
        (yaml-mode                     . "nongnu")))

How to use MELPA stable?

Note: The minimal-emacs.d author does not recommend using MELPA Stable. Use MELPA instead, which is enabled by default in the minimal-emacs.d configuration.

By default, minimal-emacs.d uses MELPA instead of MELPA Stable because MELPA Stable offers outdated packages that lack essential features. If you prefer to use MELPA Stable, you may follow the instructions below.

Here are the key differences between MELPA (the default repository used in minimal-emacs.d) and MELPA Stable:

  • MELPA (preferred) is a rolling release repository for Emacs packages, where packages are continuously updated with the latest commits from their respective development branches, delivering the most current features and bug fixes. While MELPA features the latest changes, most Emacs package developers have learned to maintain a relatively stable master branch, which contributes to MELPA’s overall stability. Furthermore, MELPA includes a broader selection of packages.
  • In contrast, MELPA Stable is a repository that hosts versioned, tagged releases of packages. However, MELPA Stable does not guarantee more reliability than MELPA, as its tagged versions may still suffer from issues like uncoordinated dependencies or incomplete testing, and updates are less frequent, often based on developer discretion rather than every new commit.

If you prefer MELPA Stable over MELPA, you can add MELPA Stable and prioritize it. To ensure packages are fetched from MELPA Stable first, add the following configuration to ~/.emacs.d/post-early-init.el:

;; This change increases MELPA Stable priority to 70, above MELPA,
;; ensuring that MELPA is preferred for package installations
;; over MELPA Stable.
;; (Note: The minimal-emacs.d author does not assign higher priority to MELPA
;; Stable than to MELPA.)
;;
;; (setq package-archive-priorities '(("gnu"          . 90)
;;                                    ("nongnu"       . 80)
;;                                    ("melpa-stable" . 70)
;;                                    ("melpa"        . 60)))

How to load a local lisp file for machine-specific configurations?

Add the following line to the end of your post-init.el file:

(minimal-emacs-load-user-init "local.el")

This allows local.el to load, enabling custom configurations specific to the machine.

(Ensure that local.el is in the same directory as post-init.el.)

How to prevent Emacs from repeatedly performing native compilation on specific Elisp files

In certain Emacs configurations, specific files may be recompiled repeatedly during startup.

Compiling /snap/emacs/current/usr/share/emacs/lisp/org/org-loaddefs.el.gz...
Compiling /snap/emacs/current/usr/share/emacs/etc/themes/modus-vivendi-theme.el...

This behavior arises because Emacs performs native compilation on specific Elisp files, and in many scenarios, it is desirable to prevent compilation of files that fail during the process.

Emacs can be configured to bypass native compilation for files whose paths match a list of regular expression patterns by setting native-comp-jit-compilation-deny-list. For example:

(let ((deny-list '("\\(?:[/\\\\]\\.dir-locals\\.el\\(?:\\.gz\\)?$\\)"
                   "\\(?:[/\\\\]modus-vivendi-theme\\.el\\(?:\\.gz\\)?$\\)"
                   "\\(?:[/\\\\][^/\\\\]+-loaddefs\\.el\\(?:\\.gz\\)?$\\)"
                   "\\(?:[/\\\\][^/\\\\]+-autoloads\\.el\\(?:\\.gz\\)?$\\)")))
  (setq native-comp-jit-compilation-deny-list deny-list)
  ;; Deprecated
  (with-no-warnings
    (setq native-comp-deferred-compilation-deny-list deny-list)
    (setq comp-deferred-compilation-deny-list deny-list)))

This deny list instructs Emacs to bypass native compilation for files matching the specified patterns, preventing unnecessary or error-prone recompilation while permitting all other files to be compiled normally.

How to load Emacs customizations?

To load customizations saved by Emacs (M-x customize), add the following code snippet to the post-init.el file. This ensures that the custom file, typically set to a separate file for user preferences, is loaded without errors or messages during startup:

(load custom-file 'noerror 'nomessage)

However, rather than relying on customizations loaded with the code above, the author recommends configuring Emacs through init files (just as you are doing by reading this README.md and customizing packages using use-package with the :custom keyword).

How to increase gc-cons-threshold?

Add the following to ~/.emacs.d/pre-early-init.el to ensure that minimal-emacs.d restores the specified amount after startup:

(setq minimal-emacs-gc-cons-threshold (* 64 1024 1024))

How to prevent Emacs from loading .dir-locals.el files?

By default, Emacs loads .dir-locals.el from the current directory or its parents and applies project-specific settings such as indentation, compilation commands, or custom minor modes. While useful in many cases, this behavior can introduce unintended overrides, inconsistencies, or even security risks when working with untrusted projects.

If you want to prevent Emacs from applying these directory-local settings, you can disable .dir-locals.el by setting enable-dir-local-variables to nil:

(setq enable-dir-local-variables nil)

How to make minimal-emacs.d use an environment variable to change ~/.emacs.d to another directory?

Add the following to the top of the ~/.emacs.d/pre-early-init.el file to make minimal-emacs.d use the MINIMAL_EMACS_USER_DIRECTORY environment variable to change ~/.emacs.d to another directory:

;; Place this at the very beginning of pre-early-init.el
(let ((previous-minimal-emacs-user-directory (expand-file-name
                                              minimal-emacs-user-directory))
      (env-dir (getenv "MINIMAL_EMACS_USER_DIRECTORY")))
  (setq minimal-emacs-user-directory (if env-dir
                                         (expand-file-name env-dir)
                                       (expand-file-name user-emacs-directory)))
  (unless (string= minimal-emacs-user-directory
                   previous-minimal-emacs-user-directory)
    ;; Load pre-early-init.el from the new directory
    (minimal-emacs-load-user-init "pre-early-init.el")))

Are post-early-init.el and pre-init.el the same file in terms of the logic?

During the execution of early-init.el (and pre-early-init.el and post-early-init.el), Emacs has not yet loaded the graphical user interface (GUI). This file is used for configurations that need to be applied before the GUI is initialized, such as settings that affect the early stages of the Emacs startup process.

Thus, post-early-init.el and pre-init.el serve different purposes and are not the same.

Why is the menu bar disabled by default?

The menu bar is disabled by default in minimal-emacs.d to provide a minimal, distraction-free environment, which many experienced users prefer.

The menu bar can be re-enabled by adding the following configuration to ~/.emacs.d/pre-early-init.el:

(setq minimal-emacs-ui-features '(menu-bar))

Other UI features can also be enabled by adding the following to ~/.emacs.d/pre-early-init.el:

(setq minimal-emacs-ui-features '(context-menu tool-bar menu-bar dialogs tooltips))

Why did the author develop minimal-emacs.d?

The author began working on it after realizing that no existing starter kit offered a truly minimal setup with the flexibility for users to choose exactly what to include in their configuration.

How to keep minimal-emacs.d pre-*.el and post-*.el files in a separate directory?

To ensure the minimal-emacs.d configuration loads post-early-init.el, pre-init.el, and post-init.el from a different directory, such as ~/.config/minimal-emacs.d/, modify the minimal-emacs-user-directory variable by adding the following to your ~/.emacs.d/pre-early-init.el file:

(setq minimal-emacs-user-directory "~/.config/minimal-emacs.d/")

This will ensure that the minimal-emacs.d configuration loads post-early-init.el, pre-init.el, and post-init.el from ~/.config/minimal-emacs.d/.

Keep in mind that if you change the minimal-emacs-user-directory, minimal-emacs.d will attempt to load the rest of the configuration from that directory (e.g., ~/.config/minimal-emacs/post-early-init.el, ~/.config/minimal-emacs/pre-init.el and ~/.config/minimal-emacs/post-init.el, etc.).

How to make minimal-emacs.d install packages in the early-init phase instead of the init phase?

NOTE: Running package initialization and installation during the early-init phase is NOT RECOMMENDED because this stage occurs before the GUI system, windowing, and comprehensive error-handling buffers are fully initialized. When package-install or package-refresh-contents triggers a failure—such as a TLS handshake error or a lost network connection—Emacs cannot yet render a graphical window to display the backtrace or warning. This results in a "silent" hang or a crash that provides no visual feedback to the user, forcing a pivot to a terminal to inspect standard output. Furthermore, many packages expect a fully functional frame and loaded user environment to configure themselves correctly; forcing them to load during early-init bypasses the intentional separation designed to let you set up UI-independent variables before the package system and GUI logic complicate the startup sequence.

To install and load packages during the early-init phase, add the following to post-early-init.el:

;; THIS IS NOT RECOMMENDED
;;
;; Running package initialization and installation during the early-init phase
;; is NOT RECOMMENDED because this stage occurs before the GUI system,
;; windowing, and comprehensive error-handling buffers are fully initialized.
;; When package-install or `package-refresh-contents` triggers a failure—such as
;; a TLS handshake error or a lost network connection—Emacs cannot yet render a
;; graphical window to display the backtrace or warning. This results in a
;; "silent" hang or a crash that provides no visual feedback to the user,
;; forcing a pivot to a terminal to inspect standard output. Furthermore, many
;; packages expect a fully functional frame and loaded user environment to
;; configure themselves correctly; forcing them to load during early-init
;; bypasses the intentional separation designed to let you set up UI-independent
;; variables before the package system and GUI logic complicate the startup
;; sequence.
;;
;; File: `post-early-init.el'

(setq minimal-emacs-package-initialize-and-refresh nil)

;; If you want to ignore the warning:
;; "Warning (package): Unnecessary call to package-initialize in init file."
;; Uncomment the following setq:
;; (setq warning-suppress-types '((package)))

;; Initialize packages in the early-init phase instead of init
(when (bound-and-true-p minimal-emacs-package-initialize-and-refresh)
  ;; Initialize and refresh package contents again if needed
  (package-initialize)
  (unless (package-installed-p 'use-package)
    (unless (seq-empty-p package-archive-contents)
      (package-refresh-contents))
    (package-install 'use-package))
  (require 'use-package))

;; TODO: Add your use-package packages here

Minimal-emacs.d configurations from users

Features

The minimal-emacs.d base provides a sensible foundation for your personal configuration. It addresses common pain points in vanilla Emacs to provide a responsive and clean environment from the start, without forcing a specific workflow.

Fast Initialization and Performance

  • Optimized File Handlers: Defers garbage collection during startup to reduce load times, restoring it to a standard threshold once Emacs is ready.
  • Process Throughput: Increases the chunk size for reading from processes to speed up external tool interactions.
  • Compiled File Preference: Instructs Emacs to prioritize loading newer byte-compiled files.
  • Optimized Text Rendering: Disables font compacting during startup to reduce memory usage and speed up initialization.
  • Silent Boot Sequence: Removes the GNU Emacs startup message, unsets OS-irrelevant command line options, and defers toolbar setup.

Native Compilation and Byte Compilation

  • Out-of-the-Box Optimization: Configures default settings for native and byte compilation.
  • Quiet Compilation: Suppresses warnings and errors during async native compilation to prevent popup interruptions.

Interface Defaults

  • Minimal UI: Disables the startup screen, menu bar, tool bar, and scroll bars by default to maximize screen space.
  • Smart Rendering: Stops rendering cursors and region highlights in non-focused windows. Prevents Emacs from automatically resizing frames on setting adjustments.
  • Typographic Defaults: Renders underlines at the descent line, replaces truncation markers with an ellipsis ("..."), and disables the visible bell.
  • Focused Minibuffer: Enables recursive minibuffers and restricts the cursor from entering read-only prompt areas.

Package and File Management

  • Repository Prioritization: Configures archives and sets explicit priorities for GNU ELPA, NonGNU ELPA, and MELPA.
  • Centralized Artifacts: Routes auto-save and backup files to dedicated subdirectories within the Emacs configuration folder. Enables versioned backups.
  • Auto-Revert: Refreshes buffers when the underlying file changes on disk. (Disabled by default.)
  • Session Memory: Saves cursor positions across sessions, maintains recent file history, and persists the minibuffer history. (Disabled by default.)

Precision Editing and UX Enhancements

  • Predictable Scrolling: Configures conservative scrolling to eliminate default half-screen jumps.
  • Modern Formatting Standards: Enforces a POSIX-compliant final newline on save, disables double-space sentence endings, and triggers smart indentation only on newlines and backspaces.
  • Sensible Tab Management: Defaults to spaces with a tab width. Configures the tab key to indent first, then complete.
  • Fast Interactions: Configures prompts to accept "y" or "n" instead of "yes" or "no".

Developer Experience

  • Optional Built-in Package Defaults: Configures optimized settings for built-in packages like Eglot, recentf, savehist, and auto-save without enabling them by default.
  • Git Integration: Sets version control to use the --histogram diff algorithm and automatically follow file renames in logs.

Buffer, Directory, and Window Management

  • Modern Splits: Favors vertical window splits over horizontal ones.
  • Ediff Optimization: Configures Ediff to use a single frame and split windows horizontally.
  • Dired Mastery: Enables dired-dwim-target for easier file operations between panes. Auto-updates Dired buffers and cleans up deleted directories silently.
  • Window Dividers: Uses minimalistic window dividers and sets default fringe widths.

Security, Stability, and Customizable Initialization

  • Safety Checks: Verifies successful configuration load and warns of conflicts with legacy ~/.emacs files.
  • Drop-In Customization: Supports loading modular configuration files (pre-early-init.el, post-early-init.el, pre-init.el, and post-init.el) to hook into different stages of the startup process.
  • Strict TLS Verification: Enforces strict SSL/TLS certificate checks and raises the minimum encryption strength for GnuTLS.
  • Encrypted Auth Sources: Prefers GPG-encrypted authentication files (~/.authinfo.gpg) and directs the GPG agent to use the minibuffer for passphrase entry.

Author and license

The minimal-emacs.d project has been written by James Cherti and is distributed under terms of the GNU General Public License version 3, or, at your choice, any later version.

Copyright (C) 2024-2026 James Cherti

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program (in the .LICENSE file).

Links

Contribution from the minimal-emacs.d community:

  • Sunng's minimal-emacs.d Nix flake: A Nix flake that enables reproducible deployment of minimal-emacs.d, allowing the Emacs configuration to be pinned, built, and installed through Nix.

Other Emacs packages by the same author:

  • compile-angel.el: Speed up Emacs! This package guarantees that all .el files are both byte-compiled and native-compiled, which significantly speeds up Emacs.
  • outline-indent.el: An Emacs package that provides a minor mode that enables code folding and outlining based on indentation levels for various indentation-based text files, such as YAML, Python, and other indented text files.
  • easysession.el: Easysession is lightweight Emacs session manager that can persist and restore file editing buffers, indirect buffers/clones, Dired buffers, the tab-bar, and the Emacs frames (with or without the Emacs frames size, width, and height).
  • vim-tab-bar.el: Make the Emacs tab-bar Look Like Vim's Tab Bar.
  • elispcomp: A command line tool that allows compiling Elisp code directly from the terminal or from a shell script. It facilitates the generation of optimized .elc (byte-compiled) and .eln (native-compiled) files.
  • tomorrow-night-deepblue-theme.el: The Tomorrow Night Deepblue Emacs theme is a beautiful deep blue variant of the Tomorrow Night theme, which is renowned for its elegant color palette that is pleasing to the eyes. It features a deep blue background color that creates a calming atmosphere. The theme is also a great choice for those who miss the blue themes that were trendy a few years ago.
  • Ultyas: A command-line tool designed to simplify the process of converting code snippets from UltiSnips to YASnippet format.
  • dir-config.el: Automatically find and evaluate .dir-config.el Elisp files to configure directory-specific settings.
  • flymake-bashate.el: A package that provides a Flymake backend for the bashate Bash script style checker.
  • flymake-ansible-lint.el: An Emacs package that offers a Flymake backend for ansible-lint.
  • inhibit-mouse.el: A package that disables mouse input in Emacs, offering a simpler and faster alternative to the disable-mouse package.
  • quick-sdcv.el: This package enables Emacs to function as an offline dictionary by using the sdcv command-line tool directly within Emacs.
  • enhanced-evil-paredit.el: An Emacs package that prevents parenthesis imbalance when using evil-mode with paredit. It intercepts evil-mode commands such as delete, change, and paste, blocking their execution if they would break the parenthetical structure.
  • stripspace.el: Ensure Emacs Automatically removes trailing whitespace before saving a buffer, with an option to preserve the cursor column.
  • persist-text-scale.el: Ensure that all adjustments made with text-scale-increase and text-scale-decrease are persisted and restored across sessions.
  • pathaction.el: Execute the pathaction command-line tool from Emacs. The pathaction command-line tool enables the execution of specific commands on targeted files or directories. Its key advantage lies in its flexibility, allowing users to handle various types of files simply by passing the file or directory as an argument to the pathaction tool. The tool uses a .pathaction.yaml rule-set file to determine which command to execute. Additionally, Jinja2 templating can be employed in the rule-set file to further customize the commands.
  • kirigami.el: The kirigami Emacs package offers a unified interface for opening and closing folds across a diverse set of major and minor modes in Emacs, including outline-mode, outline-minor-mode, outline-indent-minor-mode, org-mode, markdown-mode, vdiff-mode, vdiff-3way-mode, hs-minor-mode, hide-ifdef-mode, origami-mode, yafolding-mode, folding-mode, and treesit-fold-mode. With Kirigami, folding key bindings only need to be configured once. After that, the same keys work consistently across all supported major and minor modes, providing a unified and predictable folding experience.

About

minimal-emacs.d - Better Emacs defaults and optimized startup, intended to serve as a solid foundation for your vanilla Emacs configuration

Resources

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages

  • Emacs Lisp 93.0%
  • Python 3.4%
  • Shell 2.4%
  • Clojure 1.2%