Emacs: Enhancing up and down subtree movement in outline-mode and outline-minor-mode

When editing outlined files (e.g., using the built-in outline-minor-mode, or packages like outline-indent.el, outline-yaml.el, etc.), handling subtrees efficiently can significantly enhance productivity, especially when working with complex documents. If you’re familiar with outline-mode or outline-minor-mode, you might have noticed that the built-in functions for moving subtrees up and down, outline-move-subtree-up and outline-move-subtree-down:

  • Blank line exclusion: outline-move-subtree-up and outline-move-subtree-down exclude the last blank line of the subtree when the outline-blank-line variable is set to t. Setting outline-blank-line to t is worthwhile because it retains a visible blank line after the subtree and before the next heading, improving the readability of the document.
  • Cursor position reset: After moving a subtree up or down, the cursor position is often reset, which can be disruptive during editing.

Here’s how you can address these issues by using custom functions to enhance subtree movement:

(require 'outline)

(defun my-advice-outline-hide-subtree (orig-fun &rest args)
  "Advice for `outline-hide-subtree'.
This ensures that the outline is folded correctly by
outline-move-subtree-up/down, preventing it from being unable to open the fold."
  (let ((outline-blank-line
         (if (bound-and-true-p my-outline-hide-subtree-blank-line-enabled)
             my-outline-hide-subtree-blank-line
           outline-blank-line)))
    (apply orig-fun args)))

(defun my-advice-outline-move-subtree-up-down (orig-fun &rest args)
  "Move the current subtree up/down past ARGS headlines of the same level.
This function ensures the last blank line is included, even when
`outline-blank-line' is set to t. It also restores the cursor position,
addressing the issue where the cursor might be reset after the operation."
  (interactive "p")
  (let ((column (current-column))
        (outline-blank-line nil)
        (my-outline-hide-subtree-blank-line-enabled t)
        (my-outline-hide-subtree-blank-line outline-blank-line))
    (apply orig-fun (or args 1))
    (move-to-column column)))

(advice-add 'outline-hide-subtree
            :around #'my-advice-outline-hide-subtree)
(advice-add 'outline-move-subtree-up
            :around #'my-advice-outline-move-subtree-up-down)
(advice-add 'outline-move-subtree-down
            :around #'my-advice-outline-move-subtree-up-down)Code language: Lisp (lisp)

I also recommend using Ctrl-Up and Ctrl-Down key bindings for moving subtrees up and down.

(define-key outline-mode-map (kbd "C-<up>") 'outline-move-subtree-up)
(define-key outline-mode-map (kbd "C-<down>") 'outline-move-subtree-down)

(defun my-setup-outline-minor-mode-keybindings ()
    "Set up keybindings for moving subtrees in `outline-minor-mode'."
  (define-key outline-minor-mode-map (kbd "C-<up>") 'outline-move-subtree-up)
  (define-key outline-minor-mode-map (kbd "C-<down>") 'outline-move-subtree-down))
(add-hook 'outline-minor-mode-hook 'my-setup-outline-minor-mode-keybindings) Code language: Lisp (lisp)

With this setup, you will ensure that every time you use outline-move-subtree-up or outline-move-subtree-down, the last blank line of the subtree is included and the cursor position is restored.

Elispcomp: Compiling Elisp code directly from the command line

(The author also recommends trying: compile-angel.el, an Emacs package that automatically byte-compiles and native-compiles .el Elisp libraries, transparently, without any user intervention.)

Introduction

The elispcomp command line tool allows compiling Emacs Lisp (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, which can significantly improve the performance of Emacs.

The command line tool executes a headless instance of Emacs and Elisp that recursively scans the specified directories, byte compiling and native compiling all the .el files that haven’t been compiled yet. It supports various configuration options, allowing you to adapt the compilation process to suit your needs.

When configured appropriately, Emacs can compile to both .elc and .eln files. However, for those who wish to automate the background compilation of .el files using a script, the elispcomp command-line tool can be beneficial in ensuring that their Emacs setup remains up-to-date without manual intervention and without starting an Emacs instance.

Installation

To get started with elispcomp, you can install it using pip:

pip install --user elispcomp

This command installs elispcomp and places the executable in your ~/.local/bin/ directory, making it easily accessible from your command line.

Requirements

  • Python 3
  • Emacs >= 28

Usage

The elispcomp command line tool is straightforward to use.

First example: To compile all .el files located in the ~/.emacs.d/lisp directory:

elispcomp ~/.emacs.d/lisp

Second example: To compile all .el files located in the ~/.emacs.d/lisp directory, and store the native-compiled files in the ~/.emacs.d/eln-cache directory:

elispcomp --eln-cache ~/.emacs.d/eln-cache ~/.emacs.d/lisp

Command line options

usage: elispcomp [--option] [N]

Recursively byte and native compile .el files.

positional arguments:
  N                     The directories to be scanned recursively by Emacs to locate the '.el'
                        files for compilation.

options:
  -h, --help            show this help message and exit
  -c ELN_CACHE, --eln-cache ELN_CACHE
                        The eln-cache directory where Emacs stores the compiled native compiled
                        code. Defaults to the default Emacs eln-cache directory.
  -e EMACS_BIN, --emacs-bin EMACS_BIN
                        Path to the Emacs binary. Defaults: emacs
  -j JOBS, --jobs JOBS  Specify the number of parallel jobs for compilation. Default: Half the
                        number of available CPUs
  -b, --disable-byte-compile, --disable-byte-comp
                        Disable byte compile. Default: enabled
  -n, --disable-native-compile, --disable-native-comp
                        Disable native compilation. Default: enabled
  -i LOAD_PATH, --load-path LOAD_PATH
                        Recursively adds the subdirectories of the specified directory to the
                        Emacs `load-path`. This option can be used multiple times to include
                        several directories.
  -a, --ensure-native-compile-available, --ensure-native-comp-available
                        Fail when native compilation is not available.

Frequently asked questions

Can’t I achieve the same result using Emacs?

Indeed, when configured appropriately, Emacs can compile to both .elc and .eln files.

The elispcomp command-line tool is an Emacs wrapper that makes it easy to compile Emacs Lisp (Elisp) code directly from the terminal or from a script. It provides options and ensures that the byte compilation and native compilation processes are truly finished before quitting.

The elispcomp command-line tool can also be used in conjunction with other tools like parallel to speed up the compilation process.

How does the author utilize elispcomp?

The author utilizes the elispcomp tool to compile multiple Emacs Lisp files across various machines and Emacs versions. With a diverse range of machines and Emacs versions in his workflow, elispcomp ensures consistent compilation results and compatibility.

Additionally, the author employs the parallel command-line tool to enhance the efficiency of the byte-compilation process. This tool allows the distribution of the compilation workload across multiple processors, significantly accelerating the process.

Is elispcomp written in Python or Elisp?

Most of what elispcomp does is written in Elisp (Emacs Lisp), including scanning directories, which is handled by the Emacs functions (byte-recompile-directory) and (native-compile-async). Python handles the command-line interface (arguments), and Emacs and the Elisp code does the rest (byte compilation, native compilation, and waiting until all the .el files are byte compiled and native compiled).

License

The elispcomp 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. If not, see https://www.gnu.org/licenses/.

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 any 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).
  • 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 Evil Mode: Disabling the automatic removal of spaces after leaving Insert mode

By default, Emacs evil-mode removes newly inserted spaces when exiting insert mode. However, some users may find this disruptive to their workflow. This is particularly true for those who edit file formats where trailing spaces are significant or who simply prefer to manage whitespace manually.

To prevent the automatic removal of trailing spaces when leaving insert mode, add the following Elisp code to the Emacs init file:

(with-eval-after-load 'evil
  (defun my-evil-disable-remove-spaces ()
    "Disable automatic removal of trailing spaces in `evil-mode'."
    (setq-local evil-maybe-remove-spaces nil))

  (add-hook 'evil-insert-state-entry-hook #'my-evil-disable-remove-spaces))Code language: Lisp (lisp)

The function above sets the evil-maybe-remove-spaces variable to nil when entering insert mode, preventing the evil-maybe-remove-spaces function from deleting whitespace after leaving insert mode.

The evil-insert-state function, which Evil uses to switch to insert mode, behaves as follows:

  • When entering insert mode: It sets the evil-maybe-remove-spaces variable to t.
  • When exiting insert mode, it calls the evil-maybe-remove-spaces function, which removes trailing spaces if the evil-maybe-remove-spaces variable is set to t. Because the my-evil-disable-remove-spaces function above sets the evil-maybe-remove-spaces variable to nil when entering insert mode, it prevents the evil-maybe-remove-spaces function from deleting whitespace after leaving insert mode.

If you want to compare the behavior before and after the function above, use whitespace-mode. This mode visually highlights different types of whitespace characters, such as spaces, tabs, and newlines, making it easier to see the differences.

Customizing evil-mode with the simple piece of Elisp code above can prevent the automatic removal of trailing spaces when exiting insert mode. This adjustment allows for better control over whitespace in files.

Emacs: Customizing the Ellipsis “…” in outline-mode and outline-minor-mode to Use a More Visually Appealing Indicator for Folded Sections, Such as ” ▼”

The built-in Emacs outline-mode and outline-minor-mode allow structuring documents with collapsible sections. By default, these modes use an ellipsis (“…”) to indicate folded text. However, the default ellipsis and its face can make it hard to distinguish between folded text and regular text. This is why it can be beneficial to customize the ellipsis.

The code snippets provided in this article allow for customizing the ellipsis locally within a buffer.

Set the buffer local outline ellipsis

To apply the ellipsis locally to a buffer, the following Elisp code snippet modifies the display settings within that buffer.

The ellipsis string is displayed using the shadow face for visual consistency. Internally, a buffer-local display table is constructed (or reused if one already exists), and the selective display slot is updated to render the given ellipsis.

Here is the Emacs Lisp code snippet to achieve this:

(defun my-outline-set-buffer-local-ellipsis (ellipsis)
  "Set a buffer-local ellipsis string ELLIPSIS for outline folding display.

This function configures the current buffer to use a custom ellipsis string for
selective display, typically in `outline-mode' or `outline-minor-mode'.

The string ELLIPSIS is trimmed of trailing whitespace before use, as such
whitespace can be misleading when lines are truncated or visually wrapped. In
those cases, the trailing space may appear on a new visual line, creating the
false impression of an additional line. Deleting this apparent line can
inadvertently remove the entire folded logical line."
  (let* ((display-table (or buffer-display-table (make-display-table)))
         (face-offset (* (face-id 'shadow) (ash 1 22)))
         (value (vconcat (mapcar (lambda (c)
                                   (+ face-offset c))
                                 (string-trim-right ellipsis)))))
    (set-display-table-slot display-table 'selective-display value)
    (setq buffer-display-table display-table)))Code language: Lisp (lisp)

Here is an example of applying a buffer-local ellipsis when outline-minor-mode is enabled:

(add-hook 'outline-minor-mode-hook
          #'(lambda()
              (my-outline-set-buffer-local-ellipsis " ▼")))Code language: PHP (php)

The Elisp code above will change the outline-mode and outline-minor-mode ellipsis to:

(The screenshot above shows a YAML file folded using outline-indent.el, which leverages outline-minor-mode to enable code folding, , serving as a modern replacement for deprecated packages such as origami.)

Conclusion

Customizing the ellipsis in outline-mode and outline-minor-mode is a simple yet effective way to personalize your Emacs and create a more visually appealing way to handle folds.

Emacs: YAML file code Folding and Outlining

Working with long and complex YAML files can be a daunting task. In such cases, code folding becomes an invaluable tool, allowing the collapse and expansion of sections of the file and enhancing readability and navigation. This makes it easier to focus on specific parts of the code without being overwhelmed by the entire document.

To address this need, I would like to introduce you to outline-indent.el, a minor mode for Emacs that brings code folding and outlining capabilities to Emacs, making editing YAML and other languages more efficient and enjoyable.

How to change the Ellipsis (…) to (▼)?

The code snippet in this article can be used to to change the Ellipsis to ▼.

Enabling Emacs Native Compilation and Dynamically Adjusting the Number of Elisp Files Compiled in Parallel

Recommendation: The compile-angel Emacs package automatically byte-compiles and native-compiles Emacs Lisp libraries. It speeds up Emacs by ensuring all libraries are byte-compiled and native-compiled.

Emacs has experienced a significant performance boost with the introduction of native compilation, available from version 27 and above. This feature converts Emacs Lisp code into machine-level code, enabling faster execution and enhanced responsiveness.

Speeding up compilation by using the maximum number of available CPU cores significantly reduces compilation time. However, it’s also necessary to leave a few CPU cores free to ensure the operating system runs smoothly, including the graphical user interface, shells, and other processes. The source code snippet outlined in this article is designed to effectively manage resources by allocating CPU cores for native compilation while reserving some for system operations.

Configuring native compilation and adjusting the number of parallel compilations

To configure native compilation and dynamically adjust the number of parallel compilations, add the following code snippet to early-init.el or init.el:

;; Description: Enable native compilation and dynamically adjust
;; the number of Elisp files compiled in parallel.
;;
;; Compatible with: Emacs >= 28.1 (because `num-processors' is required)
;;
;; URL: https://www.jamescherti.com/emacs-native-compilation-config-jobs/
;; License: MIT
;; Author: James Cherti

(defvar my-native-comp-reserved-cpus 2
  "Number of CPUs to reserve and not use for `native-compile'.")

(defun my-calculate-native-comp-async-jobs ()
  "Set `native-comp-async-jobs-number' based on the available CPUs."
  ;; The `num-processors' function is only available in Emacs >= 28.1
  (max 1 (- (num-processors) my-native-comp-reserved-cpus)))

(if (and (featurep 'native-compile)
         (fboundp 'native-comp-available-p)
         (native-comp-available-p))
    ;; Activate `native-compile'
    (setq native-comp-async-jobs-number (my-calculate-native-comp-async-jobs)
          native-comp-deferred-compilation t
          package-native-compile t)
  ;; Deactivate the `native-compile' feature if it is not available
  (setq features (delq 'native-compile features)))Code language: Lisp (lisp)

What does the source code snippet above do?

  • Reserves CPUs: Sets aside 2 CPUs to not be used by the native compilation feature in Emacs.
  • Calculates Available CPUs for Compilation: Determines how many CPUs can be used for compiling Emacs Lisp files by subtracting the reserved CPUs from the total count.
  • Sets Native Compilation Parameters: Configures Emacs to use the calculated number of CPUs for parallel compilation tasks.
  • Ensures Feature Availability: Activates native compilation settings only if the feature is supported and available, otherwise deactivates it.
  • Optimizes Performance: Aims to enhance Emacs performance by efficiently using system resources without overloading the system.

How to check if native compilation is available?

To check whether native compilation is supported, you can run the following Emacs Lisp code:

(message (if (and (fboundp 'native-comp-available-p)
                  (native-comp-available-p))
             "Native compilation is available"
           "Native compilation is *not* available"))
Code language: Lisp (lisp)

Conclusion

Managing system resources efficiently is key to maintaining optimal performance in Emacs, especially when using the native compilation feature. The source code snippet outlined in this article provides a dynamic method for adjusting the number of native compilation jobs according to the number of available CPUs. This enhances the responsiveness and efficiency of Emacs without overloading the system.

Emacs Theme: Tomorrow Night Deepblue, a beautiful theme with a deep blue background

Build Status MELPA MELPA Stable License

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.

The Tomorrow Night Deepblue theme 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.

(Show your support by ⭐ starring tomorrow-night-deepblue-theme on GitHub to help more Emacs users discover it.)

Table of Contents

Screenshot

The theme was inspired by classic text editors such as QuickBASIC, RHIDE, and Turbo Pascal, as well as tools such as Midnight Commander which featured blue backgrounds by default. There’s something special about the early days of programming and the tools we used that brings back fond memories.

Installation

To install tomorrow-night-deepblue-theme 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 tomorrow-night-deepblue from MELPA:

(use-package tomorrow-night-deepblue-theme
  :config
  (let ((inhibit-redisplay t))
    ;; Disable all active themes
    (mapc #'disable-theme custom-enabled-themes)
    ;; Load the tomorrow-night-deepblue theme
    (load-theme 'tomorrow-night-deepblue t)))

What are the differences between Tomorrow Night Blue and Deepblue themes?

The main differences lie in the background and a large number of additional faces, which enable support for many more modern Emacs packages. Currently, Tomorrow Night Deepblue supports over 1,170 faces (compared to 333 in the original version), featuring a background color reminiscent of classic editors. The author plans to make further changes to support even more faces. Contributions are welcome!

The background is also different. Here is the background color of the Tomorrow Night Deepblue:

And this background color or the Tomorrow Night Blue, the previous version upon which this theme is based:

Authors

The Tomorrow Night Deepblue Emacs theme 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.

The tomorrow-night-deepblue theme is based on Tomorrow Night Blue by Chris Kempson, Steve Purcell, and Donald Curtis.

License

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).
  • 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.
  • 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.

Making the Emacs built-in tab-bar Look Like Vim’s Tab Bar

Build Status MELPA MELPA Stable License

The vim-tab-bar package makes Emacs’s built-in tab bar look like Vim’s tab bar.

Beyond its Vim-inspired appearance, vim-tab-bar automatically adapts to the active Emacs theme, to provide a visually coherent and polished interface across different themes.

(If you like vim-tab-bar, please show your support by ⭐ starring vim-tab-bar on GitHub to help more Emacs users discover its benefits.)

For users unfamiliar with Emacs’ built-in tab-bar: Emacs’ tab-bar allows users to manage multiple independent workspaces, each comprising its own set of window layouts. This goes beyond simply organizing tabs for different tasks or projects; it enables users to switch between distinct contexts, such as coding, reading documentation, or managing emails, without losing track of their previous work. It is similar to how web browsers or other editors use tabs, but offers far greater control over workspace organization and layout.

Table of Contents

Features

  • The vim-tab-bar package ensures that tabs maintain a uniform appearance regardless of the theme used. This is also beneficial those who use themes that do not configure the tab-bar properly.
  • Group Formatting: Optionally display and format tab groups.
  • Makes the Emacs tab-bar (Emacs version >= 27.1) look in a manner reminiscent of Vim’s tabbed browsing interface:

(The screenshot above shows how the vim-tab-bar package makes the Emacs tab-bar appear)

Installation

To install vim-tab-bar 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 vim-tab-bar from MELPA:

(use-package vim-tab-bar
  :commands vim-tab-bar-mode
  :hook
  (after-init . vim-tab-bar-mode))

Usage

The default keybindings for Emacs’s built-in tab-bar are as follows:

  • C-x t 2: Create a new tab (tab-bar-new-tab / tab-new)
  • C-x t b RET: Switch to a buffer in a new tab (switch-to-buffer-other-tab)
  • C-x t f RET: Open a file in a new tab (find-file-other-tab)
  • C-x t d RET: Open Dired in a new tab (dired-other-tab)
  • C-x t t C-x b RET: Use the tab-bar command prefix, then run any buffer-related command (e.g., other-tab-prefix, followed by switch-to-buffer)
  • C-x t o or C-TAB: Switch to the next tab (tab-bar-switch-to-next-tab)
  • S-C-TAB: Switch to the previous tab (tab-bar-switch-to-prev-tab)
  • C-x t RET: Switch to a named tab with completion (tab-switch)

Frequently asked questions

How to Show the tab groups?

By default, tab groups are not displayed. You can make tab-bar-vim display them by setting the variable:

(setq vim-tab-bar-show-groups t)

How to Automatic hide the Vim Tab Bar?

By default, vim-tab-bar displays the Vim tab bar whenever it is enabled. To hide the tab bar when only a single tab exists, enable the following option:

;; Hide the Vim Tab Bar when only a single tab exists
(customize-set-variable 'tab-bar-show 1)

Explanation:

  • If tab-bar-show is set to t (default), which is the default, automatically enable Vim tab bar when commands that create new window configurations are used, such as `tab-new’.

  • If tab-bar-show is set to a non-negative integer, display the tab bar only when the number of tabs exceeds that value. In particular, a value of 1 hides the tab bar when only a single tab exists and shows it again when additional tabs are created. When a non-negative integer is used, tab bar visibility is determined independently for each frame, depending on the number of tabs present in that frame and whether it exceeds the specified value.

  • If set to nil, keep the tab bar permanently hidden. In this case, persistent named window configurations remain available through keyboard commands such as tab-new, tab-close, tab-next, and tab-switcher.

Screenshots

The screenshots below shows how the vim-tab-bar package makes the Emacs tab-bar appear:

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).
  • 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.
  • 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 Evil Mode: How to restore both the line and column number of a mark, not just the line number

In Emacs with Evil mode, similar to Vim, a mark represents a position in the buffer that you can set and later return to, facilitating quick navigation between different locations within a file.

Set and restore a mark

You can set a mark by pressing the m button followed by a letter. For example, pressing ma sets a mark at the current cursor position and associates it with the letter a. To restore a mark, press either the backtick (`) or the single quote (') followed by the associated letter. For instance, pressing 'a restores the cursor to the line of the mark, while pressing `a moves the cursor to the exact line and column of the mark.

How to use a single quote instead of a backtick to restore both the line and column numbers of a mark

If you prefer using the single quote (') to restore both the line and column number of a mark, I’ve made a small change to accommodate this preference. The following Elisp code ensures that the single quote (') restores both the line and column, while the backtick (`) restores only the line:

(define-key evil-motion-state-map "`" 'evil-goto-mark-line)
(define-key evil-motion-state-map "'" 'evil-goto-mark)Code language: Lisp (lisp)

Emacs: Striking through Org Mode DONE tasks

It’s always satisfying to cross something off a to-do list, almost like declaring to yourself, ‘I did it!’ That’s the feeling I wanted to bring into Emacs Org Mode.

The following Emacs Lisp (Elisp) code instructs Emacs to apply a strike-through to any task marked as DONE:

;; Enable the fontification of headlines for tasks that have been marked as
;; completed.
(setq org-fontify-done-headline t)

(custom-set-faces
 ;; Face used for todo keywords that indicate DONE items.
 '(org-done ((t (:strike-through t))))

 ;; Face used to indicate that a headline is DONE. This face is only used if
 ;; ‘org-fontify-done-headline’ is set. If applies to the part of the headline
 ;; after the DONE keyword.
 '(org-headline-done ((t (:strike-through t)))))
Code language: Lisp (lisp)

By adding strike-through for completed items, Emacs Org Mode becomes clearer and more satisfying to use.

Emacs: Functions to evaluate Elisp Code, then display the result or copy it to the clipboard

The Elisp code below introduces three functions designed to evaluate Emacs Lisp code, either under the cursor or within a selected text region. These functions can return the evaluation result, copy it to the clipboard, or display it in the minibuffer. The functions allow obtaining immediate feedback from the code evaluation.

;; License: MIT
;; Author: James Cherti
;; URL: https://www.jamescherti.com/emacs-evaluate-elisp-display-result-copy-clipboard/
;;
;; Description: The following source code snippet introduces three functions
;; designed to evaluate Emacs Lisp code, either under the cursor or within a
;; selected text region. These functions can return the evaluation result, copy
;; it to the clipboard, or display it in the minibuffer. The functions are
;; especially useful for obtaining immediate feedback from the code evaluation.

(defun my-eval-and-get-result ()
  "Evaluate Elisp code under cursor or in the active region, then return the
result. If there is a syntax error or any other error during evaluation, an
error message is displayed."
  (interactive)
  (let* ((elisp-code (if (use-region-p)
                         (buffer-substring-no-properties (region-beginning)
                                                         (region-end))
                       (buffer-substring-no-properties (line-beginning-position)
                                                       (line-end-position)))))
    (condition-case err
        (let ((result (format "%S" (eval (read elisp-code)))))
          result)
      (error (message "Error: %s" (error-message-string err)))
      nil)))

(defun my-eval-and-copy-result-to-clipboard (&optional display-result)
  "Evaluate Elisp code under cursor or in the active region, copy the result to
the clipboard. With a prefix argument, also display the result using message."
  (interactive)
  (let ((result (my-eval-and-get-result)))
    (when result
      (kill-new result)
      (when display-result
        (message "%s" result)))))

(defun my-eval-and-copy-clipboard-and-print-result ()
  "Evaluate Elisp code under cursor or in the active region, copy the result to
  the clipboard, and display the result."
  (interactive)
  (my-eval-and-copy-result-to-clipboard t))

(defun my-eval-and-print ()
  "Evaluate Elisp code under cursor or in the active region, display the
result."
  (interactive)
  (let ((result (my-eval-and-get-result)))
    (when result
      (message "%s" result))))
Code language: Lisp (lisp)

Configure Emacs org-mode to automatically add the TODO keyword to new Org Mode headings

The built-in method used by Emacs Org mode to insert new headings does not automatically prepend the inserted heading with TODO, except when C-S-<return> is pressed. I prefer using C-<return> for all headings, whether they are to-do tasks or not, to maintain my workflow efficiency. This motivated me to write the function outlined in this article.

The function below can be triggered by pressing C-<return> to insert a new Org heading. If activated while on a TODO task, it will prefix the inserted heading with TODO, effectively creating a new to-do item. Additionally, for users of evil-mode, the function transitions into insert mode.

;; Function: (my-org-insert-heading-respect-content-and-prepend-todo)
;; Author: James Cherti
;; License: MIT
;; Key binding: Ctrl-Enter
;; URL: https://www.jamescherti.com/emacs-add-todo-keyword-to-new-org-mode-headings/
;;
;; Description: The function inserts a new heading at the current cursor
;; position, and prepends it with "TODO " if activated while on a "TODO" task,
;; thus creating a new to-do item. In addition to that, for those utilizing
;; evil-mode the function transitions the user into insert mode right after the
;; "TODO " insertion.

(defun my-org-insert-heading-respect-content-and-prepend-todo ()
    "Insert a new org-mode heading respecting content and prepend it with 'TODO'.
  Additionally, ensure entry into insert state when evil-mode is active."
    (interactive)
    (let ((entry-is-todo (org-entry-is-todo-p)))
      (when (bound-and-true-p evil-mode)
        (evil-insert-state))
      (org-insert-heading-respect-content)
      (when entry-is-todo
        (just-one-space)
        (insert "TODO")
        (just-one-space))))

;; Replace the key bindings for inserting headings in Org mode
(define-key org-mode-map (kbd "C-<return>")
            'my-org-insert-heading-respect-content-and-prepend-todo)
Code language: Lisp (lisp)

Emacs: Open a Vertico/Consult or Ivy/Counsel candidate in a new tab

In this article, you will find code snippets designed to simplify the task of opening Vertico/Consult/Embark or Ivy/Counsel candidates in a new Emacs tab using tab-bar.

The generic function that opens candidates in a new tab

This function below, tab-new-func-buffer-from-other-window, is designed to open the buffer generated by a specified function (func) in the other window and subsequently create a new tab. It also ensures that the state of the original window and tab is preserved.

;; License: MIT
;; Author: James Cherti
;; URL: https://www.jamescherti.com/emacs-open-vertico-consult-ivy-counsel-candidate-new-tab/

(defun tab-new-func-buffer-from-other-window (func)
  "Open the buffer created by the FUNC function in the other window in a new tab."
  (let* ((original-tab-index (1+ (tab-bar--current-tab-index)))
         (original-window (selected-window)))
    ;; Save the state of the other window
    (other-window 1)
    (let* ((other-window (selected-window))
           (other-window-buf (current-buffer))
           (other-window-point (point))
           (other-window-view (window-start)))
      ;; Move back to the original window
      (other-window -1)

      ;; Call the specified function (e.g., embark-dwim, ivy-call...)
      (funcall func)

      ;; Switch back to the other window
      (other-window 1)
      (unless (eq (selected-window) original-window)
        (let* ((preview-buf (current-buffer)))
          ;; Create a new tab and switch to the preview buffer
          (tab-bar-new-tab)
          (switch-to-buffer preview-buf)

          ;; Go back to the original tab
          (tab-bar-select-tab original-tab-index)

          ;; Restore the state of the other window
          (select-window other-window)
          (switch-to-buffer other-window-buf)
          (goto-char other-window-point)
          (set-window-start nil other-window-view)

          ;; Switch to the original window
          (select-window original-window))))))Code language: Lisp (lisp)

Option 1: Open Vertico, Consult, and Embark candidate in a new tab (embark-dwim)

For users of Vertico/Consult/Embark, the following function utilizes the generic function to open the default Embark action buffer in a new tab:

(defun tab-new-embark-dwim ()
  "Open embark-dwim in a new tab."
  (interactive)
  (tab-new-func-buffer-from-other-window #'embark-dwim))Code language: Lisp (lisp)

You can add the following key mapping to Vertico:

(keymap-set vertico-map "C-t" #'tab-new-embark-dwim)Code language: Lisp (lisp)

For Emacs Evil users, you can also add the following mappings:

(evil-define-key '(insert normal) vertico-map (kbd "C-t") 'tab-new-embark-dwim)
Code language: Lisp (lisp)

Option 2: Open Ivy, Counsel candidates in a new tab (ivy-call)

For users of Counsel/Ivy, the following function utilizes the generic function above to open the buffer created by ivy-call in a new tab:

(defun tab-new-ivy-call ()
  "Open ivy-call in a new tab."
  (interactive)
  (tab-new-func-buffer-from-other-window #'ivy-call))Code language: Lisp (lisp)

You can add the following key mapping to ivy-minibuffer-map:

(keymap-set ivy-minibuffer-map "C-t" #'tab-new-ivy-call)Code language: Lisp (lisp)

For Emacs Evil users, you can also add the following mappings:

(evil-define-key '(insert normal) ivy-minibuffer-map (kbd "C-t") 'tab-new-ivy-call)Code language: Lisp (lisp)

Preventing Emacs from entering the debugger when a specific error occurs

Emacs provides a built-in feature called debug-on-error, which can be activated with (setq debug-on-error t). The feature determines whether Emacs should enter the debugger when an error occurs. By default, Emacs enters the debugger for all errors, which can be helpful for diagnosing issues. However, there are cases where one may want to ignore specific errors that are not critical to their workflow.

Ignoring specific errors when (setq debug-on-error t) is activated

Open the Emacs configuration file, typically located at ~/.emacs or ~/.emacs.d/init.el. Then use the debug-ignored-errors variable to make Emacs ignore a specific error:

(add-to-list 'debug-ignored-errors 'specific-error-symbol)Code language: plaintext (plaintext)

Replace 'specific-error-symbol with the actual error that the specific function might raise.

Example

Suppose you encounter the search-failed error in Emacs (Evil package) when searching for a non-existent pattern:

Debugger entered--Lisp error: (search-failed "my-pattern")
  signal(search-failed ("my-pattern"))
  evil-ex-start-search(forward nil)
  evil-ex-search-forward(nil)
  funcall-interactively(evil-ex-search-forward nil)
  command-execute(evil-ex-search-forward)Code language: plaintext (plaintext)

To make Emacs ignore the search-failed error above, the following can be used:

(add-to-list 'debug-ignored-errors 'search-failed)Code language: plaintext (plaintext)

Emacs .dir-locals.el – Add project path to $PYTHONPATH (Python Development in Emacs)

In order to ensure that the processes executed by Emacs and its packages, such as Flycheck or Flymake, can access the Python modules of a project, it is essential to correctly configure the $PYTHONPATH environment variable.

This article provides a solution by introducing a .dir-locals.el file that adds the directory path of .dir-locals.el to the $PYTHONPATH environment variable.

The .dir-locals.el file should be placed in the root directory of a Python project.

File name: .dir-locals.el

;; -*- mode: emacs-lisp; -*-
;; File: .dir-locals.el
;; Description:
;; This file adds the path where `.dir-locals.el` is located to the
;; `$PYTHONPATH` environment variable to ensure that processes executed by
;; Emacs and its packages, such as Flycheck or Flymake, can access the Python
;; modules of a project.
;;
;; Author: James Cherti
;; License: MIT
;; URL: https://www.jamescherti.com/emacs-dir-locals-add-path-to-pythonpath/

((python-mode . ((eval . (progn
                           (let ((project_path
                                  (car (dir-locals-find-file
                                        (buffer-file-name))))
                                 (python_path_env (getenv "PYTHONPATH")))
                             (setq-local process-environment
                                         (cons
                                          (concat "PYTHONPATH="
                                                  project_path
                                                  (if python_path_env
                                                      (concat ":" python_path_env)
                                                    ""))
                                          process-environment))))))))
Code language: Lisp (lisp)