About James Cherti

James Cherti is an experienced Infrastructure and Software engineer. He has written high-quality Python, Bash, C/C++, PHP, JavaScript source codes, administered Linux servers, and delivered several presentations in universities. He is also an active Open Source contributor.

Matter Door/Window Sensor and Google Home: Script for Announcing Door Open and Close Events

The Matter standard enables smart home devices from different manufacturers to work together in a reliable and secure way. One common use case is detecting when a door is opened or closed and announcing this event through Google Home speakers or sending notifications to connected devices.

This article demonstrates how to configure Google Home to announce door events using Matter-compatible sensors such as the Aqara Door and Window Sensor P2. The example uses Google Home script automations to broadcast voice announcements and trigger mobile notifications whenever the entrance door changes state.

Requirements

  • A Matter-compatible door and window sensor.
  • A Google Speaker for announcements.
  • The Google Home application with the script editor enabled, accessible via the web interface at https://home.google.com/ .

Door Closed Announcement Script

The following script broadcasts a voice message and sends a notification when the door transitions to the closed state (sensor reports openPercent = 0):

metadata:
  name: Door closed announcement
  description: Announce when the door is closed
automations:
  - starters:
      - type: device.state.OpenClose
        device: Entrance door - Entryway
        state: openPercent
        is: 0
    actions:
      - type: assistant.command.Broadcast
        message: The door was closed

      - type: home.command.Notification
        title: The door was closed
        body: The door was closedCode language: YAML (yaml)

Note: Replace "Entrance door - Entryway" in the scripts with the actual name of the Matter-compatible door and window sensor as configured in Google Home. The device name must match exactly for the automations to work correctly.

When the door closes, the Google Assistant broadcasts “The door was closed” on all Google Home devices in the household, and a push notification with the same text is sent to connected mobile devices.

Door Open Announcement Script

The following script performs the same action when the door opens (sensor reports openPercent = 100):

metadata:
  name: Door open announcement
  description: Announce when the door is open
automations:
  - starters:
      - type: device.state.OpenClose
        device: Entrance door - Entryway
        state: openPercent
        is: 100
    actions:
      - type: assistant.command.Broadcast
        message: The door was opened

      - type: home.command.Notification
        title: The door was opened
        body: The door was openedCode language: YAML (yaml)

Note: Replace "Entrance door - Entryway" in the scripts with the actual name of the Matter-compatible door and window sensor as configured in Google Home. The device name must match exactly for the automations to work correctly.

In this case, Google Assistant announces “The door was opened” and the same message is sent as a push notification.

Conclusion

Combining a Matter-compatible door sensor with Google Home scripts provides real-time feedback whenever a door is opened or closed. It delivers both audible alerts throughout the home and push notifications to mobile devices, enhancing awareness and security.

ansible-role-auto-upgrade – An Ansible role that automates upgrading Linux operating systems

The auto-upgrade Ansible role automates regular upgrades of supported operating systems:

  • Debian-based systems (e.g., Ubuntu, Debian, Linux Mint). This role provides a simpler alternative to unattended-upgrades for applying system updates.

(In future versions, Arch Linux and Gentoo will also be supported.)

License

Copyright (c) 2025 James Cherti.

Distributed under terms of the MIT license.

Do you like ansible-role-auto-upgrade?

Please star ansible-role-auto-upgrade on GitHub.

Links

ansible-role-reniced – An Ansible role that configures reniced on Debian and Ubuntu based operating systems

The ansible-role-reniced Ansible role configures reniced on Debian and Ubuntu based operating systems.

Customizations

When reniced_conf is defined, it is used as the configuration content.

Include the role using:

- name: Import role reniced
  when: ansible_os_family == "Debian"
  ansible.builtin.import_role:
    name: reniced

Variables:

reniced_conf: |
  # high prio network services
  0 ^apache
  0 ^nfsd
  0 ^ntpd
  0 ^openvpn
  0 ^portmap
  0 ^ppp
  0 ^rpc.
  0 ^sshd

  # medium prio network services
  5 ^inn$
  5 ^mysqld

  # low prio network services
  15i ^amavisd-new
  15i ^clamd
  15 ^controlchan
  15 ^exim4
  15 ^freshclam
  15 ^innwatch
  12 ^mailman
  15 ^rc.news
  15i ^spamd

  # long running user processes (screen)
  3 ^irssi

  # test OOM settings
  o1 bash

