Skip to content

Devicetree Source Formatting

Nick Coutsos edited this page Jan 15, 2024 · 1 revision

Keymap editor has to do some amount of formatting due to the fact that keymap changes are applied directly to your existing keymap code. For consistency, it will do a proper formatting pass over the entire document, not just the edited portions.

Some formatting rules are pretty agreeable like "don't try to format the contents of integer cell arrays when they span multiple lines" (because this is how layer bindings are expressed and special formatting is applied here already as a core feature of this app), but I expect people to have lots of opinions about other ones.

Configuration

There are a few aspects of the formatting that can be configured. Right now, I only support "modeline" comment configuration, certain comment lines in your keymap can be parsed during formatting to alter the style.

e.g.

// dt-formatter: indent="  "

Some rules

  • generally these directive must be in the top level, not in any devicetree node
  • the directive must be a single-line comment beginning with dt-formatter
  • it must include a key name, followed by =, followed by a JSON-parseable value

indent (default " ")

Node contents are indented with four space tabs by default. You can specify any other string value here such as " " (two-space tabs) or "\t" (tab character). Its your own keymap so don't use any non-whitespace character that would otherwise break your keymap. This isn't run through any validation.

multilineIntegerCellsIndent (default "keep")

This governs how to handle indentation of values like layer bindings. This won't affect alignment of the binding cells relative to one another, but whether the common indentation should match the node's depth or if the indentation should be removed (this can help to avoid text wrapping for long-ish lines).

Options here are: - "reindent": apply the level of indentation appropriate for the node's depth - "dedent": remove any indentation from these lines - "keep" (default): don't make any changes. Because this mainly applies to layer bindings which are already indented by the layout code this doesn't have much effect.

multilineListCommaStyle (default: "trailing")

When writing out bindings for macros it's common to logically group control bindings (e.g. &macro_tap) separately from others, and then for readability I split each "group" of integer cells onto its own line.

The default style, trailing will wrap after [property] = and then precede each newline with a comma:

```dts
foo = 
  <blah blah blah>,
  <blah blah blah>,
  <blah blah blah>;
```

The leading style matches ZMK documentation examples, where = is on the line below the property name and precedes the first value, then each following line begins with a comma, and the whole thing is finished with an additional line for the semi-colon:

```
foo
  = <blah blah blah>
  , <blah blah blah>
  ;
```

I'm not a fan of the latter but given that its used in the ZMK documentation it's reasonable to expect it.

style

This is a special case and might need further consideration at some point. It is intended as a way to specify that groups of nodes should be rendered as tabular data, e.g.:

  combos {
    compatible = "zmk,combos";

    // dt-formatter: style="table"

    tab       { bindings = <&none>;        key-positions = <2 3>; };
    ctrl      { bindings = <&kp LCTRL>;    key-positions = <26 27>; };
    cmd       { bindings = <&kp LCMD>;     key-positions = <37 38>; };
    caps_word { bindings = <&caps_word>;   key-positions = <17 18>; };
  };

Node names, property names, and values are aligned in columns so that it's easier to scan through a longer list of related nodes. This works best in cases where the list may be long and each individual node will tend to use the same limited set of properties.

Note:

This style is meant to be used inside a node and not at the root, it doesn't "cascade" and isn't meant to be used where nodes will have multiple levels of descendants. Pretty much just use it for combos and conditional layers. Anything else is undefined.