tuh8888 / chezmoi.el

An emacs package for interacting with chezmoi.
GNU Affero General Public License v3.0
85 stars 10 forks source link

+title: chezmoi.el

This package provides convenience functions for interacting with the [[https://chezmoi.io/][chezmoi]] dotfile management system via Emacs. These are mostly equivalents to functions like ~find-file~ and ~save-buffer~.

[[https://melpa.org/#/chezmoi][file:https://melpa.org/packages/chezmoi-badge.svg]]

[[file:resources/chezmoi-template-recording.gif]]

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.

** Ediff: Comparing source and target states

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

Company integration is provided through ~chezmoi-company-backend~. Simply add it to to ~company-backends~. This will show completions for when editing template variables.

+begin_src emacs-lisp :noweb yes

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

+end_src

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

+begin_src emacs-lisp :noweb yes

(require 'chezmoi-cape) (add-to-list 'completion-at-point-functions #'chezmoi-capf)

+end_src

** Dired

In a Dired buffer, add files to chezmoi by either moving to the file or marking some and calling ~chezmoi-dired-add-marked-files~.

** Magit

Use ~chezmoi-magit-status~ to jump to the ~magit-status~ for your chezmoi.

** Org

** Evil

Integrate with evil mode by toggling template display when entering insert mode.

+begin_src emacs-lisp :noweb yes

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

+end_src

** Ligatures

Ligatures don't seem to play nice with overlaid text. When using templates, it is recommended to turn off ~ligature-mode~.

+begin_src emacs-lisp :noweb yes

;; Turn off ligatures because they show up poorly. (add-hook 'chezmoi-mode-hook #'(lambda () (when (require 'ligature) (ligature-mode (if chezmoi-mode 0 1)))))

+end_src

** Org babel tangle

I find this hook useful for my emacs config files generated through org-tangle.

+begin_src emacs-lisp :noweb yes

(add-hook 'org-babel-post-tangle-hook #'chezmoi-write))

+end_src

** Spacemacs layer

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:

+begin_src emacs-lisp :noweb yes :results silent

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

+end_src