Author and license

Copyright (C) 2024-2025 James Cherti.

Distributed under terms of the MIT license.

Links

ansible-role-apt – An Ansible role that manages the APT configuration and updates the /etc/apt/sources.list for Debian and Ubuntu systems

The ansible-role-apt Ansible role manages the APT configuration and updates the /etc/apt/sources.list for Debian and Ubuntu systems.

Role variables

Important variables:

VariableDescriptionDefault
apt_debian_communityEnables community repositories (Debian contrib and main, or Ubuntu universe)true
apt_debian_nonfreeEnables non-free repositories (Debian non-free, non-free-firmware, or Ubuntu multiverse)true
apt_debian_backportsEnables the backports repository on Debian (no effect on Ubuntu systems)false
apt_deb_srcEnables source package repositories (deb-src entries)false

Other variables:

VariableDescriptionDefault
apt_mirror_url_debianDebian mirror URL"http://deb.debian.org/debian"
apt_mirror_url_debian_securityDebian security mirror URL"http://deb.debian.org/debian-security"
apt_mirror_url_ubuntuUbuntu mirror URL"http://archive.ubuntu.com/ubuntu"

Links

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 serves as a lightweight Emacs interface for the sdcv command-line interface, which is the console version of the StarDict dictionary application.

This package enables Emacs to function as an offline dictionary.

This integration allows users to access sdcv dictionary functionalities directly within the Emacs environment, leveraging the capabilities of sdcv to look up words and translations from various dictionary files.

Here are the main interactive functions:

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

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

Table of Contents

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
    :ensure t
    :custom
    (quick-sdcv-dictionary-prefix-symbol "►")
    (quick-sdcv-ellipsis " ▼"))

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

Usage

Below are the commands you can use:

Command Description
quick-sdcv-search-at-point Searches the word around the cursor and displays the result in a buffer.
quick-sdcv-search-input Searches the input word and displays the result in a buffer.

If the current mark is active, the quick-sdcv will translate the region string; otherwise, they will translate the word around the cursor.

Frequently asked question

How to make the sdcv buffer replace the current buffer?

To make K search for the word using quick-sdcv when editing Markdown, you can customize the behavior as follows:

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

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

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
    :ensure t
    :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:
