Indentguides: Or how I learned to stop worrying and love YAML
The problem
Yaml, as well as Python, Haskell and probably more formats and languages using the off-side rule (from P.J. Landin's The next 700 programming languages (1966)) tend to get some complaints:
- It's unusual.
- I can't keep track of scope, help!
Given configuration like this:
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
whatever.io/one: annotation
whatever.io/two: annotations
name: test
namespace: test
spec:
template:
spec:
containers:
- name: frobnicate
env:
- name: MY_ENV_VAR
value: cats
- name: MY_OTHER_ENV_VAR
value: dogs
resources:
limits:
# ought to be enough for anyone
memory: &mem 640ki
requests:
cpu: 1m
memory: *mem
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
replicas: 9001
...
it's not uncommon to place something and the wrong indent level and have kubernetes or some CI system be mad at you, even if your editor has colorized the tokens.
This post is meant to help alleviate the latter issue. For the first issue, you'll just have to get used to it over time; we can't help you.[1]
Do also note that the aim here is to alleviate, not eliminate. The structure of Kubernetes yaml and many other things are inherently complex because there are a lot of variables, and remembering which go at which scope isn't trivial. So even if we can avoid accidental scope errors I wouldn't expect them to go away. A solution that could fix that is something like a kubernetes/crd/schema language server, that would tell you you're doing it wrong, just like when you do it wrong using the kubernetes openapi in your favorite programming language.
There's a yaml language server which I should probably test.
edit: There's a followup about the yaml language server; it is indeed the tool you want to be using to get meaningful errors with yaml config.
Avoiding the problem
You could just try to avoid these languages. Yaml especially seems like a problem child, with the Python implementation requiring you to specify a loader (for security reasons), and the Rust implementation is currently disowned; the common implementation even uses a deprecated draft feature. The phrase "worse is better" springs to mind (and I count myself as on friendly terms with yaml).
Maybe you'd prefer to use some nice toml instead? But if it were that easy, you wouldn't be here.
A workaround
Some of these languages, like Haskell and Yaml, are actually, semi-secretly, languages with curly braces and terminators. If you format your code[2] correctly, you can omit the braces and terminators. For Yaml's part, we can show this with python yq[3]:
<foo.yaml yq -c
outputs compact json<foo.yaml yq -c | yq -y
outputs something practically identical to the original.
and go yq:
<foo.yaml yq -o json -I0
outputs compact json<foo.yaml yq -o json -I0 | yq -P
outputs something practically identical to the original.
So if you're struggling with Yaml, one workaround is to treat it as if it were json with comments, anchors, merge keys and whatnot. It's likely not a very good workaround since any tool that automatically edits the file can be expected to emit plain golfed yaml again. If you're struggling with Python, no such workaround exists. And if you try to write Haskell that way: … 😑
The working solution: Indentguides
Developers like to simulate having synesthesia through editor features. We've been making our code look like skittles for decades, and the same editors can help us with identifying indent levels, and even better, scopes.
The solutions here are going to vary by editor. In no particular order:
Vim
One solution I've used for several years is indentguides for vim. It colors indent levels alternating in what should be mild background colors:
It works fine. There's no real reason to replace it. And yet …
Neovim
My suggestion here is a collection of three plugins:
- lukas-reineke/indent-blankline.nvim for the actual indentlines, plus the "multiple indent colors" config.
- HiPhish/rainbow-delimiters.nvim plus the integration as mentioned in indent-blankline.nvim.
- nvim-treesitter/nvim-treesitter for scope understanding for the indentlines.
If you're like me and have an ancient colorscheme for nvim, you'll also need a modern one to get the colors to work as expected. I went with rebelot/kanagawa.nvim, but pick what you fancy.
(Do also note that the indent style for arrays helps visualization of scope.[4])
The tree-sitter integration means that the current scope that the cursor is on is colored differently (and that you get syntax understanding in a markdown file). That along with lsp support is pretty neat in general, even if you don't like skittles.
Jetbrains
Sublime
Visual Studio
Helix
It looks like it uses tree-sitter for indent analysis, but I have no clue about how to turn on colored indentguides. It seems to be an open issue.
Your favorite editor, which I forgot
Send me a PR. Or just edit this file yourself and don't even tell me about it??? (I guess this is only viable from within the amedia org, if any outsiders are actually reading this)
Emacs
- ???????
- I tried spacemacs once
- Wow, look at those cursor effects for neovide, aren't those funny and adorable
- I don't think you can get indentguides in the standard editor
No, seriously
The DarthFennec/highlight-indent-guides seems to be on par with the neovim setup above, leaving the rivalry healthy and alive.
The way forward
It'd be nice to see indentguide support more places, really. Like, idunno, colorizers like the one used in this blog system, on github, in bat and whatever other colorizing tool you fancy.
You'll know you're used to it when you start forgetting semicolons and getting annoyed with languages that require them. ↩︎
Given that Yaml isn't a programming language, just an encoding format for data, code seems like the most correct term here. ↩︎
Likely you'll prefer mikefarah's go version; I appear to have the python version installed entirely by accident (as a result of installing
yq
rather thango-yq
). ↩︎The option to use less indenting for arrays in yaml is in my opinion a mistake; the less indented variants always appear less legible. My worst case of this was when looking at some documentation where the dash wasn't very visible (grey on white or something) and I wound up interpreting an array as a dict. ↩︎