Editor integration#
rdlfmt has no language server and no editor plugin, and does not need
either. Run with - as its path it reads a buffer on stdin and writes the
formatted text to stdout:
rdlfmt -
That is exactly the shape every editor’s “filter the buffer through an external command” hook expects, so format-on-save is a handful of lines of config wherever you work. The recipes below all use it; a failed format exits non-zero and prints diagnostics on stderr, leaving stdout empty, so a file with a syntax error is left as you typed it rather than being emptied.
Most editors do not know what a .rdl file is out of the box, so where a
filetype has to be declared before anything can hook onto it, the recipe does
that first.
Warning
The recipes below are offered in good faith, not tested in CI. What is
tested is the behaviour every one of them rests on: that rdlfmt -
round-trips a buffer, and that a file it cannot parse leaves stdout empty
and exits non-zero. The glue around that is your editor’s, and editors
move. If one of these has rotted, please
open an issue.
Neovim#
With conform.nvim:
vim.filetype.add({ extension = { rdl = "systemrdl" } })
require("conform").setup({
formatters = {
rdlfmt = {
command = "rdlfmt",
args = { "-" },
stdin = true,
},
},
formatters_by_ft = {
systemrdl = { "rdlfmt" },
},
format_on_save = {
timeout_ms = 1000,
lsp_format = "fallback",
},
})
Vim#
No plugin needed — filter the buffer through rdlfmt before the write, and
undo it if the format failed:
function! s:RdlFmt() abort
let l:view = winsaveview()
silent %!rdlfmt -
if v:shell_error
silent undo
echohl ErrorMsg | echom 'rdlfmt: left unformatted' | echohl None
endif
call winrestview(l:view)
endfunction
augroup rdlfmt
autocmd!
autocmd BufWritePre *.rdl call s:RdlFmt()
augroup END
winsaveview()/winrestview() keep the cursor and the scroll position
where they were, which a bare %! would not.
VS Code#
VS Code will not run an arbitrary command as a formatter, so this needs the Run on Save extension. It runs after the write, so this one uses in-place formatting rather than stdin, and VS Code reloads the file:
{
"emeraldwalk.runonsave": {
"commands": [
{
"match": "\\.rdl$",
"cmd": "rdlfmt ${file}"
}
]
}
}
Put that in .vscode/settings.json to scope it to one project, or in your
user settings for all of them.
Zed#
Install the SystemRDL extension first
— it claims .rdl and registers the language under the name SystemRDL,
which is what the settings below key off. In settings.json:
{
"languages": {
"SystemRDL": {
"format_on_save": "on",
"formatter": {
"external": {
"command": "rdlfmt",
"arguments": ["-"]
}
}
}
}
}
The extension brings a tree-sitter grammar with it, so this is the one editor here that gets highlighting and formatting from the same five minutes of setup.
Helix#
Helix has no SystemRDL language built in, so declare one. In
~/.config/helix/languages.toml:
[[language]]
name = "systemrdl"
scope = "source.systemrdl"
file-types = ["rdl"]
indent = { tab-width = 4, unit = " " }
formatter = { command = "rdlfmt", args = ["-"] }
auto-format = true
There is no tree-sitter grammar for SystemRDL, so this buys you formatting and
indentation, not highlighting. hx --health systemrdl will say as much.
Emacs#
With reformatter.el:
(define-derived-mode systemrdl-mode prog-mode "SystemRDL"
"Major mode for SystemRDL sources."
(setq-local comment-start "// ")
(setq-local indent-tabs-mode nil)
(setq-local tab-width 4))
(add-to-list 'auto-mode-alist '("\\.rdl\\'" . systemrdl-mode))
(reformatter-define rdlfmt
:program "rdlfmt"
:args '("-")
:lighter " RDLFmt")
(add-hook 'systemrdl-mode-hook #'rdlfmt-on-save-mode)
reformatter-define also gives you M-x rdlfmt-buffer and
M-x rdlfmt-region for the times you want it on demand.
Anything else#
If your editor can pipe the buffer through a shell command on save, the command
is rdlfmt - and there is nothing else to know. If it can only run a command
on a path, use rdlfmt <file> and let the editor notice the file changed
underneath it.
Formatting on save is not a substitute for a rdlfmt --check . job in CI —
it is what keeps that job from ever failing. See
Continuous integration.