``` emacs-lisp
;; 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)))

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 utilizing 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-2025 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.

The Importance of Backups: Why Failing to Create or Test Them Leads to Regret

Data loss is an inevitable reality in the digital age. It is not a matter of “if,” but “when.” Whether you’re managing critical infrastructure for a large enterprise or simply storing personal documents, photos, and legal files on your own computer, the risk of data loss is ever-present. Despite this, many people and organizations fail to prioritize backups until it is too late.

Throughout my career as an IT specialist, I have witnessed this problem repeatedly. The pattern is always the same: individuals and companies lose data, panic ensues, and attempts are made to recover what could have been easily protected with minimal cost and effort.

Data loss

On a daily basis, I encounter numerous instances of data loss across various sectors. Companies pay for bare-metal servers or cloud compute instances to run their production workloads, but when these systems crash, experience filesystem corruption, or are compromised by security breaches, the response is typically one of outrage. Support tickets are submitted with complaints that their data is lost, with no backups, no snapshots, and no contingency plan in place.

This issue is not exclusive to large enterprises. Consider personal devices. How many individuals store years of important tax records, legal documents, irreplaceable family photos, or critical work files on their laptops, with no backup strategy whatsoever? Hardware failure, malware attacks, accidental deletion, theft, and simple human error can result in irreversible data loss in an instant.

Some of the cases I handled…

The cases I handled professionally can be truly staggering. For example, I worked with a client paying tens of thousands of dollars per month for a bare-metal server to host highly sensitive data, yet they had no backup strategy in place. When hardware failure inevitably occurred, the result was outrage, threats of legal action, and attempts to assign blame. Unfortunately, without a backup policy, disaster recovery plan, and monitoring system in place, these situations are often beyond repair.

In this particular instance, I worked closely with the client to establish a comprehensive backup procedure. This involved selecting an appropriate backup solution adapted to their infrastructure, setting up regular backups, and ensuring the backups were stored securely and off-site. Additionally, we implemented a monitoring system to alert the client to any potential issues before they became critical. The result is now a much more resilient system, where data loss is no longer a risk, and the client has a clear disaster recovery plan in place.

To make matters worse, I’ve witnessed scenarios where the financial cost of data loss has reached tens of thousands of dollars per day. This is not a matter of insufficient resources. It’s a matter of misplaced priorities and negligence. For a fraction of the cost of their monthly expenses, these individuals and organizations could have secured a robust backup solution that would have prevented the catastrophe.

The reality is simple: backups are inexpensive. Data loss, on the other hand, is costly, stressful, and often irreversible. The barriers to implementing reliable, automated backup solutions today are negligible. Whether you choose cloud storage, external drives, remote servers, the tools are readily available, and there is no excuse for neglecting to protect your data.

Restores have to be tested

It is a common misconception that having a backup in place means data is secure, simply because a tool reports, “Your backups were successful.” However, the true test of a backup’s reliability occurs when it is needed most, during a restore attempt. This is when many realize that despite the “successful” alert, the backup may be incomplete, corrupted, or otherwise unusable.

It is concerning that many individuals in technical roles lack the necessary expertise to properly set up and manage infrastructure within an organization. While foundational knowledge is readily available through online resources, there is a tendency for some to set up systems with minimal effort, a few clicks, and the system is presumed to be functioning. However, the true measure of proficiency in IT infrastructure lies not in the ability to configure a system, but in the ability to resolve issues when things inevitably fail.

Conclusion

If you are reading this, I encourage you to take a moment to assess your backup strategy. If you do not have one, create one today. If you already have a backup system in place, ensure that it is functioning correctly. Whether you are managing a business with critical client data or simply safeguarding personal files on your laptop, the importance of backups cannot be overstated.

Feel free to share your own experiences with data loss, lessons learned, or helpful backup solutions in the comments.

Pathaction – Create .pathaction.yaml rule-set files for executing commands on any file

License

Introduction

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 (such as source code, text files, images, videos, configuration files, and more) 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.

(If you use Emacs, you can use the pathaction.el package to execute the pathaction command-line tool directly from within Emacs. There is also a Vim plugin: vim-pathaction @GitHub)

You can execute a file with the following commands:

pathaction -t main file.py

Or:

pathaction -t edit another-file.jpg

(Note: The -t option specifies the tag, allowing you to apply a tagged rule.)

Here’s an example of what a .pathaction.yaml rule-set file looks like:

---
actions:
  - path_match: "*.py"
    tags: main
    command:
      - "python"
      - "{{ file }}"

  - path_match: "*.jpg"
    tags:
      - edit
      - show
    command: "gimp {{ file|quote }}"

(Note: There are many ways to match paths, including using regex. See below for more details.)

The pathaction tool can be viewed as a type of Makefile but is applicable to any file or directory within the filesystem hierarchy (e.g., it can execute any file such as independent scripts, Ansible playbooks, Python scripts, configuration files, etc.). It executes specific actions (i.e., commands) using tags that allow the user to specify different commands for the same type of file (e.g., a tag for execution, another tag for debugging, another tag for installation, etc.).

By using predefined rules in a user-created rule-set file (.pathaction.yaml), pathaction enables the creation of various tagged actions (e.g., Install, Run, Debug, Compile) customized for different file types (e.g., C/C++ files, Python files, Ruby files, ini files, images, etc.).

Requirements

  • Python
  • pip

Installation

To install the pathaction executable locally in ~/.local/bin/pathaction using pip, run:

sudo pip install pathaction

(Omitting the --user flag will install pathaction system-wide in /usr/local/bin/pathaction.)

The .pathaction.yaml rule-set file

Example 1

The pathaction command-line tool utilizes regular expressions or filename pattern matching found in the rule-set file named .pathaction.yaml to associate commands with file types.

First off, we are going to create and change the current directory to the project directory:

mkdir ~/project
cd ~/project

After that, we are going to permanently allow pathaction to read rule-set files (.pathaction.yaml) from the current directory using the command:

$ pathaction --allow-dir ~/project

This is a security measure to ensure that only the directories that are explicitly allowed could execute arbitrary commands using the pathaction tool.

For instance, consider the following command:

$ pathaction file.py

The command above will load the .pathaction.yaml file not only from the directory where file.py is located but also from its parent directories. This loading behavior is similar to that of a .gitignore file. The rule sets from all these .pathaction.yaml files are combined. In case of conflicting rules or configurations, the priority is given to the rule set that is located in the directory closest to the specified file or directory passed as a parameter to the pathaction command.

Jinja2 templating can be used to dynamically replace parts of the commands defined in the rule-set file with information about the file being executed, such as its filename and path, among other details (more on this below). In the command "python {{ file|quote }}", the placeholder {{ file|quote }} will be dynamically substituted with the path to the source code passed as a parameter to the pathaction command-line tool.

Each rule defined in the rule set file .pathaction.yaml must include at least:

  • The matching rule (e.g. a file name pattern like *.py or a regex .*py$).
  • The command or a shell command (the command and its arguments can be templated with Jinja2).

Example 2

This is what the rule-set file .pathaction.yaml contains:

---
actions:
  # *.py files
  - path_match: "*.py"
    tags: main
    command:
      - "python"
      - "{{ file }}"

  # *.sh files
  - path_match: "*.sh"
    tags:
      - main
    command: "bash {{ file|quote }}"

  - path_match: "*.sh"
    tags: install
    command: "cp {{ file|quote }} ~/.local/bin/"

Consider the following command:

$ pathaction source_code.py

The command above command will:

  1. Load the source_code.py file,
  2. Attempt to locate .pathaction.yaml or .pathaction.yml in the directory where the source code is located or in its parent directories. The search for .pathaction.yaml follows the same approach as git uses to find .gitignore in the current and parent directories.
  3. Execute the command defined in .pathaction.yaml (e.g. PathAction will execute the command python {{ file }} on all *.py files).

Example 3

Here is another example of a rule-set file located at ~/.pathaction.yaml:

---
options:
  shell: /bin/bash
  verbose: false
  debug: false
  confirm_after_timeout: 120

actions:
  # A shell is used to run the following command:
  - path_match: "*.py"
    path_match_exclude: "*/not_this_one.py"    # optional
    tags:
      - main
    shell: true
    command: "python {{ file|quote }}"

  # The command is executed without a shell when shell=false
  - path_regex: '^.*ends_with_string$'
    regex_path_exclude: '^.*not_this_one$'   # optional
    tags: main
    cwd: "{{ file|dirname }}"          # optional
    shell: false                       # optional
    command:
      - "python"
      - "{{ file }}"

Jinja2 Variables and Filters

Jinja2 Variables

Variable Description
{{ file }} Replaced with the full path to the source code.
{{ cwd }} Refers to the current working directory.
{{ env }} Represents the operating system environment variables (dictionary).
{{ pathsep }} Denotes the path separator

Jinja2 Filters

Filter Description
quote Equivalent to the Python method shlex.quote
basename Equivalent to the Python method os.path.basename
dirname Equivalent to the Python method os.path.dirname
realpath Equivalent to the Python method os.path.realpath
abspath Equivalent to the Python method os.path.abspath
joinpath Equivalent to the Python method os.path.join
joincmd Equivalent to the Python method os.subprocess.list2cmdline
splitcmd Equivalent to the Python method shlex.split
expanduser Equivalent to the Python method os.path.expanduser
expandvars Equivalent to the Python method os.path.expandvars
shebang Loads the shebang from a file (e.g. Loads the first line from a Python file #!/usr/bin/env python)
shebang_list Returns the shebang as a list (e.g. [“/usr/bin/env”, “bash”])
shebang_quote Returns the shebang as a quoted string (e.g. “/usr/bin/env ‘/usr/bin/command name'”)
which Locates a command (raises an error if the command is not found)

Frequently Asked Questions

How to Integrate the pathaction tool with your favorite editor (e.g. Vim)

It is recommended to configure your source code editor to execute source code with the pathaction command when pressing a specific key combination, such as CTRL-E.

Integrate with Vim

If the preferred editor is Vim, the following line can be added to the ~/.vimrc:

nnoremap <silent> <C-e> :!pathaction -t main "%"<CR>

License

Copyright (c) 2021-2025 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

Plugins for editors:

  • Emacs package: pathaction.el: Executing the pathaction command-line tool directly from Emacs.
  • Vim plugin: vim-pathaction: Executing the pathaction command-line tool directly from Vim.

bash-stdops – A collection of Bash helper scripts that facilitate operations

License

The bash-stdops project is a collection of helpful Bash scripts, written by James Cherti, that simplify various operations, including file searching, text replacement, and content modification.

The author uses these scripts in conjunction with text editors like Emacs and Vim to automate tasks, including managing Tmux sessions, replacing text across a Git repository, securely copying and pasting from the clipboard by prompting the user before executing commands in Tmux, fix permissions, among other operations.

Table of Contents

Install bash-stdops scripts

System-wide installation

To install bash-stdops scripts system-wide, use the following command:

git clone https://github.com/jamescherti/bash-stdops
cd bash-stdops

sudo ./install.sh

Alternative installation: Install in your home directory

If you prefer to install the scripts locally in your home directory, you can use the ~/.local/bin directory. This method avoids requiring administrative privileges and keeps the installation isolated to your user environment.

Use the following command to install the scripts into the ~/.local/bin directory:

PREFIX=~/.local ./install.sh

Ensure that ~/.local/bin is included in your $PATH by adding the following line to your ~/.bashrc:

export PATH=$PATH:~/.local/bin

Install dependencies

Instructions for installing dependencies are provided below. Note that not all of these dependencies are mandatory for every script.

Install dependencies on Debian/Ubuntu based systems

# Requirements
sudo apt-get install coreutils parallel ripgrep sed

# Git
sudo apt-get install git

# SSH
sudo apt-get install openssh-client

# Clipboard
sudo apt-get install xclip

Install dependencies on RedHat/CentOS/Fedora based systems

# Requirements
sudo dnf install coreutils parallel ripgrep sed git openssh-clients

# Git
sudo dnf install git

# SSH
sudo dnf install openssh-clients

# Clipboard
sudo dnf install xclip

Install dependencies on Gentoo based systems

# Requirements
sudo emerge sys-apps/coreutils sys-process/parallel sys-apps/ripgrep sys-apps/sed

# Git
sudo emerge dev-vcs/git

# SSH
sudo emerge net-misc/openssh

# Clipboard
sudo emerge x11-misc/xclip

Install dependencies on Arch Linux based systems

# Requirements
sudo pacman -S coreutils parallel ripgrep sed

# Git
sudo pacman -S git

# SSH
sudo pacman -S openssh

# Clipboard
sudo pacman -S xclip

Scripts

Script category: tmux

Script: tmux-cbpaste

The tmux-cbpaste: script enables pasting clipboard content into the current tmux window. It ensures safety by requiring user confirmation before pasting, preventing accidental insertion of data.

Script: tmux-run

This script executes a command in a new tmux window, which functions similarly to a tab in other applications.

  • If run within an existing tmux session, it creates a new window in the same session.
  • If run outside of tmux, it creates a new window in the first available tmux session.
  • If the environment variable TMUX_RUN_SESSION_NAME is set, the script will create the new window in the specified tmux session.

Usage:

  tmux-run <command> [args...]

Example:

tmux-run bash

Example 2:

tmux-run bash -c htop

Script: tmux-session

The tmux-session script attempts to attach to an existing tmux session. If the session does not exist, it creates a new session with that name.

If no session name is provided, it defaults to creating or attaching to a session named “0”.

Script category: files, paths, and strings

Script: walk

The walk bash script recursively search the specified directory and print the list of file or directory paths to standard output.

Script: walk-run

Recursively execute a command on all files listed by the rg --files command. For example, to recursively cat all text files in /etc, use the following command:

walk-run /etc cat {}

({} is replaced with the path to each file.)

Here is an example of how you can combine walk-run and sed to replace “Text1” with “Text2” in a Git repository:

walk-run /path/to/git-repository/ sed -i -e "s/Text1/Text2/g" {}

Script: sre

The sre script replaces occurrences of a specified string or regular expression pattern with support for exact string matching, regular expressions, and case-insensitive matching. Unlike sed, which uses a single argument for replacements, this script allows specifying the text-to-find and text-to-replace as two distinct arguments.

To replace text in the standard input and output the result to the standard output:

echo "text-before" | sre "text-before" "text-after"

To replace text directly in a file (overwriting the file):

sre "text-before" "text-after" file

Here are the sre options:

Usage: sre [-ierdh] <string-before> <string-after>

  -i    Ignore case when comparing files
  -e    Use regular expressions instead of exact strings.
  -r    Use extended regular expressions.
  -d    Show the sed command
  -h    Show this help message and exit

Here is an example of how you can combine walk-run and sre to replace Text1 with Text2 in a Git repository:

walk-run /path/to/git-repository/ sre Text1 Text2 {}

Script: git-sre

Execute sre at the root directory of a Git repository.

(The sre script replaces occurrences of a specified string or regular expression pattern with support for exact string matching, regular expressions, and case-insensitive matching.)

Example usage:

git sre TextBefore TextAfter /path/to/git/repo

(sre also supports regular expressions.)

Scripts: path-tr, path-uppercase, path-lowercase

  • path-tr: This script processes a given file path, extracts the directory and filename, converts the filename using the specified tr options (e.g., to lowercase), and prints the modified full path. Example usage: path-tr /Path/TO/FILE '[:upper:]' '[:lower:]' This will convert the filename to lowercase, producing: /Path/TO/file.

  • path-uppercase: This script processes a given file path, extracts the directory and filename, converts the filename to uppercase. Example usage: path-uppercase /Path/TO/FILE This will convert the filename to uppercase, producing: /Path/to/FILE.

  • path-lowercase: This script processes a given file path, extracts the directory and filename, converts the filename to lowercase. Example usage: path-lowercase /Path/TO/FILE. This will convert the filename to lowercase, producing: /Path/TO/file.

Script: autoperm

This script sets permissions for files or directories:

  • If it’s a directory: 755
  • If it’s a file with a shebang (e.g., “#!/bin/bash”): 755
  • If it’s a file: 644

Usage:

autoperm /path/to/file-or-directory

Script: path-is

Print the Path to stdout and exit with the code 0 if it is a binary or text file.

Example usage:

path-is /Path/TO/FILE binary
path-is /Path/TO/FILE text

Script category: git

git-dcommit

Script to automate common Git commit tasks:

  • Automatically add untracked files (prompted),
  • Display git diff to the user before committing,
  • Commit changes to the Git repository,
  • Optionally reuse the previous Git commit message if available.

Usage:

./script_name.sh

Run this script from within a Git repository to automate adding, reviewing, and committing changes.

git-squash

A script to squash new Git commits between the current branch and a specified branch.

Usage:
  ./script_name.sh <other-git-branch>

Features:

  • Compares the current branch with the specified branch.
  • Displays a summary of new commits to be squashed.
  • Prompts for confirmation if there are more than 4 commits.
  • Automatically squashes all new commits into one, retaining the message of the first commit.

git-finder

This script recursively locates all Git repositories starting from a specified directory or the current directory if none is provided.

It first checks for fd to perform faster searches; if unavailable, it defaults to find.

The script outputs the paths of all discovered Git repositories to standard output.

git-finder-exec

The git-finder-exec recursively finds all Git repositories starting from the current directory using the git-finder script.

It then executes the command provided as an argument in the directory of each Git repository.

Example usage:

git-finder-exec pwd

git-ourstheir

This script extracts the ‘ours’ and ‘theirs’ versions of a file involved in a Git merge conflict. It is intended to facilitate manual conflict resolution by saving both conflicting versions under distinct filenames (“ours-” and “theirs-“). This allows users to inspect and compare the conflicting changes independently of Git’s built-in merge tools.

Usage:

git-ourstheir <file-in-conflict>

git-sync-upstream

This script synchronizes the current Git branch with its upstream counterpart and force-pushes the result to the ‘origin’ remote. It is intended for workflows where a local branch is kept in sync with an upstream source of truth, and the mirror on ‘origin’ must match upstream exactly.

The script performs the following actions:

  1. Verifies that both ‘origin’ and ‘upstream’ remotes are defined.
  2. Performs a rebase of the current branch onto its upstream equivalent.
  3. Displays the diff between the rebased branch and the remote ‘origin’.
  4. Prompts for confirmation unless run in batch mode.
  5. Merges upstream changes with –ff-only and force-pushes to ‘origin’.

Intended for use in CI workflows or manual synchronization where upstream is authoritative.

Usage:
  git-sync-upstream [-h] [-b]
  -h    Show help message and exit
  -b    Run in batch mode (no interactive prompts)

Script category: ssh

Script: esa

Esa (Easy SSH Agent) simplifies starting ssh-agent, adding keys with ssh-add, and executing commands using the agent.

Usage:

Usage: esa <start|stop|ssh-add|exec>

start: Starts the ssh agent
start: Stop the ssh agent
add: Adds private keys requiring a password with ssh-add
exec: Executes a program using this agent
env: Displays the ssh-agent environment variables

Script: sshwait

This script repeatedly attempts to check the availability of the SSH server on the host provided as the first argument. It exits with a 0 status upon successfully establishing a connection at least once. Note that it only verifies if the SSH server is reachable and does not provide a shell prompt or execute any commands on the remote host.

Usage:

./script_name.sh <host>

X11/Wayland scripts

xocrshot

The xocrshot script captures a screenshot using ‘scrot’, performs optical character recognition (OCR) using ‘tesseract’ command, and:

  • Displays the extracted text in the terminal
  • Copies it to the clipboard.

Features:

  • Captures a screenshot using the ‘scrot’ command,
  • Performs OCR on the screenshot using Tesseract,
  • Displays the extracted text in the terminal,
  • Copies the extracted text to the clipboard using ‘xclip’,
  • Provides error handling and cleanup of temporary files,
  • Supports notifications using ‘notify-send’ (if available).

Usage:

xocrshot

Script category: Misc

Script: haide

The haide script utilizes AIDE (Advanced Intrusion Detection Environment) to monitor the file integrity of the user’s home directory, ensuring no files are modified, added, or deleted without the user’s knowledge. Key functions handle database setup, integrity checks, and user-approved updates. The script filters non-critical changes, ensuring meaningful alerts while maintaining a secure and reliable monitoring process.

Scripts: cbcopy, cbpaste

  • cbcopy: This script copies the content of stdin to the clipboard.
  • cbpaste: This script reads the contents of the system clipboard and writes it to stdout.
  • cbwatch: Monitor the clipboard and display its content when it changes.

Script: outonerror

The outonerror script redirects the command’s output to stderr only if the command fails (non-zero exit code). No output is shown when the command succeeds.

Here is an example of how to use this script: How to make cron notify the user about a failed command by redirecting its output to stderr only when it fails (non-zero exit code).

Script: over

This program simply displays a notification. It can be used in the terminal while another command is running. Once the command finishes executing, a notification is displayed, informing the user that the process has completed.

Script: largs

This script reads from standard input and executes a command for each line, replacing {} with the content read from stdin. It expects {} to be passed as one of the arguments and will fail if {} is not provided.

This script is an alternative to xargs.

{ echo "file1"; echo "file2"; } | largs ls {}

License

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

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
    :ensure t
    :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”.)

License

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

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:
    (use-package enhanced-evil-paredit
    :ensure t
    :config
    (add-hook 'paredit-mode-hook #'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 is enabled. Otherwise, enhanced-evil-paredit-mode uses Evil functions.
  • 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-2025 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.

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
    :ensure t
    :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"))

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

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

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
  :ensure t
  :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-2025 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.

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-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 this repository as a local hook in your .pre-commit-config.yaml:

---

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

      # Optional: Byte-compile .el files to identify compilation errors early
      # - id: elisp-check-byte-compile

      # 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 and elisp-byte-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 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:

((nil . ((pre-commit-elisp-load-path . ("." "lib/" "utils")))))

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

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