8.2 KiB
Programming Ansible
Configuring Ansible and YAML
My day job now involves a lot of Ansible, and I’ve been struggling to get the right balance here.
Much of the conflict stems from whether to use Tree Sitter for the YAML mode or not.
YAML
Doing a lot of YAML work, but the yaml-mode
project needs a new maintainer, so I might as well switch over to the T version.
, so I’ve switch to yaml-pro that is now based on Tree Sitter. Let’s make sure the Tree-Sitter version works:
(when (treesit-available-p)
(use-package yaml-ts-mode
:straight (:type built-in)
:mode ((rx ".yamllint")
(rx ".y" (optional "a") "ml" string-end))
:hook (yaml-ts-mode . (lambda () (mixed-pitch-mode -1)))
:mode-hydra
((:foreign-keys run)
("Simple"
(("l" ha-yaml-next-section "Next section")
("h" ha-yaml-prev-section "Previous"))))))
major-mode-hydras/yaml-ts-mode/body
Allow this mode in Org blocks:
(add-to-list 'org-babel-load-languages '(yaml-ts . t))
And we hook
(use-package yaml-pro
:straight (:host github :repo "zkry/yaml-pro")
:after yaml-ts-mode
:hook ((yaml-ts-mode . yaml-pro-ts-mode)
(yaml-mode . yaml-pro-mode)))
Since I can never remember too many keybindings for particular nodes, we create a Hydra just for it.
(use-package major-mode-hydra
:after yaml-pro
:config
(major-mode-hydra-define yaml-ts-mode (:foreign-keys run)
("Navigation"
(("u" yaml-pro-ts-up-level "Up level" :color pink) ; C-c C-u
("J" yaml-pro-ts-next-subtree "Next subtree" :color pink) ; C-c C-n
("K" yaml-pro-ts-prev-subtree "Previous" :color pink)) ; C-c C-p
"Editing"
(("m" yaml-pro-ts-mark-subtree "Mark subtree") ; C-c C-@
("x" yaml-pro-ts-kill-subtree "Kill subtree") ; C-c C-x C-w
("p" yaml-pro-ts-paste-subtree "Paste subtree")) ; C-c C-x C-y
"Insert"
(("e" yaml-pro-edit-ts-scalar "Edit item") ; C-c '
("o" yaml-pro-ts-meta-return "New list item"))
"Refactor"
(("r" yaml-pro-ts-move-subtree-up "Raise subtree")
("t" yaml-pro-ts-move-subtree-down "Lower subtree")
("," combobulate-hydra/body ">>>"))
"Documentation"
(("d" hydra-devdocs/body "Devdocs")))))
Note that these packages need the following to run properly:
pip install yamllint
Jinja2
A lot of projects (like Ansible and Zuul) uses Jinja2 with YAML, so we first install the jinja2-mode:
(use-package jinja2-mode
:mode (rx ".j2" string-end))
Jinja is a template system that integrates inside formats like JSON, HTML or YAML. The polymode project glues modes like jinja2-mode to yaml-mode.
I adapted this code from the poly-ansible project:
(use-package polymode
:config
(define-hostmode poly-yaml-hostmode :mode 'yaml-ts-mode)
(defcustom pm-inner/jinja2
(pm-inner-chunkmode :mode #'jinja2-mode
:head-matcher (rx "{"
(or "%" "{" "#")
(optional (or "+" "-")))
:tail-matcher (rx (optional (or "+" "-"))
(or "%" "}" "#")
"}")
:head-mode 'body
:tail-mode 'body
:head-adjust-face t)
"Jinja2 chunk."
:group 'innermodes
:type 'object)
(define-polymode poly-yaml-jinja2-mode
:hostmode 'poly-yaml-hostmode
:innermodes '(pm-inner/jinja2))
(major-mode-hydra-define+ yaml-ts-mode nil
("Extensions" (("j" poly-yaml-jinja2-mode "Jinja2")))))
We need to make sure the mixed-pitch-mode
doesn’t screw things up.
(add-hook 'poly-yaml-jinja2-mode-hook (lambda () (mixed-pitch-mode -1)))
;; (add-hook 'yaml-ts-mode-hook 'poly-yaml-jinja2-mode)
---
# Let's see how this works
- name: Busta move
debug:
msg: >-
This {{ adjective }} {{ noun }} {{ verb }} the ball."
{% for x in does %}
What is this about?
{% endfor %}
vars:
adjective: small
noun: squirrel
verb: ate
Ansible
Do I consider all YAML files an Ansible file needing ansible-mode? Maybe we just have a toggle for when we want the Ansible feature.
(use-package ansible
:straight (:host github :repo "k1LoW/emacs-ansible")
;; :mode ((rx (or "playbooks" "roles") (one-or-more any) ".y" (optional "a") "ml") . ansible-mode)
:config
(setq ansible-vault-password-file "~/.ansible-vault-passfile")
(major-mode-hydra-define+ yaml-ts-mode nil
("Extensions" (("a" ansible "Ansible"))))
(ha-leader "t y" 'ansible))
The ansible-vault-password-file variable needs to change per project, so let’s use the .dir-locals.el
file, for instance:
((nil . ((ansible-vault-password-file . "playbooks/.vault-password"))))
The YAML files get access Ansible’s documentation using the ansible-doc project (that accesses the ansible-doc interface):
(use-package ansible-doc
:hook (yaml-ts-mode . ansible-doc-mode)
:config
;; (add-to-list 'exec-path (expand-file-name "~/.local/share/mise/installs/python/3.10/bin/ansible-doc"))
(major-mode-hydra-define+ yaml-ts-mode nil
("Documentation"
(("D" ansible-doc "Ansible")))))
Can we integrate Ansible with LSP using ansible-language-server project (see this documentation)?
Using npm
to install the program:
npm install -g @ansible/ansible-language-server
But … will I get some use out of this? I’ll come back to it later.