A Technical Guide to Compiling Emacs for Performance on Linux and Unix systems

Most Linux distributions ship generic binaries compiled to run safely on a vast array of older hardware configurations. While this ensures broad compatibility, it sacrifices the speed that comes from using the specific, modern instruction sets of your processor. Building Emacs directly from source allows instructing the compiler to generate machine code targeted at your CPU architecture, resulting in a faster and more efficient runtime environment.

Before we dive in, please consider sharing this article on your website, blog, Mastodon, Reddit, X, Linkedin, or other social media platforms. Sharing it will help other Emacs users discover how to properly build Emacs for performance.

Beyond raw hardware optimization, building from source enables dropping decades of legacy compatibility layers and embracing modern desktop technologies. For example, Wayland users can configure the build to bypass old X11 display protocols in favor of a Wayland environment, ensuring smoother rendering and better system integration.

Additionally, this article details how to optimize the internal native Lisp compiler, which transforms Lisp packages into machine code to ensure that every Emacs package in your configuration operates at its maximum potential speed.

Here is the step-by-step process for building a highly optimized Emacs binary and packages.

Installing dependencies

Arch Linux

On Arch Linux, the cleanest and most native method to resolve build dependencies is to use the official Emacs PKGBUILD, which automatically read the official dependency list and install them:

mkdir -p ~/emacs-deps
cd ~/emacs-deps
wget https://gitlab.archlinux.org/archlinux/packaging/packages/emacs/-/raw/main/PKGBUILD
makepkg --syncdeps --nobuildCode language: plaintext (plaintext)

NOTE: Once makepkg finishes installing the dependencies, you can safely delete the ~/emacs-deps directory.

Debian, Mint and Ubuntu

On Debian-based systems, the most efficient method to gather dependencies is to use the package manager to automatically fetch them based on the distribution’s source package. You must first ensure that source repositories are enabled:

  • Open /etc/apt/sources.list with root privileges in your text editor.
  • Find the lines starting with deb-src (Read: “sources.list format” on Debian Wiki) and uncomment them by removing the # at the beginning of the line.
  • Update your package lists and download the install Emacs dependencies:
sudo apt update
sudo apt build-dep emacs

Other Linux Distributions (Generic)

If you are using a distribution not listed above, you will need to use your distribution’s specific package manager to install the required development libraries. Look for packages that include the library headers, typically suffixed with -dev or -devel.

Here is the master list of upstream library names required to compile this specific Wayland and Native-Comp optimized build:

  • Core Build Tools: gcc, make, autoconf, automake, pkg-config (or pkgconf), git, texinfo
  • Native Compilation Engine: libgccjit (Ensure this matches your GCC version)
  • System and Core Libraries: glib2, gnutls, zlib, ncurses, sqlite3, tree-sitter, gmp
  • Graphics and Wayland Toolkit (PGTK): gtk3, cairo, harfbuzz, pango, dbus
  • Image Formats: libjpeg (or libjpeg-turbo), libpng, libtiff, giflib, libwebp, librsvg2, lcms2
  • Fonts and Text Shaping: fontconfig, freetype2, libotf, m17n-lib, libxml2

Optimizing the Native Lisp Compiler

Fine-Tuning Native Compilation

Before building Emacs with native compilation support, we will optimize how Emacs transforms Lisp packages into machine code. This is managed via the native-comp-compiler-options variable. While the main Emacs build uses your global CFLAGS, this variable specifically instructs libgccjit on how to handle every .el file it encounters.

Add the following to your early-init.el file:

;; Display the architecture using:
;;   gcc -march=native -Q --help=target | grep march
;;
;; The above command asks the compiler to resolve native for your current CPU
;; and display the resulting target. For example, if the output shows
;; -march=skylake, you know that skylake is the identifier you should pass to
;; -mtune and -march.
(setq my-cpu-architecture "CHANGE_THIS_TO_YOUR_ARCHITECTURE")

;; `native-comp-compiler-options' specifies flags passed directly to the C
;; compiler (for example, GCC) when compiling the Lisp-to-C output
;; produced by the native compilation process. These flags affect code
;; generation, optimization, and debugging information.
(setq native-comp-compiler-options `(;; The most meaningful optimizations:
                                     "-O2"
                                     ,(format "-mtune=%s" my-cpu-architecture)
                                     ,(format "-march=%s" my-cpu-architecture)
                                     ;; Reduce .eln size and compilation
                                     ;; overhead.
                                     "-g0"
                                     ;; Good defensive choice for Emacs
                                     ;; stability.
                                     "-fno-omit-frame-pointer"
                                     "-fno-finite-math-only"))

(setq native-comp-driver-options '(;; -Wl,-z,pack-relative-relocs compresses
                                   ;; relocation tables to reduce file size and
                                   ;; slightly improve load times.
                                   "-Wl,-z,pack-relative-relocs"
                                   ;; -Wl,-O2 applies standard linker-level
                                   ;; optimizations (like string merging) to the
                                   ;; generated shared object.
                                   "-Wl,-O2"
                                   ;; -Wl,--as-needed prevents the linker from
                                   ;; recording dependencies on libraries that
                                   ;; are not actually used by the code.
                                   "-Wl,--as-needed"))Code language: Lisp (lisp)

IMPORTANT: Change CHANGE_THIS_TO_YOUR_ARCHITECTURE to your specific architecture. Run the following command to display the CPU architecture:

gcc -march=native -Q --help=target | grep march

The above command asks the compiler to resolve native for your current CPU and display the resulting target. For example, if the output shows -march=skylake, then replace CHANGE_THIS_TO_YOUR_ARCHITECTURE with skylake.

(If you prefer automatic CPU architecture detection, refer to the comments section below. I shared a function that detects the CPU architecture using gcc and adds it to the configuration.)

NOTE: Avoid adding -mtune=native and/or -march=native to the native-comp-compiler-options variable. While these flags work in global CFLAGS, libgccjit, the library responsible for native compilation, often fails to resolve the native keyword correctly. This happens because the JIT interface does not always trigger the same host-probing logic as the standalone GCC driver.

The rationale behind the selection of these flags is as follows

  • The choice of -O2 is an intentional balance. While -O3 may provide small performance gains in some workloads, it can also increase binary size and occasionally reduce responsiveness. -Ofast is generally discouraged because it enables aggressive floating-point optimizations.
  • Using -g0 disables the generation of debug symbols for .eln files, which reduces their size on disk and speeds up the compilation process itself.
  • -fno-omit-frame-pointer The Emacs developers recommend using this flag to disable omit-frame-pointer. Although enabling omit-frame-pointer frees up a general-purpose CPU register, it does not yield significant performance gains on modern architectures and can lead to bugs that are difficult to debug. According to Eli Zaretskii, an Emacs developer: “See bug#76180. This is in the context of the igc branch, where omit-frame-pointer is particularly troublesome, though it also causes problems in other situations. For further details, see etc/DEBUG in the Emacs source tree.”
  • The -fno-finite-math-only flag prevents the compiler from assuming that floating-point operations never produce NaN or infinity values. This flag is mostly defensive because GCC does not enable -ffinite-math-only at -O2 by default, but it can help avoid unsafe assumptions if additional aggressive optimization flags are introduced later.

For users looking to ensure a fully optimized environment, the compile-angel package is a valuable addition to the native compilation workflow. Integrating compile-angel guarantees that every .el file in your load path, including your own configuration and manually managed .el files, is properly byte and natively compiled. This ensures a consistent performance boost across the entire editor.

Purging the Native Cache to Force JIT Recompilation

After modifying the native-comp-compiler-options and/or native-comp-driver-options variables, you must force Emacs to rebuild your packages. Ensure Emacs is closed and delete all existing .eln binaries using the following command:

find ~/.emacs.d/ -name '*.eln' -deleteCode language: plaintext (plaintext)

Because Emacs uses a deferred compilation engine (Native JIT compiler), you do not need to manually trigger a build script. Simply launch Emacs and begin your normal workflow. As Emacs loads your packages and detects the missing .eln files, it will spin up background threads to recompile them using your new optimization flags.

Compiling Emacs for Performance

Step 1: Cloning and Preparing the Source

To build Emacs, you must first obtain the source code from the official mirror and switch to a stable release branch:

git clone https://github.com/emacs-mirror/emacs
cd emacs
git checkout "emacs-30.2"Code language: plaintext (plaintext)

NOTE: The official Savannah Git repository at https://git.savannah.gnu.org/git/emacs.git can occasionally be slow or unreliable, so this guide uses the official GitHub mirror instead.

We target a specific release tag like emacs-30.2 (If you desire to install another version, you can display tags using the git tag command) to ensure a stable foundation. Building from a tagged release, rather than the bleeding-edge development branch like the master branch, minimizes the risk of build failures or experimental regressions that could impact your daily productivity.

Standard cleanup is often insufficient when switching branches or recovering from a failed build. Execute the following commands to ensure a pristine environment where no residual artifacts can interfere with the new build:

