Indentguides: Or how I learned to stop worrying and love YAML

Emil Snorre Alnæs

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:

  1. It's unusual.
  2. 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:

Vim indentguides
Indentguides for vim, from the github page.

It works fine. There's no real reason to replace it. And yet …

Neovim

My suggestion here is a collection of three plugins:

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.

Neovim indentguides
Indentguides for neovim, as they appear for me.

(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

Jetbrains indentguides
Indentguides for Jetbrains, from the marketplace page.

Sublime

Sublime indentguides
Indentguides for Sublime, from the github page.

Visual Studio

Visual Studio indentguides
Indentguides for Visual Studio, from the marketplace page.

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

No, seriously

The DarthFennec/highlight-indent-guides seems to be on par with the neovim setup above, leaving the rivalry healthy and alive.

Emacs indentguides
Indentguides for Emacs, from the github page.

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.


  1. You'll know you're used to it when you start forgetting semicolons and getting annoyed with languages that require them. ↩︎

  2. Given that Yaml isn't a programming language, just an encoding format for data, code seems like the most correct term here. ↩︎

  3. 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 than go-yq). ↩︎

  4. 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. ↩︎