This package provides convenience functions for interacting with the chezmoi dotfile management system via Emacs. These are mostly equivalents to functions like find-file
and save-buffer
.
The recording above demonstrates editing a chezmoi template with source file on left, command log on top right, and associated target file on bottom right.
Clone this repo or use a package manager.
(use-package chezmoi)
Add keybindings to some functions. Or call using M-x <cmd>
.
(global-set-key (kbd "C-c C f") #'chezmoi-find)
(global-set-key (kbd "C-c C s") #'chezmoi-write)
You can manually call M-x chezmoi-mode
in a source file buffer to turn on/of syncronization and template rendering (see Templates). When using chezmoi-find
or chezmoi-ediff
, chezmoi-mode
will be turned on for you in the source file’s buffer.
One of the main goals of this package is to allow users to access their files managed by chezmoi and sync changes in the source state with the target state files that are used. Opening source state files is done using chezmoi-find
. This opens a buffer for the source state and adds a hook to sync it with the corresponding target state file when changes are saved. However, to prevent overwriting changes that were made to the target state file outside of the source state (such as by auto-generated content), this hook is only added when the source and target states are in sync at the time of opening.
You can overwrite the target state file manually by calling chezmoi-write
from within the source state buffer. Alternatively, you can overwrite the source state file with the content from the current target state file using chezmoi-write
. This can be performed for several files in a row using chezmoi-write-files
.
Quickly jump to the corresponding target file or source file using chezmoi-open-other
.
Some functions provided are direct equivalents to common emacs functions.
Function | chezmoi equivalent | chezmoi.el |
---|---|---|
find-file | chezmoi edit | chezmoi\vertfind |
save-buffer | chezmoi apply | chezmoi\vertwrite |
diff | chezmoi diff | chezmoi\vertdiff |
ediff | chezmoi merge | chezmoi\vertediff |
magit-status | chezmoi git status | chezmoi\vertmagit-status |
Chezmoi.el provides a minor mode for displaying the values of chezmoi template strings as overlays in source file buffers. You can toggle their display with M-x chezmoi-template-buffer-display
or with a configuration variable:
(setq-default chezmoi-template-display-p t) ;; Display template values in all source buffers.
(setq chezmoi-template-display-p t) ;; Display template values in current buffer.
(setq-default chezmoi-template-display-p nil) ;; Don't display template values by default.
Emacs has a lovely package called ediff
for comparing differences between files which is perfect for when the source and target states get out of sync. Quickly resolve inconsistencies between source and target states using chezmoi-ediff
. Or view the raw diff using chezmoi-diff
if you prefer. Pipe this into your own diff workflow using (chezmoi-diff 1)
to give raw diff input to some other diff management tool.
Company integration is provided through chezmoi-company-backend
. Simply add it to to company-backends
. This will show completions for when editing template variables.
(require 'chezmoi-company)
(add-hook 'chezmoi-mode-hook #'(lambda () (if chezmoi-mode
(add-to-list 'company-backends 'chezmoi-company-backend)
(delete 'chezmoi-company-backend 'company-backends))))
Cape integration is provided through chezmoi-capf
. Simply add it to to completion-at-point-functions
. This will show completions for when editing template variables.
(require 'chezmoi-cape)
(add-to-list 'completion-at-point-functions #'chezmoi-capf)
In a Dired buffer, add files to chezmoi by either moving to the file or marking some and calling chezmoi-dired-add-marked-files
.
Use chezmoi-magit-status
to jump to the magit-status
for your chezmoi.
Integrate with evil mode by toggling template display when entering insert mode.
(defun chezmoi--evil-insert-state-enter ()
"Run after evil-insert-state-entry."
(chezmoi-template-buffer-display nil (point))
(remove-hook 'after-change-functions #'chezmoi-template--after-change 1))
(defun chezmoi--evil-insert-state-exit ()
"Run after evil-insert-state-exit."
(chezmoi-template-buffer-display nil)
(chezmoi-template-buffer-display t)
(add-hook 'after-change-functions #'chezmoi-template--after-change nil 1))
(defun chezmoi-evil ()
(if chezmoi-mode
(progn
(add-hook 'evil-insert-state-entry-hook #'chezmoi--evil-insert-state-enter nil 1)
(add-hook 'evil-insert-state-exit-hook #'chezmoi--evil-insert-state-exit nil 1))
(progn
(remove-hook 'evil-insert-state-entry-hook #'chezmoi--evil-insert-state-enter 1)
(remove-hook 'evil-insert-state-exit-hook #'chezmoi--evil-insert-state-exit 1))))
(add-hook 'chezmoi-mode-hook #'chezmoi-evil)
Ligatures don’t seem to play nice with overlaid text. When using templates, it is recommended to turn off ligature-mode
.
;; Turn off ligatures because they show up poorly.
(add-hook 'chezmoi-mode-hook #'(lambda () (when (require 'ligature)
(ligature-mode (if chezmoi-mode 0 1)))))
I find this hook useful for my emacs config files generated through org-tangle.
(add-hook 'org-babel-post-tangle-hook #'chezmoi-write))
Provided here is a sample layer for those who use Spacemacs. Add it by creating a Spacemacs layer called “chezmoi” and create a file in it called “packages.el” with the following code:
(defconst chezmoi-packages
'(
chezmoi)
"The list of Lisp packages required by the chezmoi layer.")
(defun chezmoi/init-chezmoi ()
(use-package chezmoi
:init
(spacemacs/declare-prefix "f d" "chezmoi")
(spacemacs/set-leader-keys
"f d s" #'chezmoi-write
"f d g" #'chezmoi-magit-status
"f d d" #'chezmoi-diff
"f d e" #'chezmoi-ediff
"f d f" #'chezmoi-find
"f d i" #'chezmoi-write-files
"f d o" #'chezmoi-open-other
"f d t" #'chezmoi-template-buffer-display
"f d c" #'chezmoi-mode)
(when (equalp dotspacemacs-editing-style 'vim)
(defun chezmoi--evil-insert-state-enter ()
"Run after evil-insert-state-entry."
(chezmoi-template-buffer-display nil (point))
(remove-hook 'after-change-functions #'chezmoi-template--after-change 1))
(defun chezmoi--evil-insert-state-exit ()
"Run after evil-insert-state-exit."
(chezmoi-template-buffer-display nil)
(chezmoi-template-buffer-display t)
(add-hook 'after-change-functions #'chezmoi-template--after-change nil 1))
(defun chezmoi-evil ()
(if chezmoi-mode
(progn
(add-hook 'evil-insert-state-entry-hook #'chezmoi--evil-insert-state-enter nil 1)
(add-hook 'evil-insert-state-exit-hook #'chezmoi--evil-insert-state-exit nil 1))
(progn
(remove-hook 'evil-insert-state-entry-hook #'chezmoi--evil-insert-state-enter 1)
(remove-hook 'evil-insert-state-exit-hook #'chezmoi--evil-insert-state-exit 1))))
(add-hook 'chezmoi-mode-hook #'chezmoi-evil))
(setq chezmoi-template-display-p t) ;; Display template values in all source buffers.
(require 'chezmoi-company)
(add-hook 'chezmoi-mode-hook #'(lambda () (if chezmoi-mode
(add-to-list 'company-backends 'chezmoi-company-backend)
(setq company-backends (delete 'chezmoi-company-backend company-backends)))))
;; Turn off ligatures cuz they look bad.
(add-hook 'chezmoi-mode-hook #'(lambda () (ligature-mode (if chezmoi-mode 0 1))))
;; I find this hook useful for my emacs config files generated through org-tangle.
(defun chezmoi-org-babel-tangle ()
(when-let ((fle (chezmoi-target-file (buffer-file-name))))
(chezmoi-write file)))
(add-hook 'org-babel-post-tangle-hook #'chezmoi-org-babel-tangle)))