git reset --hard HEAD
git clean -f -d -x
rm -fr .git/hooks/*Code language: plaintext (plaintext)

(Executing these commands acts as the ultimate factory reset for your repository, which is important when switching between major Emacs versions. Emacs has a highly complex build process where the C core compiles its own Lisp files; if leftover artifacts from a previous configuration, such as cached object files, old Makefiles, or stale byte-compiled .elc scripts, git hooks, are left behind, they can silently contaminate the new build and cause segmentation faults or compile-time errors. Together, these commands guarantee a pristine, predictable environment.)

Once inside the repository, all subsequent configuration and compilation commands are executed from this directory.

Step 2: Generating the Configuration Script

Emacs uses the Autotools build system, which requires generating the final configuration script before it can be used:

./autogen.shCode language: Bash (bash)

This shell script reads the developer configuration files provided in the repository and generates the final ./configure script. It sets up the necessary infrastructure to inspect your specific environment, locate system libraries, and prepare the Makefile.

Step 3: Setting Compiler and Linker Flags

To enhance runtime performance, we must export specific variables that instruct the C compiler and linker to optimize the resulting binary for the host CPU:

export CFLAGS="-O2 -pipe -march=native -mtune=native -fno-omit-frame-pointer -fno-plt -flto=auto"
export LDFLAGS="-Wl,-O2 -Wl,-z,now -Wl,-z,relro -Wl,--sort-common -Wl,--as-needed -Wl,-z,pack-relative-relocs -flto=auto -O2"Code language: Bash (bash)

The CFLAGS variable tells the compiler to apply safe, general-purpose optimizations (-O2), optimize instruction scheduling for the specific CPU compiling the code (-march=native and -mtune=native), store the metadata necessary for the linker to later perform cross-module optimization (-flto=auto), disable omit-frame-pointer (-fno-omit-frame-pointer), use memory pipes instead of temporary files to speed up the build (-pipe), and remove indirect PLT calls to external functions, improving runtime call efficiency at the cost of slightly higher startup and dynamic loading overhead (-fno-plt).

The LDFLAGS variable instructs the linker to apply additional optimization passes to the final executable (-Wl,-O2), group common symbols to reduce duplicate storage (-Wl,--sort-common), avoid linking unused shared libraries (-Wl,--as-needed), reduces binary size by performing a global analysis to inline functions and remove dead code across the entire program (-flto=auto), compress relative relocations to reduce relocation overhead and binary size (-Wl,-z,pack-relative-relocs), resolve all dynamic symbols at startup, trading slightly slower launch time for faster, more consistent runtime execution (-Wl,-z,now -Wl,-z,relro). Together, these flags help produce a smaller, more memory-efficient executable with improved startup and runtime performance.

NOTE 1: To successfully build Emacs using Link-Time Optimization (LTO) -flto, It is recommended to maintain a consistent optimization level, such as -O2, across both the compilation (CFLAGS) and linking stages (LDFLAGS). When enabling -flto=auto in your CFLAGS, the compiler emits GIMPLE intermediate representation; the actual transformation into an optimized executable is deferred until the linking phase, where the GCC driver re-invokes internal optimization passes. While modern GCC versions can often infer the correct heuristics from metadata embedded within the object files if a link-time flag is missing, explicitly including -O2 in your LDFLAGS is recommended for a predictable, deterministic build. This practice ensures that the whole-program analysis phase executes the exact same optimization level as the initial compilation. (Source: “To use the link-time optimizer, -flto and optimization options should be specified at compile time and during the final link. It is recommended that you compile all the files participating in the same link with the same options and also specify those options at link time…”)

NOTE 2: You must ensure CC are exported to the exact gcc version that matches your libgccjit version. For example: export CC="/usr/bin/gcc-11".

Step 4: Configuring the Build

We run the configure script to select exactly which features to include.

For X11 users:

./configure \
  --with-x \
  --with-x-toolkit=gtk3 \
  --without-toolkit-scroll-bars \
  --with-cairo \
  --without-xft \
  --with-harfbuzz \
  --without-libotf \
  --with-gnutls \
  --without-xdbe \
  --without-xim \
  --without-gpm \
  --disable-gc-mark-trace \
  --with-gsettings \
  --with-modules \
  --with-threads \
  --with-libgmp \
  --with-xml2 \
  --with-tree-sitter \
  --with-zlib \
  --without-included-regex \
  --with-native-compilation \
  --with-file-notification=inotify \
  --without-compress-installCode language: plaintext (plaintext)

For Wayland users:

./configure \
  --without-x \
  --with-pgtk \
  --with-toolkit-scroll-bars \
  --with-cairo \
  --without-xft \
  --with-harfbuzz \
  --without-libotf \
  --with-gnutls \
  --without-xdbe \
  --without-xim \
  --without-gpm \
  --disable-gc-mark-trace \
  --with-gsettings \
  --with-modules \
  --with-threads \
  --with-libgmp \
  --with-xml2 \
  --with-tree-sitter \
  --with-zlib \
  --without-included-regex \
  --with-native-compilation \
  --with-file-notification=inotify \
  --without-compress-installCode language: plaintext (plaintext)

The rationale behind the selection of these flags is as follows

  • --disable-gc-mark-trace: Disable the GC mark trace buffer for about 5% better garbage collection performance. It removes debugging code from the garbage collector marking phase. This provides a reduction in overhead during garbage collection cycles, leading to a more responsive experience during memory-intensive tasks.
  • --with-native-compilation Enable native compilation. (I omitted the aot flag to instruct the build system to skip compiling the built-in Lisp files during the make step. Instead, Emacs defers this work until runtime, where it will use the optimizations in native-comp-compiler-options and native-comp-driver-options while compiling all .el files the first time Emacs is launched.)
  • --with-cairo and --with-harfbuzz enable modern text rendering.
  • --without-compress-install By default, Emacs compresses its installed Lisp files to save disk space. Using this flag keeps the files uncompressed. The benefit is faster load times when Emacs needs to read these files from disk, as it skips the decompression step entirely. (On modern SSDs, loading compressed .el.gz files generally takes a bit more time than loading uncompressed files. While compression definitely saved time on older spinning hard drives by reducing I/O waits, modern solid-state drives can read uncompressed data at gigabytes per second. That being said, the actual performance gain of using uncompressed files is often negligible in practice. This is especially true if you are compiling all your .el files, because Emacs prefers to load the compiled byte-code .elc or native code .eln)
  • --without-xft Disable xft because modern Emacs rendering no longer needs it. Modern GTK builds of Emacs use Cairo + HarfBuzz handle rendering.
  • --without-included-regex Makes Emacs use the system libc regex implementation. On contemporary Linux systems using glibc, the system regex engine is usually better optimized and maintained than Emacs’s bundled GNU regex implementation.
  • --with-libgmp Enables GMP, the GNU Multiple Precision Arithmetic Library, an optimized engine Emacs relies on to calculate arbitrary-precision integers (bignums) at bare-metal speeds. Modern Emacs workflows constantly process massive numbers in the background. If you disable this flag or fail to install the system library, Emacs is forced to fall back on mini-gmp, a generic, software-only C implementation designed strictly for portability rather than speed.
  • --without-xim: Disable XIM, a legacy X Input Method protocol used primarily for typing complex languages (like Chinese, Japanese, or Korean) on old X11 systems. If you use GTK3/Wayland, modern input methods handle this instead. Disabling this is recommended for Wayland/PGTK users as it removes unnecessary X11-specific code.
  • --with-file-notification=inotify Guarantees that the build will use the Linux kernel’s efficient event-watching API rather than falling back to slow, resource-heavy polling if the detection fails.
  • --with-gsettings Enable communication with the GTK configuration storage system. This allows inheriting system-wide preferences for themes, fonts, antialiasing hints…
  • --without-libotf: Disables the legacy OpenType Font library. This is recommended for modern builds that use HarfBuzz (--with-harfbuzz), as HarfBuzz handles text shaping more efficiently. Disabling this library reduces binary size without sacrificing font quality in modern desktop environments.
  • --with-gnutls: Enables secure network communication. This is required for secure package installation from MELPA/ELPA and for browsing HTTPS websites via EWW.
  • --without-xdbe: Disables the X11 Double Buffer Extension. This protocol is redundant for modern builds because both the PGTK (Wayland) and GTK3 (X11) layers handle window buffering internally. Disabling it simplifies the binary and ensures Emacs uses modern rendering paths.
  • --without-gpm Disable General Purpose Mouse (GPM), a background service that provides mouse support for the Linux console (the text-only TTY you see before logging into a graphical desktop). Unless you plan to use Emacs in a bare-metal Linux console (outside of a terminal emulator like Alacritty, Foot, or GNOME Terminal), GPM is unnecessary. Modern terminal emulators use their own internal protocols for mouse interaction that do not rely on the GPM daemon.

Additional flags to pass to ./configure

If your workflow is primarily text-based, you can significantly reduce the number of external libraries linked to your binary. However, each omission comes with a specific trade-off:

  • --without-sound Disables support for audio notifications. You will not hear the audible system bell or sound cues from productivity packages like Pomodoro timers or chat clients.
  • --without-libsystemd Disables the ability for Emacs to communicate with systemd. You cannot use advanced systemd service features, such as Type=notify, which allows systemd to know exactly when the Emacs daemon is fully loaded and ready.
  • --without-dbus: Disables D-Bus integration in Emacs. This produces a slightly leaner build, but removes integration with desktop services that rely on D-Bus. Depending on the desktop environment and enabled packages, this can affect desktop notifications, interaction with services such as GNOME Keyring, file manager integration, power and network state notifications, and various portal-based desktop features. It is generally safe on minimal Emacs GUI builds or terminal-only setups, but many modern Linux desktop environments expect D-Bus support.
  • --without-gconf Disables support for GConf. This is a deprecated GNOME configuration system that was replaced by GSettings. Disabling it ensures your build is not carrying legacy, obsolete desktop integrations.
  • --without-sqlite3 Disables the built-in SQLite engine. This breaks modern packages that rely on a local database for performance, such as org-roam or certain mail indexers.
  • --without-m17n-flt Disables the m17n library for complex text layout. While fine for English-only workflows, this will cause rendering issues (incorrect character joining or positioning) for complex scripts like Indic or Thai.
  • --without-selinux Disables Security-Enhanced Linux support. On systems where SELinux is active, Emacs will be unable to preserve or manage SELinux security contexts when creating or copying files, potentially leading to permission issues or security policy violations.
  • --without-libsmack Disables Smack security support. Similar to SELinux, if your Linux distribution uses the Smack kernel security module, disabling this prevents Emacs from managing those specific security contexts on files.
  • --disable-build-details: Omits build metadata, such as your machine’s hostname and the compilation timestamp, from the final executable. While this doesn’t provides performance or startup speed benefits, it ensures a “reproducible build” and prevents your personal system details from leaking if you share your compiled binary.
  • --without-gif, --without-jpeg, --without-png, --without-rsvg, --without-tiff, --without-xpm, --without-webp Disabling these prevents Emacs from linking against heavy image processing libraries. Emacs will be unable to render these image formats natively. This breaks functionality for image-heavy modes, such as image-mode, viewing PDFs via pdf-tools, or displaying mathematical LaTeX previews.
  • --without-imagemagick Prevent Emacs from using this large dependency for complex image transformations. You lose the ability to perform advanced image manipulation (like dynamic resizing or rotation of certain formats) within Emacs buffers.
  • --without-lcms2 Remove the Little CMS color management layer. Images may appear with slightly incorrect colors on high-quality displays, as Emacs will ignore ICC color profiles embedded in files.
  • --without-xinput2: Disables the modern X11 input extension. Warning: If you are building for X11, disabling this will break pixel-precision smooth scrolling for trackpads and mouse wheels, forcing Emacs to use choppy line-by-line scrolling. This flag does nothing for Wayland/PGTK builds and offers no performance benefits.
  • --disable-acl: Disables support for Access Control Lists. Disabling this reduces the number of system calls Emacs performs during file operations. This is a good choice for single-user systems where standard Unix permissions are sufficient.
  • --disable-xattr: Disables support for Extended File Attributes. Only keep this enabled if you rely on SELinux or filesystem-level file tagging.
  • --without-kerberos --without-pop --without-kerberos5 --without-hesiod --without-mail-unlink: These flags disable support for ancient mail retrieval methods, directory services, and local mail spool manipulation. Because modern Emacs mail setups rely on external synchronization, disabling these ensures the build script does not waste time searching for legacy network libraries and keeps the binary entirely free of dead mail code.

Step 5: Compiling the Source Code

With the configuration complete, the next step is to compile the C source files and the core Emacs Lisp files:

make -j "$(nproc)" -l "$(nproc --ignore=1)"Code language: plaintext (plaintext)
  • -j $(nproc): This sets the maximum number of concurrent jobs to the number of CPU cores. Make will attempt to run up to the the number of CPU cores compilation commands in parallel. This is an upper bound; actual concurrency may be lower depending on dependencies and system load.
  • -l $(nproc --ignore=1): This sets a load average limit. $(nproc --ignore=1) returns the number of available CPU cores minus 1. Example: on an 8-core system, this evaluates to 7. So effectively, -l 7 means: do not start new jobs if system load average is 7 or higher. Make uses system load average (typically 1-minute load average) as a throttling mechanism.

On a low-load system, Make may run close to 48 jobs in parallel. Under high CPU pressure, Make will throttle and pause scheduling new jobs until load decreases.

(Related article: Similar to make -j command above for Emacs compilation, read “Enabling Emacs native compilation and dynamically adjusting the number of Elisp files compiled in parallel“)

Step 6: Installing the Stripped Binary

The final step is to copy the compiled binary and its associated files to their proper locations on your file system.

sudo make install-stripCode language: plaintext (plaintext)

While the standard make install simply copies the compiled files, make install-strip performs an additional optimization. It strips debugging symbols from the final executable. Removing these symbols reduces reduces binary size on disk.

Verifying Emacs Build Features

After successfully compiling Emacs from source, execute the resulting Emacs binary.

Once the editor is running, it is good practice to verify that your desired features, such as native JSON parsing or tree-sitter support, were correctly detected and linked during the build process.

You can verify this by inspecting the system-configuration-features variable. To view its contents, type M-x describe-variable RET system-configuration-features RET, which will output a string detailing the exact libraries and features baked into your current executable.

Optional: Risky Emacs Optimizations

Risky Optimization: Replacing -O2 with -O3

NOTE: The Emacs developers strongly recommend against using -O3, -Os, and -fsanitize=undefined for ordinary production builds, stating that these flags are known to sometimes cause unpredictable problems with the generated code. (Source: The INSTALL file in the Emacs source tree.) That said, I have compiled Emacs using -O3 and have not experienced any issues.

Here is how to apply this optimization:

  • Compiler configuration: Replace the -O2 flag with -O3 in your CFLAGS. (Avoid substituting -Wl,-O2 with -Wl,-O3 in your LDFLAGS, as the underlying GNU ld documents optimization levels up to -O2 for linker optimizations.)
  • Linker configuration: Replace the -O2 flag with -O3 in LDFLAGS.
  • Emacs configuration: Replace -O2 flag with -O3 in the native-comp-compiler-options variable.

The theoretical benefits of -O3:

  • Aggressive function Inlining: Function inlining speeds up execution by pasting a function’s code directly where it is called, eliminating the overhead of jumping to a different memory address.
  • Loop Unrolling: Loop unrolling is a compiler optimization that copies parts of a loop multiple times so the program does not need to repeatedly check conditions like i < 10 as often. This reduces repeated checks and jumps, allowing the CPU to spend more time performing useful work instead of constantly deciding whether to continue the loop. This creates longer uninterrupted sections of code, which modern processors can execute more efficiently by processing several independent operations in parallel at the same time.
  • Faster Buffer Processing (Vectorization/SIMD): For heavy text searching, such as complex regular expression matching or byte-level buffer manipulation, -O3 may allow the compiler to use special CPU instructions that operate on many bytes of data at once instead of processing each byte individually. For example, instead of comparing one character at a time, the CPU may compare 16, 32, or more characters in a single operation, which can improve performance in some workloads.

The tangible risks of -O3:

  • Instruction Cache Bloat: Aggressive inlining copies large amounts of code directly into other functions, which can significantly increase the size of the final executable.
  • Exposing Undefined Behavior: -O3 enables more aggressive optimizations that assume the C source code fully follows the rules of the C standard. In large and old codebases like Emacs, some code may accidentally rely on behavior that is technically invalid or undefined. When combined with Link-Time Optimization (LTO), the compiler can optimize across multiple source files and make transformations that expose these hidden issues, potentially causing random crashes, UI freezes, or unstable behavior.
  • Mangled Stack Traces: -O3 aggressively rearranges and simplifies code to improve performance. Functions may be merged, variables may disappear entirely, and instructions may execute in a very different order than they appear in the original source code. If Emacs crashes, debugging tools such as gdb may produce stack traces that no longer clearly match the original program structure, making debugging substantially more difficult.

Using -O3 is an experimental optimization. If you experience out-of-memory build failures, random micro-stutters, UI freezing, or crashes, revert to a standard -O2 build with or without LTO.

Conclusion

Compiling Emacs from source and bypassing generic Emacs distribution binaries strips away decades of legacy compatibility layers and align the Emacs’ execution directly with your specific hardware architecture.

Remember to trigger a fresh recompilation whenever you update core system toolchains, such as GCC or your graphical compositor, to maintain binary compatibility and performance integrity.

Easily Toggle an Emacs Terminal with a Single Keystroke using shell-pop (Recently Refactored)

The shell-pop Emacs package provides on-demand access to a terminal buffer via a single, configurable key binding. It allows toggling a terminal window without disrupting the workspace layout, making it a useful tool for quick command-line tasks.

NOTE: Kazuo Yagi, the shell-pop original author, appointed me as a co-maintainer of shell-pop Emacs package. I recently refactored shell-pop to improve robustness, fix bugs, and add support for additional terminals (vterm and eat). Stepping into the maintainer role gave me the opportunity to give the codebase a thorough refactoring.

Why use shell-pop?

Adding shell-pop to your workflow offers the following benefits:

  • Your terminal session remains active in the background, retaining your command history and running processes.
  • It can automatically change the terminal directory to match the file or project you are currently visiting in Emacs.
  • Toggling the shell does not ruin your carefully arranged window splits. (Especially when shell-pop-full-span is set to set to t)
  • It supports a wide variety of terminal emulators (term, eshell, ansi-term, vterm, and eat).
  • It provides control over the terminal window layout, allowing you to specify its exact size as a percentage, define its position (top, bottom, left, right, or full screen), and choose whether it should span the entire width of the frame.
  • It handles cleanup gracefully by automatically killing the terminal buffer and safely deleting its window when the underlying shell process exits.
  • It includes a comprehensive set of lifecycle hooks (for opening, closing, and exiting), allowing you to trigger custom Emacs Lisp functions automatically based on the terminal state.

Installation and configuration

To install shell-pop from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.
  2. Add the following code to your Emacs init file to install shell-pop from MELPA:
(use-package shell-pop
  ;; :bind automatically sets up the keybinding AND tells Emacs to lazy-load the
  ;; package the moment the key is pressed.
  :bind (("C-c t" . shell-pop))
  :custom
  ;; The key sequence used to toggle the shell window.
  (shell-pop-universal-key "C-c t")

  ;; Sets the screen position where the shell popup appears.
  ;; You can choose "bottom", "top", "right", "left", or "full".
  (shell-pop-window-position "bottom")

  ;; If non-nil, the window stretches across the entire frame width.
  (shell-pop-full-span nil)

  ;; The path to the shell executable used by the terminal emulator
  ;; (e.g., "/usr/bin/env bash").
  (shell-pop-term-shell shell-file-name)

  ;; The height or width of the window as a percentage of the frame.
  (shell-pop-window-size 30)

  ;; Setting this to non-nil sends commands to the shell. This is not always
  ;; desirable, as it can send commands to any prompt.
  (shell-pop-autocd-to-working-dir nil))Code language: Lisp (lisp)

Configuring the terminal

Here are the exact configurations for the most popular Emacs shells. Simply copy and paste your preferred option into your init file:

ansi-term

(with-eval-after-load 'shell-pop
  (setopt shell-pop-shell-type '("ansi-term" "*ansi-term*"
                                 (lambda ()
                                   (ansi-term shell-pop-term-shell)))))Code language: Lisp (lisp)

term

(with-eval-after-load 'shell-pop
  (setopt shell-pop-shell-type '("terminal" "*terminal*"
                                 (lambda ()
                                   (term shell-pop-term-shell)))))Code language: Lisp (lisp)

vterm

Note: Requires the vterm package to be installed.

(with-eval-after-load 'shell-pop
  (setopt shell-pop-shell-type '("vterm" "*vterm*"
                                 (lambda ()
                                   (when (fboundp 'vterm)
                                     (let ((vterm-shell shell-pop-term-shell))
                                       (vterm)))))))Code language: Lisp (lisp)

eat

Note: Requires the eat package to be installed.

(with-eval-after-load 'shell-pop
  (setopt shell-pop-shell-type '("eat" "*eat*"
                                 (lambda ()
                                   (when (fboundp 'eat)
                                     (eat shell-pop-term-shell))))))Code language: Lisp (lisp)

Enhancements that I implemented as co-maintainer

If you are a long-time shell-pop user, here are the changes I recently made to the package. I encourage you to try the latest version and send Kazuo Yagi and me your feedback in the issue tracker:

  • I added support for the vterm and eat terminals, two highly requested modern terminal emulators. This includes implementing automatic directory synchronization to ensure the shell always matches the current working directory in Emacs.
  • Previously, the package relied on global variables and buffer deletion to manage window states. This caused unpredictable behavior when using complex layouts, multiple frames, or tabs. I refactored shell-pop to isolate state tracking by attaching it directly to Emacs window parameters.
  • I resolved issues related to zombie buffers and asynchronous window hijacking. The code now stores buffer objects instead of names, scopes process sentinels strictly to the shell window, and correctly verifies buffer lifespans before attempting restoration.
  • The toggle functionality now correctly recognizes active shell windows even when the cursor is focused elsewhere in the frame, preventing redundant terminal pop-ups.
  • I fixed a directory desync bug by unconditionally enforcing auto cd. Emacs will no longer lose track of the shell’s actual working directory if a user manually changes directories inside the terminal.
  • The teardown routines were adjusted to ensure native terminal cleanup processes, such as writing Eshell history, execute fully before the buffer is destroyed.
  • I replaced the simulated Ctrl-L keystroke with an explicit clear command to prevent literal ^L characters from printing in the terminal input buffer.
  • The hard dependency on the term package is now optional. Users who prefer vterm, eat, standard shells or Eshell are no longer forced to load unnecessary terminal packages on startup.

Conclusion

Taking on a maintenance role for a tool I use daily has been an interesting experience. These recent updates aim to make shell-pop more reliable and modern. I encourage you to try the latest version and send us your feedback.

The Definitive Guide to Code Folding in Emacs

Navigating large source files containing thousands of lines of code with Emacs makes it difficult to perceive the underlying structure. For a software engineer spending the majority of the day reading and writing code, reliable folding is a requirement for maintaining focus and managing complexity.

Before we dive in, please consider sharing this article on your website/blog, Mastodon, Reddit, X, or your preferred social media platforms. Sharing it will help fellow Emacs users discover better ways to manage code folding.

In this article, we explore:

  • A folding Frontend: Consolidating folding commands into a single, predictable keymap that operates consistently across all code folding modes.
  • Folding Backends: Ready-to-use hooks to activate the most effective folding backend for the following major modes: C, C++, Java, Rust, Go, Python, JavaScript, TypeScript, Emacs Lisp, shell scripts, Lua, Haskell, YAML, Org-mode, Markdown…
  • Editor Integration: Using indirect buffers to maintain independent folding states, configuring search operations to strictly ignore folded text, and setting up display-line-numbers-mode…
  • Discouraged Folding Engines: A review of legacy or poorly performing packages to avoid.

Why code folding?

Code folding is about managing cognitive load, preserving spatial memory, and controlling screen real estate:

  • Navigating through code (e.g., with LSP) can create a vacuum of context. Folding an entire file to its top-level headings allows the manipulation of the file skeleton directly in the main buffer. Revealing only a specific entry and its parents provides an immediate understanding of the hierarchy without losing position.
  • When tasked with debugging a 20,000 line legacy file, immediate refactoring is rarely an option. Folding enables the visual modularization of massive files on the fly, making hostile codebases readable.
  • Every visible line of code on the screen requires a fraction of subconscious attention to ignore. During debugging sessions, folding adjacent functions or complex implementations acts as a visual garbage collector.
  • Moving or deleting a massive function or block is prone to selection errors. When a block is folded, it behaves as a single logical unit that can be cut, copied, or moved safely and cleanly.
  • Folding is effective for tracking progress during extensive pull requests. Collapsing previously examined functions or blocks actively filters out visual noise.

Code Folding Frontend

The primary drawback of code folding modes is inconsistency. For example, hs-minor-mode and outline-minor-mode use entirely different functions and keybindings to perform the exact same logical action.

The solution is a package called kirigami, which acts as a universal frontend for text folding. You define your keybindings once, and kirigami automatically detects the active folding and routes your commands to the appropriate engine, whether that is outline-minor-mode, outline-indent-minor-mode, org-mode, markdown-mode, gfm-mode, treesit-fold-mode, hs-minor-mode (hideshow), and many others…

To install and configure kirigami, add the following code to your Emacs init file:

(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
  ;; Vanilla Emacs keybindings
  (("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 a" . kirigami-toggle-fold)))      ; Toggle fold at pointCode language: Lisp (lisp)

If you are an evil-mode user, add the following keybindings to your init file:

;; 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))Code language: Lisp (lisp)

In addition to providing a unified interface, the kirigami package enhances folding behavior in outline, markdown-mode, and org-mode packages. It ensures that deep folds and sibling folds open and close reliably.

Code Folding Backends

A code folding backend is the underlying engine that handles the logic of identifying and hiding specific blocks of text. While the kirigami package provides the user interface and keybindings, it requires a backend, such as outline-minor-mode or hs-minor-mode, to perform the folding.

NOTE: When configuring folding backends, ensure that only one folding minor mode is active concurrently in a single buffer, as conflicts and unexpected behavior may occur. For this reason, adding folding hooks to broad categories like prog-mode-hook or text-mode-hook is discouraged. Instead, hooks should be applied specifically to individual language modes, such as emacs-lisp-mode-hook.

Below are ready-to-use hooks to activate the optimal folding backend for each major mode:

Outline (built-in)

outline-minor-mode relies on hierarchical headings to determine collapsible sections. It is effective for structured text and is my default choice for Elisp, Lisp, Markdown, Diff, and configuration files.

(add-hook 'emacs-lisp-mode-hook #'outline-minor-mode)
(add-hook 'lisp-interaction-mode-hook #'hs-minor-mode) ; scratch
(add-hook 'lisp-mode-hook #'outline-minor-mode)
(add-hook 'conf-mode-hook #'outline-minor-mode)
(add-hook 'markdown-mode-hook #'outline-minor-mode)
(add-hook 'diff-mode-hook #'outline-minor-mode)Code language: Lisp (lisp)

Hideshow (built-in)

hs-minor-mode parses buffer syntax to accurately detect the start and end of blocks. It is the best tool for C-style languages, or anything using braces {} and explicit block structures like sh/Bash shell scripts.

;; Systems and General Purpose
(add-hook 'c-mode-hook #'hs-minor-mode)
(add-hook 'c++-mode-hook #'hs-minor-mode)
(add-hook 'java-mode-hook #'hs-minor-mode)
(add-hook 'rust-mode-hook #'hs-minor-mode)
(add-hook 'go-mode-hook #'hs-minor-mode)
(add-hook 'ruby-mode-hook #'hs-minor-mode)
(add-hook 'php-mode-hook #'hs-minor-mode)
(add-hook 'perl-mode-hook #'hs-minor-mode)

;; Web and Frontend
(add-hook 'js-mode-hook #'hs-minor-mode)
(add-hook 'typescript-mode-hook #'hs-minor-mode)
(add-hook 'css-mode-hook #'hs-minor-mode)

;; Scripting, Data, and Infrastructure
(add-hook 'sh-mode-hook #'hs-minor-mode) ; for bash/shell scripts
(add-hook 'json-mode-hook #'hs-minor-mode)
(add-hook 'lua-mode-hook #'hs-minor-mode)
(add-hook 'nxml-mode-hook #'hs-minor-mode)
(add-hook 'html-mode-hook #'hs-minor-mode)  ;; mhtml and htmlCode language: Lisp (lisp)

hs-minor-mode folds a single level at a time, such as entire functions, without providing convenient access to nested blocks. This makes it less practical for languages that require deep folding, such as YAML, where multiple nested levels are common. Even in languages like Python, Hideshow can be impractical, because it allows folding classes but does not provide convenient folding for the functions within those classes for example.

Outline-indent

The outline-indent package provides code folding based on indentation levels. It is recommended for Python, Haskell, and YAML because it supports an unlimited number of folding levels. For instance, it allows folding an entire function or specific nested blocks within that function, such as if statements inside while loops.

(use-package outline-indent
  :commands outline-indent-minor-mode
  :custom
  (outline-indent-ellipsis " ▼"))

;; Python
(add-hook 'python-mode-hook #'outline-indent-minor-mode)
(add-hook 'python-ts-mode-hook #'outline-indent-minor-mode)

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

;; Haskell
(add-hook 'haskell-mode-hook #'outline-indent-minor-mode)Code language: Lisp (lisp)

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, and moving backward/forward to the indentation level of the current line.

Treesit-fold

The treesit-fold package provides Intelligent code folding by using 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.

(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))

;; Systems and General Purpose
(add-hook 'c-ts-mode-hook #'treesit-fold-mode)
(add-hook 'c++-ts-mode-hook #'treesit-fold-mode)
(add-hook 'java-ts-mode-hook #'treesit-fold-mode)
(add-hook 'rust-ts-mode-hook #'treesit-fold-mode)
(add-hook 'go-ts-mode-hook #'treesit-fold-mode)
(add-hook 'ruby-ts-mode-hook #'treesit-fold-mode)
(add-hook 'php-ts-mode-hook #'treesit-fold-mode)
(add-hook 'csharp-ts-mode-hook #'treesit-fold-mode)
(add-hook 'go-mod-ts-mode-hook #'treesit-fold-mode)
(add-hook 'lua-ts-mode-hook #'treesit-fold-mode)

;; Web and Frontend
(add-hook 'js-ts-mode-hook #'treesit-fold-mode)
(add-hook 'typescript-ts-mode-hook #'treesit-fold-mode)
(add-hook 'tsx-ts-mode-hook #'treesit-fold-mode)
(add-hook 'css-ts-mode-hook #'treesit-fold-mode)
(add-hook 'html-ts-mode-hook #'treesit-fold-mode)
(add-hook 'heex-ts-mode-hook #'treesit-fold-mode)
(add-hook 'xml-ts-mode-hook #'treesit-fold-mode)

;; Scripting and Infrastructure
(add-hook 'bash-ts-mode-hook #'treesit-fold-mode)
(add-hook 'cmake-ts-mode-hook #'treesit-fold-mode)
(add-hook 'dockerfile-ts-mode-hook #'treesit-fold-mode)
(add-hook 'awk-ts-mode-hook #'treesit-fold-mode)
(add-hook 'vimscript-ts-mode-hook #'treesit-fold-mode)
(add-hook 'nix-ts-mode-hook #'treesit-fold-mode)

;; Data and Configuration
(add-hook 'json-ts-mode-hook #'treesit-fold-mode)
(add-hook 'toml-ts-mode-hook #'treesit-fold-mode)

;; Build Systems and Makefiles
(add-hook 'makefile-ts-mode-hook #'treesit-fold-mode)

;; Hardware Description and Shaders
(add-hook 'verilog-ts-mode-hook #'treesit-fold-mode)
(add-hook 'vhdl-ts-mode-hook #'treesit-fold-mode)
(add-hook 'hlsl-ts-mode-hook #'treesit-fold-mode)

;; Scientific, Data Science, and Academic
(add-hook 'latex-ts-mode-hook #'treesit-fold-mode)
(add-hook 'beancount-ts-mode-hook #'treesit-fold-mode)

;; Documentation and Diagrams
(add-hook 'markdown-ts-mode-hook #'treesit-fold-mode)
(add-hook 'mermaid-ts-mode-hook #'treesit-fold-mode)
 
;; Other
(add-hook 'gdscript-ts-mode-hook #'treesit-fold-mode)
(add-hook 'clojure-ts-mode-hook #'treesit-fold-mode)
(add-hook 'caml-ts-mode-hook #'treesit-fold-mode)
(add-hook 'ocaml-ts-mode-hook #'treesit-fold-mode)
(add-hook 'erlang-ts-mode-hook #'treesit-fold-mode)
(add-hook 'elixir-ts-mode-hook #'treesit-fold-mode)
(add-hook 'scala-ts-mode-hook #'treesit-fold-mode)
(add-hook 'dart-ts-mode-hook #'treesit-fold-mode)
(add-hook 'haskell-ts-mode-hook #'treesit-fold-mode)
(add-hook 'julia-ts-mode-hook #'treesit-fold-mode)
(add-hook 'kotlin-ts-mode-hook #'treesit-fold-mode)
(add-hook 'gleam-ts-mode-hook #'treesit-fold-mode)
(add-hook 'noir-ts-mode-hook #'treesit-fold-mode)
(add-hook 'swift-ts-mode-hook #'treesit-fold-mode)
(add-hook 'zig-ts-mode-hook #'treesit-fold-mode)Code language: Lisp (lisp)

For the treesit-fold block to function, you must be using Emacs 29.1 or newer, and you must have the actual Tree-sitter grammars installed on your machine for those specific languages.

Markdown-mode

The markdown-mode package provides a major mode 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). Markdown-mode and gfm-mode support outline-minor-mode folding.

(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)))

;; Hooks
(add-hook 'markdown-mode-hook #'outline-minor-mode)Code language: Lisp (lisp)

Maintaining independent folding states in separate windows via indirect buffers (clones)

Opening the same buffer in multiple windows results in synchronized folding states; any folding or unfolding action performed in one window is immediately reflected in all others.

This occurs because folding engines use buffer-local overlays, which are shared across all windows associated with that specific buffer.

Indirect buffers provide a robust solution to this limitation. An indirect buffer shares the underlying text of its parent buffer but maintains an independent set of overlays. This distinction allows for the maintenance of different folding configurations for the same file simultaneously.

To create an indirect buffer (clone) of the current buffer in a separate window, execute:

M-x clone-indirect-buffer-other-windowCode language: plaintext (plaintext)

Creating an indirect buffer provides a separate buffer object that references the same text while maintaining its own isolated set of opened/closed folds.

Persisting and restoring folding state across sessions with savefold

By default, Emacs does not preserve the state of your folds when you close a buffer or exit the editor. The savefold package resolves this limitation. It records the positions of opened and closed folds to disk, automatically restoring them when a file is reopened.

The package integrates with most overlay-based folding frameworks. Currently supported systems include outline, org-mode, markdown-mode, hideshow, treesit-fold, ts-fold, etc.

To install and activate savefold globally using use-package, add the following snippet to your initialization file.

(use-package savefold
  :init
  ;;  list of symbols indicating active backends. Default: '(outline)
  (setq savefold-backends '(outline org hideshow treesit-fold markdown))

  ;; The directory path where the serialization files are stored.
  (setq savefold-directory (locate-user-emacs-file "savefold"))

  ;; When using `savefold' alongside `org-mode', configure the default Org startup
  ;; visibility to ensure that the saved state applies correctly without
  ;; conflicting with internal Org visibility cycles:
  (setq org-startup-folded 'showeverything)

  :config
  (savefold-mode 1))Code language: Lisp (lisp)

Preventing Emacs search from matching text within folded blocks

Note: This setting is for users who want search operations to ignore folded blocks instead of expanding them. This behavior is subjective and may not suit every workflow.

By default, search operations can match text within folded blocks, which often causes Emacs to automatically expand the hidden content.

To instruct Emacs to strictly ignore invisible text during search operations, add the following configuration to your init file:

(setq-default search-invisible nil)Code language: Lisp (lisp)

Alternatively, to restrict this behavior to specific modes, apply a buffer-local configuration via a mode hook:

(add-hook 'prog-mode-hook (lambda ()
                            (setq-local search-invisible nil)))Code language: Lisp (lisp)

Integrating display-line-numbers-mode with code folding

The built-in display-line-numbers-mode renders line numbers in the side margin of the window. By default, it uses absolute line numbering, which tracks the absolute line count in the buffer. Consequently, when a block is folded, the line numbers skip the hidden range (e.g., jumping from 15 to 120).

For users who prefer visual line numbering, display-line-numbers-mode can be configured to ignore collapsed content and assign numbers sequentially based only on what is currently rendered on the screen.

To implement visual line numbering as your global default, set the following variable in your configuration:

(setq-default display-line-numbers-type 'visual)Code language: Lisp (lisp)

(Note that you must still enable the mode itself using M-x global-display-line-numbers-mode for the line numbers to appear.)

Discouraged Emacs Folding Engines

Choosing an appropriate folding engine is important for maintaining performance and stability within Emacs. While several third-party and legacy options exist, the following packages and methods are generally discouraged in favor of more modern or integrated alternatives:

  • Origami: This package is slow and largely unmaintained. Origami uses a non-standard API and a complex implementation that frequently conflicts with other overlay-based minor modes. Its overhead can lead to performance degradation, especially when handling large buffers or deeply nested code. (Modern alternatives to origami: outline-indent, treesit-fold, outline-minor-mode, hs-minor-mode)
  • Yafolding: This package is also unmaintained and suffers from performance issues. (Modern alternative to yafolding: outline-indent)
  • Semantic (CEDET): Part of the legacy CEDET suite, Semantic folding is widely regarded as heavyweight. The parsing overhead required for its operation often introduces noticeable latency, making it vastly less efficient than modern built-in alternatives like Tree-sitter. (Modern alternatives to CEDET code folding: treesit-fold, outline-minor-mode, hs-minor-mode, outline-indent)
  • Selective Display (set-selective-display): This is Emacs’ oldest built-in folding method (often bound to C-x $). It causes unpredictable cursor jumping, and lacks any contextual awareness.
  • Folding-mode: This ancient package relies on explicit structural markers placed manually inside code comments (e.g., {{{ and }}}). While robust for the user, markers pollute the source code with editor-specific metadata. This is heavily frowned upon in modern collaborative environments where team members use varying IDEs.
  • Vimish-fold: Although useful for manual, ad-hoc text folding, vimish-fold is not recommended as a primary automated folding engine. Unlike Vim’s set foldmethod=marker, the vimish-fold implementation does not support recursive markers, such as {{{ inside of {{{. Additionally, like folding-mode, vimish-fold also uses markers that pollute the source code with editor-specific markers, a practice discouraged in collaborative environments where team members use a variety of editors and IDEs.

Conclusion

Establishing a unified folding interface in Emacs converts a buffer into a structured environment. Whether you are refactoring complex Python classes or navigating extensive Org documents, relying on a standardized command set simplifies the experience. Integrating the hooks outlined in this article ensures you enable the optimal backend for each major mode, allowing you to focus on logic rather than editor mechanics.

buffer-guardian.el – Automatically Save Emacs Buffers Without Manual Intervention (When Buffers Lose Focus, Regularly, or After Emacs is Idle)

Build Status License MELPA MELPA Stable

The buffer-guardian Emacs package provides buffer-guardian-mode, a global mode that automatically saves buffers without requiring manual intervention.

By default, buffer-guardian-mode saves file-visiting buffers when:

  • Switching to another buffer.
  • Switching to another window or frame.
  • The window configuration changes (e.g., window splits).
  • The minibuffer is opened.
  • Emacs loses focus.

(Skip to: Installation)

In addition to regular file-visiting buffers, buffer-guardian-mode also handles specialized editing buffers used for inline code blocks, such as org-src (for Org mode) and edit-indirect (commonly used for Markdown source code blocks). These temporary buffers are linked to an underlying parent buffer. Automatically saving them ensures that modifications made within these isolated code environments are correctly propagated back to the original Org or Markdown file.

The buffer-guardian-mode automatically detects active completion interfaces, such as corfu or completion-in-region-mode, and suppresses background save operations (controlled by the variable buffer-guardian-inhibit-save-on-completion, which defaults to t). This prevents premature auto-save triggers from invoking external hooks like automated code formatters, linters, or language server processes, which eliminates potential UI latency or race conditions.

If this package enhances your workflow, please show your support by ⭐ starring buffer-guardian on GitHub to help more users discover its benefits.

Other features that are disabled by default:

  • Save the buffer even if a window change results in the same buffer being selected. (Variable: buffer-guardian-save-on-same-buffer-window-change)
  • Save all file-visiting buffers periodically at a specific interval. (Variable: buffer-guardian-save-all-buffers-interval)
  • Save all file-visiting buffers after a period of user inactivity. (Variable: buffer-guardian-save-all-buffers-idle)
  • Pre-save buffers silently before global save and exit commands. (Variable: buffer-guardian-override-save-some-buffers)
  • Prevent auto-saving remote files. (Variable: buffer-guardian-inhibit-saving-remote-files)
  • Prevent saving files that do not exist on disk. (Variable: buffer-guardian-inhibit-saving-nonexistent-files)
  • Set a maximum buffer size limit for auto-saving. (Variable: buffer-guardian-max-buffer-size)
  • Ignore buffers whose names match specific regular expressions. (Variable: buffer-guardian-exclude-regexps)
  • Use custom predicate functions to determine if a buffer should be saved. (Variable: buffer-guardian-predicate-functions)

(Buffer Guardian runs in the background without interrupting the workflow. For example, the package safely aborts the auto-save process if the file is read-only, if the file’s parent directory does not exist, or if the file was modified externally. It also implements a dual-edge debouncing mechanism that fires an immediate synchronous save on the first trigger and a final trailing save when user activity stops, completely preventing editor freezes and saving race conditions. Additionally, it gracefully catches and logs errors if a third-party hook attempts to request user input, ensuring that the editor never freezes during an automatic background save.)

Installation

To install buffer-guardian from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install buffer-guardian from MELPA:

(use-package buffer-guardian
  :custom
  ;; When non-nil, include remote files in the auto-save process
  (buffer-guardian-inhibit-saving-remote-files t)

  ;; When non-nil, buffers visiting nonexistent files are not saved
  (buffer-guardian-inhibit-saving-nonexistent-files nil)

  ;; Save the buffer even if the window change results in the same buffer
  (buffer-guardian-save-on-same-buffer-window-change t)

  ;; Non-nil to enable verbose mode to log when a buffer is automatically saved
  (buffer-guardian-verbose nil)

  ;; Pre-save all package-managed buffers before native save commands run
  ;; Advise `save-some-buffers' to use `buffer-guardian' logic.
  ;; When non-nil and `buffer-guardian-mode' is active, this intercepts
  ;; `save-some-buffers' to silently pre-save package-managed buffers before
  ;; allowing the native command to run normally.
  (buffer-guardian-override-save-some-buffers nil)

  ;; Save all buffers after N seconds of user idle time. (Disabled by default)
  ;; (buffer-guardian-save-all-buffers-idle 30)

  ;; Save all buffers every N seconds. (Disabled by default)
  ;; (setq buffer-guardian-save-all-buffers-interval (* 60 30))

  :hook
  (after-init . buffer-guardian-mode))

Configuration

You can customize buffer-guardian to fit your workflow. Below are the main customization variables:

Triggers

  • buffer-guardian-save-on-focus-loss (Default: t): Save when the Emacs frame loses focus.
  • buffer-guardian-save-on-minibuffer-setup (Default: t): Save when the minibuffer opens.
  • buffer-guardian-save-on-buffer-switch (Default: t): Save when window-buffer-change-functions runs.
  • buffer-guardian-save-on-window-selection-change (Default: t): Save when window-selection-change-functions runs.
  • buffer-guardian-save-on-window-configuration-change (Default: t): Save when window-configuration-change-hook runs.
  • buffer-guardian-save-on-same-buffer-window-change (Default: nil): Save the buffer even if the window change results in the same buffer.

Timers

  • buffer-guardian-save-all-buffers-interval (Default: nil): Save all buffers periodically every N seconds.
  • buffer-guardian-save-all-buffers-idle (Default: nil): Save all buffers after N seconds of user idle time.

Exclusions and Filters

  • buffer-guardian-inhibit-saving-remote-files (Default: t): Prevent auto-saving remote files.
  • buffer-guardian-inhibit-saving-nonexistent-files (Default: t): Prevent saving files that do not exist on disk.
  • buffer-guardian-exclude-regexps (Default: nil): A list of regular expressions for file names to ignore.
  • buffer-guardian-max-buffer-size (Default: nil): Maximum buffer size (in characters) to save. Set to 0 or nil to disable.
  • buffer-guardian-predicate-functions (Default: nil): List of predicate functions to determine if a buffer should be saved.

Specialized Buffers (Inline Code Blocks)

  • buffer-guardian-handle-org-src (Default: t): Enable automatic saving for org-src buffers.
  • buffer-guardian-handle-edit-indirect (Default: t): Enable automatic saving for edit-indirect buffers.

Advanced

  • buffer-guardian-override-save-some-buffers (Default: nil): Advises save-some-buffers to execute a silent save of all buffers before letting the native save-some-buffers logic run. When this option is enabled, triggering commands like save-buffers-kill-emacs cleanly writes your modified project files to disk first, drastically minimizing or entirely bypassing subsequent interactive prompts for those buffers.
  • buffer-guardian-save-all-buffers-trigger-hooks: A list of hooks that trigger saving all modified buffers. Defaults to nil.
  • buffer-guardian-save-trigger-functions: A list of functions to advise. A :before advice will save the current buffer before these functions execute.
  • buffer-guardian-verbose (Default: nil): Enable logging messages when a buffer is saved.

Manual Saving Without Interruption

While buffer-guardian-mode handles background saves automatically, you can explicitly force a safe, background-style save at any time using the buffer-guardian-save-buffer command.

Replacing the default Emacs save-buffer with this command provides several direct improvements to your daily editing workflow:

  • It actively guards against overwriting external changes. If a file is modified outside of Emacs, the command gracefully intercepts the save operation and presents clear, interactive choices to discard your edits, force an overwrite, or cancel safely.
  • Running it inside temporary or isolated buffers like org-src (for Org mode source blocks) or edit-indirect (for Markdown code blocks) correctly commits changes straight back to the underlying parent file.

To replace the standard Emacs save shortcut globally with this alternative, add the following snippet to your configuration:

(keymap-global-set "C-x C-s" #'buffer-guardian-save-buffer)

Author and License

The buffer-guardian Emacs package 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) 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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.

pathaction.el: An Emacs package for executing pathaction rules, the universal Makefile for the entire filesystem

Build Status License

The pathaction.el Emacs package provides an interface for executing .pathaction.yaml rules directly from Emacs through the pathaction cli, a flexible tool for running commands on files and directories.

Think of pathaction like a Makefile for any file or directory in the filesystem. It uses a .pathaction.yaml file to figure out which command to run, and you can even use Jinja2 templating to make those commands dynamic. You can also use tags to define multiple actions for the exact same file type, like setting up one tag to run a script, and another to debug it.

This tool is for software developers who manage multiple projects across diverse ecosystems and want to eliminate the cognitive load of switching between different build tools, environment configurations, and deployment methods. Just run one single command on any file and trust that it gets handled correctly.

If this package helps your workflow, please show your support by ⭐ starring pathaction.el on GitHub to help more software developers discover its benefits.

Requirements

Installation

To install pathaction from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install pathaction from MELPA:

(use-package pathaction
  :config
  (add-to-list 'display-buffer-alist '("\\*pathaction:"
                                       (display-buffer-at-bottom)
                                       (window-height . 0.33))))

Usage

Allow the directory

By default, pathaction does not read rule-set files such as .pathaction.yaml from arbitrary directories. The target directory must be explicitly permitted.

For example, to allow Pathaction to load .pathaction.yaml rules from ~/projects and its subdirectories, run the following command:

pathaction --allow-dir ~/projects

Run

To execute the pathaction action that is tagged with main, you can call the following Emacs function:

(pathaction-run "main")
  • pathaction-run: This is the main function for triggering pathaction actions.
  • "main": This is the tag used to identify a specific action. The tag you provide to the function determines which set of actions will be executed. In this case, "main" refers to the actions that are specifically tagged with this name.

Edit .pathaction.yaml

To edit a .pathaction.yaml file located in a parent directory, run the command: M-x pathaction-edit

The command prompts for selection of one of the rule-set files found in the current directory or in one of its parent directories.

Customization

Configuration Options

pathaction-term-shell (Default: explicit-shell-file-name or shell-file-name)

The shell used by the terminal emulator to execute the pathaction command (e.g., "/bin/bash" or "/bin/zsh").

pathaction-term-function (Default: #'pathaction-ansi-term)

The function used to create and execute the terminal. By default, it uses #'pathaction-ansi-term. You can customize this to use faster, third-party terminal emulators like:

  • #'pathaction-eat
  • #'pathaction-vterm

pathaction-cleanup-buffer-at-process-exit (Default: t)

If non-nil, automatically closes the terminal and kills the buffer when the process exits. Set this to nil if you want the window to remain open so you can inspect the output.

pathaction-close-window-after-execution (Default: t)

If non-nil, the pathaction window will be closed once execution is complete.

pathaction-keep-buffer-when-process-running (Default: t)

If non-nil, keeps hidden pathaction buffers alive if they have an active process.

Making pathaction open a window under the current one

To configure pathaction to open its window under the current one, you can use the display-buffer-alist variable to customize how the pathaction buffer is displayed. Specifically, you can use the display-buffer-at-bottom action, which will display the buffer in a new window at the bottom of the current frame.

Here’s the code to do this:

(add-to-list 'display-buffer-alist '("\\*pathaction:"
                                     (display-buffer-at-bottom)
                                     (window-height . 0.33)))

Hooks

  • pathaction-before-run-hook: This hook is executed by pathaction-run before the pathaction command is executed.
  • pathaction-after-create-buffer-hook: This hook is executed after the pathaction buffer is created. It runs from within the pathaction buffer, enabling further customization or actions once the buffer is available.

Saving all buffers before executing pathaction

By default, pathaction-before-run-hook only calls the pathaction-save-buffer function to save the current buffer before executing actions or commands that affect the current or any other edited buffer.

To make pathaction save all buffers, use the following configuration:

(defun my-save-some-buffers ()
  "Prevent `save-some-buffers' from prompting by passing 1 to it."
  ;; The first argument means to save all buffers without prompting
  (save-some-buffers t))

(add-hook 'pathaction-before-run-hook #'my-save-some-buffers)

Author and License

The pathaction Emacs package 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) 2025-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.

Links

  • pathaction.el, an Emacs package that allows executing the pathaction command-line tool directly from Emacs.
  • The pathaction command-line tool (requirement): pathaction cli
  • For Vim users: vim-pathaction, a Vim plugin that allows executing the pathaction command-line tool directly from Vim.

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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

ultisnips-mode.el: An Emacs major mode for editing Ultisnips snippet files (*.snippets files)

Build Status MELPA MELPA Stable License

The ultisnips-mode is an Emacs major mode for editing Ultisnips snippet files (*.snippets files). This mode provides syntax highlighting to facilitate editing Ultisnips snippets.

(Vim’s UltiSnips is a snippet solution for Vim, and its snippets can be used in Emacs by converting them to the Yasnippet format using Ultyas.)

Features

  • Syntax highlighting for UltiSnips: snippet, endsnippet, global, endglobal, priority, comments, and placeholders in the form of ${1:value} or $1
  • Integration with outline-minor-mode or hs-minor-mode to enable folding of snippet -> endsnippet and global -> endglobal blocks.
  • Support for commenting and uncommenting UltiSnips snippets using standard Emacs commands, such as comment-or-uncomment-region.
  • Add *.snippets to auto-mode-alist to automatically enable ultisnips-mode.

Installation

To install ultisnips-mode from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install ultisnips-mode from MELPA:

(use-package ultisnips-mode
  :commands ultisnips-mode
  :mode ("\\.snippets\\'" . ultisnips-mode))

Frequently Asked Questions

Folding snippet blocks with hs-minor-mode

Activating hs-minor-mode provides the ability to collapse and expand snippet -> endsnippet blocks, making navigation in large snippet files much easier.

To enable hs-minor-mode automatically for Ultisnips files, add the following to the Emacs configuration:

(add-hook 'ultisnips-mode-hook #'hs-minor-mode)

NOTE: As an alternative to hs-minor-mode, ultisnips-mode also supports outline-minor-mode; however, hs-minor-mode is recommended because it can reliably fold entire blocks from snippet to endsnippet. In contrast, outline-minor-mode uses only the snippet line as a header and may hide everything between the first snippet and the next one, including comments.

For a better and more intuitive way to fold and unfold snippets, it is recommended to use the kirigami.el emacs package.

Hiding all snippets with hs-minor-mode when opening *.snippets files

The following configuration automatically folds all code blocks when ultisnips-mode is enabled, collapsing all snippets:

(defun my-ultisnips-mode-fold-all ()
  "Fold all snippet blocks using `hs-minor-mode'."
  (hs-minor-mode 1)
  (hs-hide-all))

(add-hook 'ultisnips-mode-hook #'my-ultisnips-mode-fold-all)

This ensures a cleaner view of snippets, collapsing all regions by default and allowing selective expansion as needed.

Is there a package that allows using UltiSnips directly in Emacs, or is it necessary to first convert them to the Yasnippet format?

Yes, conversion to Yasnippet is required.

A command-line tool called Ultyas facilitates the conversion of snippets from UltiSnips to Yasnippet format.

How does the author use ultisnips-mode and Ultyas?

The author maintains all snippets in their original UltiSnips format for Vim and developed a shell script that automatically scans the UltiSnips directory, generating the corresponding Yasnippet files using Ultyas.

He uses the ultisnips-mode Emacs package to edit snippets, which provides syntax highlighting and code folding via hs-minor-mode.

This workflow allows editing and storing a single set of snippets while making them available in Vim and Emacs.

Author and License

The ultisnips-mode Emacs package 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) 2025-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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

kirigami.el – A Unified Interface for Text Folding across a diverse set of Emacs modes (outline-mode, outline-minor-mode, outline-indent-mode, org-mode, markdown-mode, vdiff-mode, hs-minor-mode, treesit-fold-mode…)

Build Status MELPA MELPA Stable License

The kirigami Emacs 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, outli-mode, embark-collect-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, hs-minor-mode (hideshow), ibuffer-mode (M-x ibuffer), and profiler-report-mode (M-x profile-report).

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 interactive 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.

It features both a buffer-local minor mode (kirigami-mode) and an editor-wide global minor mode (kirigami-global-mode) that expose all text-folding operations through keybindings, a menu bar entry, and context menus.

In addition to providing a unified interface, the kirigami package enhances folding behavior in the outline, markdown-mode, and org-mode packages. It ensures that deep folds open reliably, allows folds to be closed even when the cursor is positioned inside the content, and ensures that sibling folds at the same level are visible when a sub-fold is expanded. For org-mode specifically, Kirigami now provides native folding support for elements such as source blocks (#+begin_src), drawers (:TEST_DRAWER:), and results (#+RESULTS:). When Kirigami closes outline folds, it preserves the visibility of folded headings in the window. Additionally, it resolves upstream Emacs issues, such as bug#79286.

If kirigami enhances your workflow, please show your support by ⭐ starring kirigami.el on GitHub to help more Emacs users discover its benefits.

Features

Here are the features that kirigami offers:

  • Uniform commands: The same commands and keys can be used to open, close, toggle, or check folds, no matter what mode is active. (Commands: kirigami-open-fold, kirigami-open-fold-rec, kirigami-open-folds, kirigami-close-fold, kirigami-toggle-fold, kirigami-close-folds)
  • Automatic handler selection: Kirigami automatically chooses the right folding method based on the mode being used.
  • Extensible fold list: Users can easily add or customize folding methods for different modes through the kirigami-fold-list alist.
  • Support for multiple folding backends, including:
    • outline-mode, outline-minor-mode (built-in), and external packages based on outline such as outli (outli-mode) or outline-indent (outline-indent-minor-mode), a package that enables code folding based on indentation.
    • hs-minor-mode (hideshow, built-in)
    • outline-indent-minor-mode (outline-indent.el, a package that enables code folding based on indentation)
    • org-mode (built-in)
    • markdown-mode and gfm-mode (markdown-mode)
    • vdiff-mode and vdiff-3way-mode
    • treesit-fold-mode (treesit-fold, which provides intelligent code folding by using the structural understanding of the built-in tree-sitter parser)
    • embark-collect-mode
    • hide-ifdef-mode
    • vimish-fold-mode
    • origami-mode
    • TeX-fold-mode (AUCTeX)
    • fold-this-mode
    • yafolding-mode
    • ts-fold-mode
    • ibuffer-mode (toggle filter groups in M-x ibuffer)
    • profiler-report-mode (expand/collapse M-x profile-report tree entries)
  • In addition to unified interface for opening and closing folds, the kirigami package:
    • Visual Stability: Avoids the disruptive window jump by preserving the cursor’s exact vertical position when expanding or collapsing headings, maintaining a constant relative distance between the cursor and the window start.
    • Enhances outline and org-mode: Improves folding in outline-mode, outline-minor-mode, markdown-mode, gfm-mode, and org-mode by ensuring deep folds open reliably, keeping folded headings visible, and collapsing to the shallowest heading level. In org-mode, it intercepts folding commands to natively toggle source blocks (#+begin_src), drawers (:TEST_DRAWER:), and results (#+RESULTS:) sections without falling back to standard heading behavior.
    • Hooks: kirigami-pre-action-predicates and kirigami-post-action-functions run before and after each fold, allowing actions to be allowed or blocked and enabling UI or external updates after changes.

The kirigami package supports Emacs version 26.3 and above.

Installation

To install kirigami from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install kirigami from MELPA:

(use-package kirigami
  :custom
  ;; Add Kirigami to the menu bar and context menu (`context-menu-mode').
  (kirigami-show-menu-bar t)
  (kirigami-show-context-menu t)
  :config
  (kirigami-global-mode 1))

Usage

Vanilla Emacs Key bindings

Here is an example of default key bindings:

(global-set-key (kbd "C-c z o") 'kirigami-open-fold)     ; Open fold at point
(global-set-key (kbd "C-c z O") 'kirigami-open-fold-rec) ; Open fold recursively
(global-set-key (kbd "C-c z r") 'kirigami-open-folds)    ; Open all folds
(global-set-key (kbd "C-c z c") 'kirigami-close-fold)    ; Close fold at point
(global-set-key (kbd "C-c z m") 'kirigami-close-folds)   ; Close all folds
(global-set-key (kbd "C-c z a") 'kirigami-toggle-fold)   ; Toggle fold at point

Evil-mode Key Bindings

Evil-mode users can override the default folding keys with the following configuration:

;; Configure Kirigami to replace the default Evil-mode folding key bindings
(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))

Configuring and Enabling Folding Backends

Kirigami acts as a unified interface and requires an underlying folding backend to be active in the current buffer.

The following article provides a comprehensive guide on installing and enabling the supported folding backends: The Definitive Guide to Code Folding in Emacs.

Commands

Kirigami defines several interactive commands. These commands abstract over all supported folding systems:

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

Extending Kirigami: Adding other fold methods

The core behavior is driven by kirigami-fold-list, a customizable list that associates folding actions with sets of major or minor modes. Each entry in the list specifies:

  • A list of modes that act as a predicate.
  • A property list describing supported folding actions.

Properties include:

  • :open-all Function to open every fold in the current buffer.

  • :close-all Function to close every fold in the current buffer.

  • :toggle Function to toggle the fold at point.

  • :open Function to open the fold at point.

  • :open-rec Function to open the fold at point recursively.

  • :close Function to close the fold at point.

Each property must specify a function. A value of nil indicates that the corresponding action is ignored for that handler.

Here is an example using the built-in hs-minor-mode, which Kirigami supports by default. This example demonstrates how additional folding actions can be configured:

(push
 '((hs-minor-mode)
   :open-all    hs-show-all
   :close-all   hs-hide-all
   :toggle      hs-toggle-hiding
   :open        hs-show-block
   :open-rec    nil
   :close       hs-hide-block)
 kirigami-fold-list)

Frequently Asked Questions

Why code folding?

Code folding is about managing cognitive load, preserving spatial memory, and controlling screen real estate:

  • Navigating through code (e.g., with LSP) can create a vacuum of context. Folding an entire file to its top-level headings allows the manipulation of the file skeleton directly in the main buffer. Revealing only a specific entry and its parents provides an immediate understanding of the hierarchy without losing position.
  • When tasked with debugging a 20,000 line legacy file, immediate refactoring is rarely an option. Folding enables the visual modularization of massive files on the fly, making hostile codebases readable.
  • Every visible line of code on the screen requires a fraction of subconscious attention to ignore. During deep debugging sessions, folding adjacent functions or complex implementations acts as a visual garbage collector.
  • Moving or deleting a massive function or block is prone to selection errors. When a block is folded, it behaves as a single logical unit. Large chunks of logic can be cut, copied, or moved safely and cleanly without manually highlighting hundreds of lines.
  • Folding is effective for tracking progress during extensive pull requests. Collapsing previously examined functions or blocks actively filters out visual noise and enforces a strict focus on the unreviewed code.

Why the author developed the kirigami package?

Code folding in Emacs has historically suffered from reliability issues, which led to the development of kirigami. Even built-in modes such as outline-mode and outline-minor-mode which are also used by org-mode, gfm-mode, and markdown-mode contain bugs that have not yet been addressed upstream, and kirigami fixes them.

The kirigami package also provides a unified interface for opening and closing folds. Without it, users must manually configure keybindings for each individual mode, a tedious process. It functions as a set-and-forget enhancement for code folding. It requires configuration only once. Subsequently, the same keys and functions enable consistent folding and unfolding across all supported major and minor modes.

(The kirigami package is highly recommended for use with outline-based modes, such as markdown-mode, gfm-mode, org-mode, outline-minor-mode, or outline-indent-minor-mode. This package resolves persistent inconsistencies and prevents incorrect folding behavior.)

Preventing Emacs search from matching text within folded blocks

By default, search operations can match text within folded blocks, which often causes Emacs to automatically expand the hidden content.

To instruct Emacs to strictly ignore invisible text during search operations, add the following configuration to your init file:

(setq-default search-invisible nil)

Alternatively, to restrict this behavior to specific modes, apply a buffer-local configuration via a mode hook:

(add-hook 'prog-mode-hook (lambda ()
                            (setq-local search-invisible nil)))

Integrating display-line-numbers-mode with code folding

The built-in display-line-numbers-mode renders line numbers in the side margin of the window. By default, it uses absolute line numbering, which tracks the absolute line count in the buffer. Consequently, when a block is folded, the line numbers skip the hidden range (e.g., jumping from 15 to 120).

For users who prefer visual line numbering, display-line-numbers-mode can be configured to ignore collapsed content and assign numbers sequentially based only on what is currently rendered on the screen.

To implement visual line numbering as your global default, set the following variable in your configuration:

(setq-default display-line-numbers-type 'visual)

Note that you must still enable the mode itself (for example, via M-x global-display-line-numbers-mode) for the line numbers to appear.

Maintaining independent folding states in separate windows via indirect buffers (clones)

Opening the same buffer in multiple windows results in synchronized folding states; any folding or unfolding action performed in one window is immediately reflected in all others.

This occurs because folding engines use buffer-local overlays, which are shared across all windows associated with that specific buffer.

Indirect buffers provide a robust solution to this limitation. An indirect buffer shares the underlying text of its parent buffer but maintains an independent set of overlays. This distinction allows for the maintenance of different folding configurations for the same file simultaneously.

To create an indirect buffer (clone) of the current buffer in a separate window, execute:

M-x clone-indirect-buffer-other-window

Creating an indirect buffer provides a separate buffer object that references the same text while maintaining its own isolated set of opened/closed folds.

Discouraged Emacs Folding Engines

Choosing an appropriate folding engine is important for maintaining performance and stability within Emacs. While several third-party and legacy options exist, the following packages and methods are generally discouraged in favor of more modern or integrated alternatives:

  • Origami: This package is slow and largely unmaintained. Origami uses a non-standard API and a complex implementation that frequently conflicts with other overlay-based minor modes. Its overhead can lead to performance degradation, especially when handling large buffers or deeply nested code. (Modern alternatives to origami: outline-indent, treesit-fold, outline-minor-mode, hs-minor-mode)
  • Yafolding: This package is also unmaintained and suffers from performance issues. (Modern alternative to yafolding: outline-indent)
  • Semantic (CEDET): Part of the legacy CEDET suite, Semantic folding is widely regarded as heavyweight. The parsing overhead required for its operation often introduces noticeable latency, making it vastly less efficient than modern built-in alternatives like Tree-sitter. (Modern alternatives to CEDET code folding: treesit-fold, outline-minor-mode, hs-minor-mode, outline-indent)
  • Selective Display (set-selective-display): This is Emacs’ oldest built-in folding method (often bound to C-x $). It causes unpredictable cursor jumping, and lacks any contextual awareness.
  • Folding-mode: This ancient package relies on explicit structural markers placed manually inside code comments (e.g., {{{ and }}}). While robust for the user, markers pollute the source code with editor-specific metadata. This is heavily frowned upon in modern collaborative environments where team members use varying IDEs.
  • Vimish-fold: Although useful for manual, ad-hoc text folding, vimish-fold is not recommended as a primary automated folding engine. Unlike Vim’s set foldmethod=marker, the vimish-fold implementation does not support recursive markers, such as {{{ inside of {{{. Additionally, like folding-mode, vimish-fold also uses markers that pollute the source code with editor-specific metadata, a practice discouraged in collaborative environments where team members use a variety of editors and IDEs.

What code folding packages does the author use in addition to kirigami.el?

In addition to the kirigami package, the author uses two reliable code folding packages:

  1. Indentation-based folding (Python, YAML, Haskell, etc.): outline-indent
  2. Tree-sitter-based folding: treesit-fold (The integration of Tree-sitter allows Emacs to operate on the Abstract Syntax Tree, making folding structurally accurate rather than heuristic.)
  3. The built-in outline-minor-mode for emacs-lisp-mode, markdown-mode, and conf-mode/conf-unix-mode.

NOTE: The author prefers using outline-indent for languages like Python, despite having treesit-fold installed. The advantage of outline-indent is that it allows for infinite folding depth; it enables the folding of classes, functions within them, and even nested structures like while loops and if statements.

Maintaining Vertical Cursor Position During Folding

Folding packages such as Outline, Outline Indent, and Org mode depend on the native Emacs redisplay engine to handle visibility changes. Expanding or collapsing folds can cause window-start to shift relative to the current line. When this displacement moves the cursor off-screen, Emacs triggers an abrupt recentering. This visual discontinuity disrupts spatial context and requires manual effort to relocate the cursor.

To address these issues, the following option can be used to eliminate visual discontinuities by preventing window shifts and suppressing forced recentering when headings are expanded or collapsed:

(setq kirigami-preserve-visual-position t)

What is the meaning of the word Kirigami?

Kirigami is a form of Origami, the Japanese art that transforms a flat sheet of paper into a figure through controlled folds. In kirigami, the sheet is both folded and cut to form a three-dimensional structure that rises from the surface.

Kirigami and code folding in Emacs share a structural analogy based on selective concealment and controlled revelation. In kirigami, cuts and folds create regions that can be collapsed or expanded, revealing depth or hiding detail depending on how the paper is manipulated.

Code folding in Emacs operates on a similar principle. Blocks of text remain present in the buffer, but their visibility is adjusted by folding or unfolding sections.

Comments from users

  • neurolit on GitHub: “Thank you very much for this package!”

  • jcs090218: “Thanks for this great package!”

  • RideAndRoam3C: “I enabled it today while doing some Org technical docs work. Solid.”

  • mickeyp: “Nice job. So many different packages.”

  • Anthea_Likes: “I’ve been using Kirigami for a few months now, and it’s absolutely gorgeous! Thank you for this quality work 🙏”

Author and License

The kirigami Emacs package 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. Special thanks to the developers of Evil mode. Kirigami builds upon the idea and function from Evil mode to provide enhanced and unified code folding functionality to all Emacs users.

Copyright (C) 2025-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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

quick-sdcv.el, a package that enables Emacs to function as an offline dictionary using sdcv

Build Status MELPA MELPA Stable License

The quick-sdcv.el package provides a lightweight interface for the sdcv command-line tool, enabling Emacs to function as an offline dictionary.

This package allows for immediate word definitions and translations without requiring an internet connection.

Key interactive functions include:

  • quick-sdcv-search-at-point: Searches the word under the cursor and displays the result in a dedicated buffer.
  • quick-sdcv-search-input: Prompts for a custom input string and presents the corresponding dictionary entry in a buffer.

If this package enhances your workflow, please show your support by ⭐ starring quick-sdcv on GitHub to help more Emacs users discover its benefits.

Prerequisite

  • The sdcv command. (It can usually be installed by installing 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.

Installation

To install quick-sdcv on Emacs from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code at the very beginning of your init.el file, before all other packages:

(use-package quick-sdcv
  :init
  ;; When non-nil, a distinct buffer is created for each word searched.
  (setq quick-sdcv-unique-buffers t)

  ;; Change the prefix character used before dictionary names, replacing the
  ;; default `-->`:
  (setq quick-sdcv-dictionary-prefix-symbol "►")

  ;; Change the quick-sdcv dictionaries ellipsis from … to " ▼"
  ;; (In quick-sdcv buffers, `outline-minor-mode' is enabled by default, which
  ;; allows sections corresponding to individual dictionaries to be folded. The
  ;; ellipsis … indicates a folded section, making it easy to collapse all
  ;; dictionaries and expand only those of interest.)
  (setq quick-sdcv-ellipsis " ▼")

  ;; Automatically fold all dictionary entries when performing a search.
  ;; You can then unfold the dictionaries you want to read.
  (setq quick-sdcv-fold-on-search t))

Usage

To retrieve the word under the cursor and display its definition in a buffer:

(quick-sdcv-search-at-point)

To prompt the user for a word and display its definition in a buffer:

(quick-sdcv-search-input)

Customizations

To create a unique buffer for each word lookup, set the following:

;; Controls whether each word lookup creates a separate buffer.
;; Its default value is nil, but it can be set to t to enable unique buffers.
;;
;; When non-nil, a distinct buffer is created for each word searched. For
;; example, searching for the word "computer" produces a buffer named
;; "*sdcv:computer*". When nil, all lookups share the same buffer, typically
;; named "*sdcv*".
;;
;; The naming of unique buffers can be further customized using the variables:
;; - 'quick-sdcv-buffer-name-prefix'
;; - 'quick-sdcv-buffer-name-separator'
;; - 'quick-sdcv-buffer-name-suffix'
(setq quick-sdcv-unique-buffers t)

To perform exact word searches (as opposed to fuzzy searches), use:

;; To perform exact word searches (as opposed to fuzzy searches), use:
(setq quick-sdcv-exact-search t)

To change the prefix character used before dictionary names, replacing the default -->, set:

;; To change the prefix character used before dictionary names, replacing the
;; default `-->`, set:
(setq quick-sdcv-dictionary-prefix-symbol "►")

Customize the quick-sdcv dictionaries ellipsis display:

;; Customize the *quick-sdcv* dictionaries ellipsis display. In quick-sdcv
;; buffers, `outline-minor-mode' is enabled by default, which allows sections
;; corresponding to individual dictionaries to be folded. The ellipsis (…)
;; indicates a folded section, making it easy to collapse all dictionaries and
;; expand only those of interest
(setq quick-sdcv-ellipsis " ▼")

To automatically fold all dictionary entries when a search is performed:

;; Automatically fold all dictionary entries when a search is performed.
;; This is useful if you use many dictionaries and want to see a clean list
;; of dictionary names first.
(setq quick-sdcv-fold-on-search t)

To customize the sdcv history size:

;; Customize the sdcv history size
(setq quick-sdcv-hist-size 100)

To specify the path to the sdcv executable:

;; Specify the path to the sdcv executable:
(setq quick-sdcv-program "/path/to/sdcv")

To customize the naming convention of the SDCV buffer:

;; Customize the naming convention of the SDCV buffer:
(setq quick-sdcv-buffer-name-prefix "*sdcv"
      quick-sdcv-buffer-name-separator ":"
      quick-sdcv-buffer-name-suffix "*")

To specify a list of dictionaries (NOT RECOMMENDED. It is better to let sdcv show all dictionaries):

;; To specify a list of dictionaries (NOT RECOMMENDED. It is better to let sdcv
;; show all dictionaries):
(setq quick-sdcv-dictionary-complete-list '("stardict-WordNet"
                                            "stardict-Webster"
                                            "stardict-eng_eng_main"))

Frequently asked question

Why not dictd?

The primary advantage of sdcv is its direct compatibility with the StarDict format. Over the years, the StarDict ecosystem has accumulated a massive, easily accessible repository of freely distributed dictionaries (e.g, huzheng), including highly specialized, technical, and bilingual databases. Using StarDict dictionaries is easier and offers a richer selection of reference materials compared to finding or manually converting formats to support a native dictd setup.

How can dictionary entries be folded and unfolded?

The quick-sdcv mode enables outline-minor-mode by default, allowing sections corresponding to individual dictionaries to be folded.

To automatically collapse all dictionary entries upon search initialization, enable the following variable:

(setq quick-sdcv-fold-on-search t)

Since quick-sdcv inherits the standard outline keybindings, you should be able to toggle the visibility of a single dictionary section by placing your cursor on the header line and pressing TAB (which calls outline-toggle-children). If TAB is not working as expected, it is possible that another package in your configuration is shadowing that binding in the sdcv-mode buffer.

While the built-in outline-minor-mode functions can be used to open and close these folds, installing kirigami.el is highly recommended. It enhances the folding experience by providing a more robust and unified interface for folding text.

How to customize the buffer display?

By default, Emacs typically opens the *sdcv* results in a standard split window, occupying half of the frame. The placement and behavior of this buffer can be precisely controlled by customizing the display-buffer-alist variable.

Below are two common configurations to add to the Emacs initialization file:

Option 1: Display at the bottom with a fixed height

To create a less intrusive interface, Emacs can be configured to display the dictionary buffer at the bottom of the frame while maintaining the current window arrangement:

(add-to-list 'display-buffer-alist
             '("\\*sdcv"
               (display-buffer-reuse-window display-buffer-at-bottom)
               (window-height . 0.33)))

Option 2: Replace the current window entirely

Alternatively, to have the dictionary results fully replace the active window rather than creating a split, the following configuration applies:

(add-to-list 'display-buffer-alist '("\\*sdcv"
                                     (display-buffer-same-window)))

How to make links appear as links in an sdcv buffer?

To ensure that links appear as clickable links in the SDCV buffer while using quick-sdcv, add the following hook:

(add-hook 'quick-sdcv-mode-hook #'goto-address-mode)

Evil mode: How to configure the default K key to search for words using quick-sdcv?

In Evil-mode, the K key in normal mode typically triggers a help function. While viewing a word’s definition in a quick-sdcv buffer, pressing K in normal mode jumps to the definition of the word at point.

This behavior can be configured in other modes, allowing, for instance, the definition of a word to be displayed by pressing K while editing a Markdown or Org file.

For example, to configure K to search for a word using quick-sdcv when editing Markdown or Org files, use the following customization:

(dolist (mode-hook '(markdown-mode-hook org-mode-hook))
  (add-hook mode-hook
            (lambda ()
              (setq-local evil-lookup-func #'quick-sdcv-search-at-point))))

What is the difference between sdcv and quick-sdcv Emacs packages?

The quick-sdcv Emacs package is a fork of sdcv.el version 3.4, which is available on MELPA. The primary differences between the two packages are as follows:

  • Less dependencies: Quick-sdcv does not require any external dependencies; sdcv, on the other hand, installs popup, pos-tip, and showtip.
  • Customize the buffer name:: New variables to customize whether the word is included in the buffer name, as well as the prefix, separator, and suffix of the buffer name (quick-sdcv-unique-buffers, quick-sdcv-buffer-name-prefix, quick-sdcv-buffer-name-separator, and quick-sdcv-buffer-name-suffix). When the buffer is dedicated to a specific word, refresh it only when the buffer is created.
  • Improved Outline Minor Mode: The quick-sdcv package fixes the outline minor mode for dictionary folding, enabling users to collapse all definitions for quicker navigation through dictionaries.
  • Default Language Settings: Various issues have been addressed, including changing the default language setting from Chinese (zh) to nil, providing a more neutral starting point.
  • Buffer Customization: The quick-sdcv package employs display-buffer, allowing users to customize the display of the sdcv buffer and control its placement through display-buffer-alist.
  • Removal of bugs and Warnings: All Emacs warnings have been eliminated and bugs fixed. (e.g., when sdcv-search-at-point cannot locate the word under the cursor)
  • Code Simplification: The code has been simplified by removing unused variables and omitting features like posframe, text-to-speech using the ‘say’ command, the quick-sdcv-env-lang variable, and functions such as (quick-sdcv-scroll-up-one-line, quick-sdcv-scroll-down-one-line, quick-sdcv-next-line and quick-sdcv-prev-line) which are similar Emacs features. This simplification makes quick-sdcv easier to understand, maintain, and use by focusing solely on dictionary lookup functionality. Features like posframe and text-to-speech, which are not essential to core usage, are better suited as separate packages.
  • Keybindings removal: The default keybindings have been removed from quick-sdcv-mode to prevent conflicts with other modes and keeps the mode lightweight and adaptable for users’ preferences.
  • New options: quick-sdcv-fold-on-search, quick-sdcv-ellipsis, quick-sdcv-hist-size, quick-sdcv-exact-search, quick-sdcv-buffer-name-prefix, quick-sdcv-buffer-name-separator, quick-sdcv-buffer-name-suffix, quick-sdcv-verbose.
  • Various improvements: Unset the SDCV_PAGER environment variable, Ensure the buffer and the SDCV output are in UTF-8, Enhance dictionary representation with UTF-8 characters, Implement error handling for cases when the sdcv program is not found.

Community contribution: How I use quick-sdcv to get the Oxford English Dictionary entirely offline

Mingey, a quick-sdcv user, shared a workflow demonstrating how to integrate the massive Oxford English Dictionary (OED) directly into Emacs:

How I use quick-sdcv to get the Oxford English Dictionary (OED) in my Emacs

His workflow stack:

  • quick-sdcv: For instantaneous, offline dictionary queries. Mingey configured it to act like a native Emacs help buffer, allowing for ‘Do What I Mean’ (DWIM) searches that automatically look up the word under the cursor, display results in a collapsible outline, and cleanly restore the previous window layout when dismissed.
  • nov.el: For a in-editor EPUB reading experience. Binding a custom shortcut (K) directly to the dictionary tool within the reader creates an ergonomic workflow where the user can look up obscure words without ever breaking focus or leaving the book.
  • olivetti-mode: For distraction-free visual centering of the dense dictionary output.

Comments from users

  • ecraven on GitHub: Thank you very much for this mode, it is proving very helpful!

  • mingey on GitHub: “I don’t know if this is the appropriate place, but I wanted to thank you for writing this mode — I’ve been using Emacs about a year now, and it’s still constantly surprising me with its depth, and the richness of the added value the community brings. This package is a perfect example; I do a lot of reading in Emacs now, and with minimal configuration, I can be reading an epub and, with a keystroke, instantly get the OED article for a word I’m curious about…it’s one of those Emacs things that feels miraculous. I’m so grateful to you for taking the time to write the mode and for sharing it so generously; I hope (and expect) I’ll be using it with pleasure for years to come.”

Links

Related links:

  • How I use quick-sdcv to get the The Oxford English Dictionary entirely offline: Mingey, a quick-sdcv user, shares a workflow to get the Oxford English Dictionary entirely offline by combining quick-sdcv for rapid dictionary queries, nov.el for an EPUB reading experience, and olivetti-mode for distraction-free visual centering. This workflow transforms Emacs into a sophisticated research workstation where centuries of linguistic evolution are accessible at a single keystroke.

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • vim-tab-bar.el: Make the Emacs tab-bar Look Like Vim’s Tab Bar.
  • 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).
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

inhibit-mouse.el – Deactivate mouse input in Emacs (Alternative to disable-mouse)

Build Status MELPA MELPA Stable License

The inhibit-mouse package allows the disabling of mouse input in Emacs using inhibit-mouse-mode.

Instead of modifying the keymap of its own mode as the disable-mouse package does, enabling inhibit-mouse-mode only modifies input-decode-map to disable mouse events, making it more efficient and faster than disable-mouse.

Additionally, the inhibit-mouse package allows for the restoration of mouse input when inhibit-mouse-mode is disabled.

If this enhances your workflow, please show your support by ⭐ starring inhibit-mouse on GitHub to help more Emacs users discover its benefits.

Installation

To install inhibit-mouse from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.
  2. Add the following code to the Emacs init file:
(use-package inhibit-mouse
  :custom
  ;; Disable highlighting of clickable text such as URLs and hyperlinks when
  ;; hovered by the mouse pointer.
  (inhibit-mouse-adjust-mouse-highlight t)

  ;; Disables the use of tooltips (show-help-function) during mouse events.
  (inhibit-mouse-adjust-show-help-function t)

  :config
  (if (daemonp)
      (add-hook 'server-after-make-frame-hook #'inhibit-mouse-mode)
    (inhibit-mouse-mode 1)))

Customization

Customizing the mouse buttons disabled by inhibit-mouse?

The inhibit-mouse custom variables allow you to fine-tune which mouse interactions are disabled.

You can use the following configuration to specify which mouse buttons and events you want to disable:

;; This variable specifies which mouse buttons should be inhibited from
;; triggering events.
(setq inhibit-mouse-button-numbers '(1 2 3 4 5))

;; List of mouse button events to be inhibited.
(setq inhibit-mouse-button-events '("mouse"
                                    "up-mouse"
                                    "down-mouse"
                                    "drag-mouse"))

;; List of miscellaneous mouse events to be inhibited.
(setq inhibit-mouse-misc-events '("wheel-up"
                                  "wheel-down"
                                  "wheel-left"
                                  "wheel-right"
                                  "pinch"))

;; List of mouse multiplier events to be inhibited.
(setq inhibit-mouse-multipliers '("double" "triple"))

;; List of key modifier combinations to be inhibited for mouse events.
(setq inhibit-mouse-key-modifiers '((control)
                                    (meta)
                                    (shift)
                                    (control meta shift)
                                    (control meta)
                                    (control shift)
                                    (meta shift)))

Allowing mouse in specific major modes

To allow mouse input in specific major modes (e.g., when viewing a PDF document or an image), add those modes to the inhibit-mouse-excluded-modes list.

When the mouse pointer hovers over a window containing a buffer that matches any mode in this list, mouse events will pass through completely unmodified. This allows clicking links inside a PDF or navigating an image without needing to turn off the global mode.

(setq inhibit-mouse-excluded-modes '(pdf-view-mode image-mode))

Enabling/Disabling the context menu

To enable or disable the context menu based on the state of inhibit-mouse-mode, the following code dynamically toggles context-menu-mode accordingly:

(add-hook 'inhibit-mouse-mode-hook
          #'(lambda()
              ;; Enable or disable the context menu based on the state of
              ;; `inhibit-mouse-mode', the following code dynamically toggles
              ;; `context-menu-mode' accordingly.
              (when (fboundp 'context-menu-mode)
                (if (bound-and-true-p inhibit-mouse-mode)
                    (context-menu-mode -1)
                  (context-menu-mode 1)))))

This ensures that the context menu is disabled when inhibit-mouse-mode is active and enabled when it is inactive.

Enabling/Disabling tooltip-mode

When tooltip-mode is enabled, Emacs displays certain UI hints (e.g., help text and mouse-hover messages) as popup windows near the cursor, instead of in the echo area. This behavior is useful in graphical Emacs sessions.

To toggle tooltip-mode dynamically based on the state of inhibit-mouse-mode, you can use the following hook:

(add-hook 'inhibit-mouse-mode-hook
          #'(lambda()
              ;; Enable or disable `tooltip-mode'. 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.
              (when (fboundp 'tooltip-mode)
                (if (bound-and-true-p inhibit-mouse-mode)
                    (tooltip-mode -1)
                  (tooltip-mode 1)))))

Enabling/disabling pixel scroll precision mode

The following configuration toggles pixel-scroll-precision-mode based on the state of inhibit-mouse-mode, excluding macOS Carbon environments where pixel scrolling is natively supported and does not require explicit activation.

(add-hook 'inhibit-mouse-mode-hook
          #'(lambda()
              (unless (and
                       ;; Exclude macOS Carbon environments where pixel
                       ;; scrolling is natively supported and does not
                       ;; require explicit activation.
                       (eq window-system 'mac)
                       (bound-and-true-p mac-carbon-version-string))
                (when (fboundp 'pixel-scroll-precision-mode)
                  (if (bound-and-true-p inhibit-mouse-mode)
                      (pixel-scroll-precision-mode -1)
                    (pixel-scroll-precision-mode 1))))))

Frequently Asked Question

What motivates the author to disable the mouse in Emacs?

The author disables the mouse in Emacs:

  • To prevent accidental clicks or cursor movements that can change the cursor position unexpectedly.
  • To reinforce a keyboard-centric workflow, helping to avoid the habit of relying on the mouse for navigation.

Some may suggest that the author could modify the touchpad settings at the OS level. However, he prefers not to disable the touchpad entirely, as it remains useful in other applications, such as web browsers.

Is it not enough to simply avoid touching the mouse?

It is not always as simple as just deciding not to touch the mouse. When transitioning to a fully keyboard-driven workflow, existing habits can be surprisingly persistent.

In the author’s case, he often found himself unconsciously reaching for the mouse, even though they had deliberately chosen to keep his hands on the home row. The home row, the middle row of keys on a standard keyboard layout, is where the fingers rest in the touch typing method. Keeping the hands on the home row minimizes unnecessary hand movement, preserves typing rhythm, and allows immediate access to the majority of keys. In contrast, reaching for the mouse interrupts the workflow, introduces delays, and shifts focus away from the keyboard, reducing overall efficiency.

The inhibit-mouse Emacs package provided a practical solution. By disabling mouse input entirely, it removed the possibility of falling back on that habit. Over time, this enforced constraint trained the author to rely exclusively on the keyboard.

This package acted as a form of behavioral reinforcement for the author: each attempt to use the mouse proved unproductive, gradually reshaping habits until the keyboard-driven workflow became natural and automatic.

What is the difference between the disable-mouse and inhibit-mouse packages?

The inhibit-mouse package is a efficient alternative to the disable-mouse package, as it only modifies input-decode-map to disable mouse events.

In contrast, disable-mouse applies mouse events to its own mode, and sometimes the user has to apply it to other modes that are not affected by the disable-mouse mode using the disable-mouse-in-keymap function (e.g, evil-mode, tab-bar…).

Additionally, inhibit-mouse:

  • Allows re-enabling mouse functionality when the mode is disabled, which is not supported by disable-mouse when the disable-mouse-in-keymap function is used. The disable-mouse-in-keymap function overwrites the key mappings of other modes (e.g., evil, tab-bar), and there is no straightforward way to make disable-mouse restore them.
  • It resolves issues that disable-mouse does not, such as the “C-c C-x is not bound” problem, where the user intended to enter C-c C-x j but accidentally touched the touchpad.

This concept of using input-decode-map to disable the mouse was introduced by Stefan Monnier in an emacs-devel mailing list thread initiated by Daniel Radetsky, who proposed a patch to the Emacs developers. Additionally, here is an interesting discussion on GitHub: Add recipe for inhibit-mouse.

Author and License

The inhibit-mouse Emacs package 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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • vim-tab-bar.el: Make the Emacs tab-bar Look Like Vim’s Tab Bar.
  • 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).
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Emacs flymake-bashate.el – A Flymake backend for bashate that provides style checking for Bash shell scripts within Emacs

Build Status MELPA MELPA Stable License

The flymake-bashate Emacs package provides a Flymake backend for bashate, enabling real-time style checking for Bash shell scripts within Emacs.

(This package can also work with Flycheck: simply use the flymake-flycheck package, which allows any Emacs Flymake backend to function as a Flycheck checker.)

If this enhances your workflow, please show your support by ⭐ starring flymake-bashate.el on GitHub to help more Emacs users discover its benefits.

Installation

To install flymake-bashate from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install flymake-bashate from MELPA:

(use-package flymake-bashate
  :commands flymake-bashate-setup
  :hook (((bash-ts-mode sh-mode) . flymake-bashate-setup)
         ((bash-ts-mode sh-mode) . flymake-mode))
  :custom
  (flymake-bashate-max-line-length 80))

Customizations

Ignoring Bashate errors

To make bashate ignore specific Bashate rules, such as E003 (ensure all indents are a multiple of 4 spaces) and E006 (check for lines longer than 79 columns), set the following variable:

(setq flymake-bashate-ignore "E003,E006")

(This corresponds to the -i or --ignore option in Bashate.)

Setting maximum line length

To define the maximum line length for Bashate to check:

(setq flymake-bashate-max-line-length 80)

(This corresponds to the --max-line-length option in Bashate.)

Specifying the Bashate executable

To change the path or filename of the Bashate executable:

(setq flymake-bashate-executable "/opt/different-directory/bin/bashate")

(Defaults to “bashate”.)

Comments from users

  • gsotirchos: ‘Thank you for maintaining flymake-bashate, I really appreciate the work you’ve put into it.’

License

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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Emacs enhanced-evil-paredit.el package: Preventing Parenthesis Imbalance when Using Evil-mode with Paredit

Build Status MELPA MELPA Stable License

The enhanced-evil-paredit package 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. This guarantees that your Lisp code remains syntactically correct while retaining the editing features of evil-mode.

If this enhances your workflow, please show your support by ⭐ starring enhanced-evil-paredit-mode on GitHub to help more Emacs users discover its benefits.

Installation

To install enhanced-evil-paredit from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.
  2. Add the following code to the Emacs init file to install enhanced-evil-paredit:
;; `paredit-mode' is a requirement
(use-package paredit
  :commands paredit-mode
  :hook
  (emacs-lisp-mode . paredit-mode))

(use-package enhanced-evil-paredit
  :commands enhanced-evil-paredit-mode
  :hook (paredit-mode . enhanced-evil-paredit-mode))

Frequently asked questions

What are the differences between enhanced-evil-paredit and evil-paredit?

The enhanced-evil-paredit package is a modernized version of evil-paredit. It has been enhanced and fully functions in recent versions of Emacs (Emacs >= 28). The author decided to develop enhanced-evil-paredit because the evil-paredit package is no longer maintained and does not function in recent versions of Emacs and Evil.

Here are the enhancements in enhanced-evil-paredit:

  • Handles paste using p and P, ensuring that the pasted text has balanced parentheses.
  • Fix call to a non-existent function (evil-called-interactively-p), which has been replaced by (called-interactively-p 'any).
  • Add new functions: enhanced-evil-paredit-backward-delete and enhanced-evil-paredit-forward-delete.
  • enhanced-evil-paredit-mode only uses the paredit functions when paredit-mode is enabled. It acts as a wrapper that delegates commands to Paredit when Paredit is enabled and otherwise uses standard Evil commands. (The difference in behavior is that with paredit-mode, structural editing operations preserve balanced parentheses and Lisp structure, whereas without paredit-mode, the same operations rely on Evil motions and can disrupt parentheses and overall code structure.)
  • Add lexical binding with lexical-binding: t.
  • Suppress Emacs Lisp warnings and add Melpa tests.
  • Refactor and improve enhanced-evil-paredit.
  • Create a enhanced-evil-paredit customization group for user configuration.
  • Remove Evil state change from enhanced-evil-paredit-mode.
  • Improve error handling in enhanced-evil-paredit-check-region.
  • Enhance docstrings.
  • Remove keymap bindings that are reserved by Emacs.
  • Add &optional after the end argument to make it similar to Evil functions.
  • dd restores the column when there is a parentheses mismatch.

Author and License

The enhanced-evil-paredit Emacs package has been written by Roman Gonzalez and James Cherti. It 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

Copyright (C) 2012-2015 Roman Gonzalez

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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Emacs flymake-ansible-lint.el – A Flymake backend for ansible-lint

Build Status MELPA MELPA Stable License

The flymake-ansible-lint package provides a Flymake backend for ansible-lint, enabling real-time syntax and style checking for Ansible playbooks and roles within Emacs.

(This package can also work with Flycheck: simply use the flymake-flycheck package, which allows any Emacs Flymake backend to function as a Flycheck checker.)

Requirements

Installation

To install flymake-ansible-lint from MELPA:

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install flymake-ansible-lint from MELPA:

(use-package flymake-ansible-lint
  :commands flymake-ansible-lint-setup
  :hook (((yaml-ts-mode yaml-mode) . flymake-ansible-lint-setup)
         ((yaml-ts-mode yaml-mode) . flymake-mode)))

Customizations

You can configure ansible-lint parameters using the flymake-ansible-lint-args variable:

(setq flymake-ansible-lint-args '("--offline"
                                  "-x"
                                  "run-once[play],no-free-form"))

You can also enable automatic project directory detection to pass the --project-dir argument to the linter automatically. This feature detects the project or version control root and uses it as the project directory:

(setq flymake-ansible-lint-auto-project-dir t)

This ensures that Ansible caches its data inside a single .ansible directory at the project root, rather than cluttering your repository by creating an .ansible folder in every subdirectory where a file is linted, keeping your project tree clean.

Frequently asked questions

Why are some ansible-lint error messages truncated?

This issue is a known bug in ansible-lint, not in flymake-ansible-lint.

It is ansible-lint that truncates some error messages:

$ ansible-lint -p test.yaml
test.yaml:5: yaml[truthy]: Truthy value should be one of

Location of the temporary files created by the flymake-ansible-lint package

By default, the flymake-ansible-lint package creates temporary files in the same directory as the Ansible YAML file currently being edited.

For example, when editing: /home/user/test/myfile.yaml, the package may generate temporary files such as: /home/user/test/flymake_1_myfile.yaml /home/user/test/flymake_2_myfile.yaml

These temporary files are automatically removed once flymake-ansible-lint completes its analysis.

(This behavior is controlled by the variable flymake-ansible-lint-tmp-files-enabled. Keeping flymake-ansible-lint-tmp-files-enabled enabled is important because it allows Flymake to lint the most recent in-memory state of the buffer, including unsaved modifications. Without these temporary files, Flymake would have to rely on the last saved version of the file, which might not reflect the current edits. This ensures that linting diagnostics remain accurate, up to date, and synchronized with the actual buffer contents, providing immediate feedback while editing.)

License

The flymake-ansible-lint Emacs package 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. This package uses flymake-quickdef, by Karl Otness.

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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • flymake-bashate.el: A package that provides a Flymake backend for the bashate Bash script style checker.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Emacs quick-fasd: Integrate Fasd for fast file and directory navigation

Build Status MELPA MELPA Stable License

The quick-fasd Emacs package integrates the Fasd tool into the Emacs environment. Fasd is a command-line utility that provides fast access to frequently used files and directories.

After installing quick-fasd and enabling quick-fasd-mode:

  • All visited files and directories are automatically added to the Fasd database.
  • The quick-fasd-find-path function prompts for input and presents candidates from the Fasd index. (For example, recently accessed files can be opened, and frequently used directories can be visited without leaving Emacs.)
  • When invoked from the minibuffer, quick-fasd-find-path appends the selected path, simplifying completion.

If this package improves the workflow, consider supporting the project by ⭐ starring quick-fasd.el on GitHub so that more Emacs users can benefit from it.

Requirements

  • The fasd command line tool.

Installation

  1. If you haven’t already done so, add MELPA repository to your Emacs configuration.

  2. Add the following code to your Emacs init file to install easysession from MELPA:

(use-package quick-fasd
  :bind (("C-x C-d" . quick-fasd-find-path)
         :map minibuffer-local-completion-map
         ("C-x C-d" . quick-fasd-find-path))
  :config
  (quick-fasd-mode))

Usage

Key binding

Add a shortcut key for quick-fasd-find-path:

(global-set-key (kbd "C-x C-d") 'quick-fasd-find-path)

;; When `quick-fasd-find-path' is invoked from the minibuffer, it appends
;; the selected path, simplifying completion.
;; Path insertion can be disabled by setting `quick-fasd-minibuffer-insert-path' to nil.
(define-key minibuffer-local-completion-map (kbd "C-x C-d") 'quick-fasd-find-path)

Customizations

You can configure quick-fasd using Emacs’ customization system:

M-x customize-group RET quick-fasd RET

Passing custom arguments to Fasd

The quick-fasd package allows customizing the types of results returned by Fasd using quick-fasd-standard-search:

;; Display directories only
(setq quick-fasd-standard-search '("-d"))

;; Display files only
(setq quick-fasd-standard-search '("-f"))

;; Display both files and directories
(setq quick-fasd-standard-search '("-a"))

Initial Prompt

By default, quick-fasd prompts for an initial query. To bypass the prompt and display all results immediately, set:

(setq quick-fasd-enable-initial-prompt nil)

Setting this to nil is useful when using completion frameworks such as Consult, Vertico, or Orderless, allowing them to handle filtering instead of fasd. However, fetching all paths from fasd can be slower for large file databases and may produce an overwhelming number of candidates.

Completion Function

The M-x quick-fasd-find-path command uses the standard completing-read-function, which may be backed by Consult, helm, ido, or any other completion framework you have configured.

Standard Search Behavior

By default, quick-fasd searches for both files and directories using the -a parameter. You can customize this behavior by setting the quick-fasd-standard-search option to refine the search criteria.

Automatically adding paths on buffer or window change

Quick-Fasd can optionally add the current file or directory to the Fasd database whenever the buffer or window changes. This behavior is controlled by the quick-fasd-auto-add-on-buffer-change option.

To enable automatic path addition, set the option to t:

(setq quick-fasd-auto-add-on-buffer-change t)

When enabled, Quick-Fasd will track every file or directory visited in Emacs, including those accessed through buffers and Dired windows, without requiring manual addition.

Benefits:

  • Seamless tracking: Ensures that all relevant files and directories are added to Fasd automatically.
  • Improved workflow: Facilitates faster navigation through frequently accessed paths using Quick-Fasd commands, without the need to manually update the database.

Drawbacks:

  • Increased background activity: Each buffer or window change spawns a background process to update the Fasd database. While this does not block Emacs, it can generate extra system activity if buffers are switched frequently.
  • Database growth: Continuous automatic additions may increase the size of the Fasd database over time, potentially including entries that are rarely used.

Use this option when the convenience of automatic tracking outweighs the potential performance and database size considerations.

Frequently asked questions

What is the difference between quick-fasd and the fasd Emacs package?

The quick-fasd Emacs package is a fork of the unmaintained fasd Emacs package. It supersedes fasd by providing additional features and bug fixes.

Key differences and improvements in quick-fasd include:

  • When quick-fasd-find-path is invoked from the minibuffer, it appends the selected path, simplifying completion. (This can be disabled by setting quick-fasd-minibuffer-insert-path to nil)
  • Adds support for indirect Dired buffers.
  • Enhances dired-mode detection to append paths using the fasd command, increasing their priority for subsequent fasd usage.
  • Fixes an issue in quick-fasd-add-path to ensure it respects quick-fasd-executable-path.
  • Caches the path to the fasd executable for efficiency.
  • Enhances modularity and readability of quick-fasd functions.
  • Fixes all Emacs warnings.
  • Renames global-quick-fasd-mode to quick-fasd-mode.
  • Refines overall code readability and structure.
  • Removes Ivy support, delegating it to a possible third-party package.
  • Allows customizing the Lighter
  • Removes the trailing slash from directories before adding them to Fasd ensures consistent path entries and prevents duplicates.
  • Normalizes the path before adding it to Fasd by expanding it (e.g., replacing ~/ with the home directory).
  • Provides a function to remove a specified path from the Fasd database (quick-fasd-delete-path).
  • Can optionally add the current file or directory to the Fasd database whenever the buffer or window changes. This behavior is controlled by the quick-fasd-auto-add-on-buffer-change option.

Author and License

The quick-fasd Emacs package James Cherti and is distributed under terms of the GNU General Public License version 3, or, at your choice, any later version. It is based on the fasd package, originally written by Steckerhalter.

Copyright (C) 2024-2026 James Cherti

Copyright (C) 2013-2021 Steckerhalter

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.

Links

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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

pre-commit-elisp – Pre-commit hooks for Emacs Lisp (Elisp) Git repositories

The pre-commit-elisp repository offers pre-commit hooks for Emacs Lisp (Elisp) projects. These hooks enforce code quality and consistency by performing automated checks on .el files prior to committing changes:

  • elisp-check-parens: Validates that all parentheses in .el files are correctly balanced.
  • elisp-check-byte-compile: Byte-compile Elisp files to detect compilation errors.
  • elisp-check-native-compile: Native-compile Elisp files to detect compilation errors.
  • elisp-indent: Indent Elisp files according to Emacs Lisp style conventions.

These pre-commit hooks enforce syntactic correctness, successful byte-compilation, and consistent code formatting, ensuring a high standard of code quality and maintainability throughout the repository.

If this enhances your workflow, please show your support by ⭐ starring pre-commit-elisp on GitHub to help more Emacs users discover its benefits.

Installation

  1. Install pre-commit.

  2. Add the following to your .pre-commit-config.yaml:

---

repos:
  - repo: https://github.com/jamescherti/pre-commit-elisp
    rev: v1.0.9
    hooks:
      # Validate that all parentheses in .el files are correctly balanced
      - id: elisp-check-parens

      # Byte-compile .el files to identify compilation errors early
      - id: elisp-check-byte-compile
        exclude: '(^|/)\.dir-locals\.el$'

      # Optional: Native-compile .el files to identify compilation errors early
      # - id: elisp-check-native-compile
      #   exclude: '(^|/)\.dir-locals\.el$'

      # Optional: Indent Elisp files according to Emacs Lisp style conventions
      # - id: elisp-indent
  1. Install the hooks in your project:
pre-commit install
  1. Run hooks manually on all files (optional):
pre-commit run --all-files

Customizations

Customizing load-path

Scripts such as elisp-check-byte-compile, elisp-byte-compile, elisp-check-native-compile, elisp-native-compile support customizing the load-path variable using a .dir-locals.el variable pre-commit-elisp-load-path. This variable allows specifying the directories that should be included in the load-path without modifying the scripts themselves, ensuring that dependencies and libraries located in the project or its subdirectories are correctly available for byte-compilation.

Customizing the load-path allows the byte-compilation and native-compilation scripts, such as elisp-check-byte-compile, to find and load project-specific Emacs Lisp files during compilation.

Here is an example of a .dir-locals.el file to place at the root of the Git repository:

;; pre-commit .dir-locals.el
((nil . ((pre-commit-elisp-load-path . ("."
                                        "lib/"
                                        "tools/utils/"))
         ;; This makes the byte-compiler report warnings with as errors
         (pre-commit-elisp-error-on-compile-warning . t))))

The pre-commit-elisp-load-path list is a list of directories relative to the Git repository root or project directory.

Each entry in the list determines how it is added to load-path:

  1. Directory ends with a slash (/): Recursively adds the directory and all its subdirectories to load-path. Example: "lib/" adds lib/ and all its subdirectories.

  2. Directory does not end with a slash: The directory is added non-recursively. Example: "utils" adds only the utils directory, not its subdirectories.

License

The pre-commit-elisp hooks have 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) 2025-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.

Links

Other Emacs packages by the same author:

  • minimal-emacs.d: This repository hosts a minimal Emacs configuration designed to serve as a foundation for your vanilla Emacs setup and provide a solid base for an enhanced Emacs experience.
  • 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.
  • 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.
  • buffer-guardian.el: Automatically saves Emacs buffers without requiring manual intervention. By default, it triggers a save when the user switches to another buffer, switches to another window or frame, Emacs loses focus, or the minibuffer is opened. Beyond standard file buffers, buffer-guardian also manages specialized editing buffers such as org-src and edit-indirect. Additional features, disabled by default, include periodic or idle-time saving of all buffers, automatic exclusion of remote, nonexistent, or large files, and support for custom exclusion rules via regular expressions or predicate functions.

Related external links

Using Emacs vc-diff with tools such as git-crypt or Rails credentials: Handling Binary Diff Issues

Tools like git-crypt or Rails credentials provide an encryption layer for managing sensitive files within Git repositories. However, when using Emacs vc-diff on repositories protected by these tools, the diff output is incorrect because vc-diff compares the encrypted binary files directly rather than comparing the decrypted files. This occurs even when the repository is unlocked and the decrypted content is available, resulting in a failure to display meaningful diffs.

The root cause

Internally, vc-diff uses Git commands to compute diffs. However, it does not invoke them with the --textconv flag by default. Without --textconv, Git does not apply content filters, including decryption filters specified by tools such as git-crypt or Rails credentials. Consequently, Emacs vc-diff displays diffs of the raw binary files rather than the decrypted content.

The solution

A workaround for enabling human-readable diffs of encrypted files in Emacs is to modify the vc-git-diff-switches variable to include the --textconv argument:

;; Emacs vc-diff fails to produce meaningful output on git-crypt enabled
;; repositories because it does not use Git's --textconv flag by default. This
;; flag enables Git to apply text conversion filters (e.g., for encrypted files)
;; when generating diffs. Without it, vc-diff compares raw encrypted blobs, even
;; when the working tree shows decrypted content.
(unless (member "--textconv" vc-git-diff-switches)
  (setq vc-git-diff-switches (cons "--textconv" vc-git-diff-switches)))Code language: Lisp (lisp)

Adding the --textconv flag to the vc-git-diff-switches variable enables Emacs vc-diff to apply the text conversion filters specified in .gitattributes. This resolves the issue by displaying the diff of the decrypted files instead of the encrypted binary files.

Further Reading