What is the "right" way to do `:format` on write?

currently I have something along the lines of

hook buffer BufWritePre .* { format }

in my config. I’d like to extend this to only write format if formatcmd is set. How would I do this? Or, am I missing something that kakoune can already do?

Probably the easiest solution would be to add that hook inside each hook that sets formatcmd, like:

hook global WinSetOption filetype=rust %{
    set-option window formatcmd rustfmt

    hook -group rust-auto-format window BufWritePre .* format

    hook -once -always WinSetOption filetype=.* %{
        unset-option window formatcmd
        remove-hooks window rust-auto-format

On the other hand, if you want to only write the hook once, you’ll need some kind of if/then statement to check the formatcmd option, which means you’ll need to invoke the shell to make the decisions. Typically, this is done with a combination of the %sh{} expansion (to generate text with the shell) and the evaluate-commands command, to execute the commands the %sh{} expansion generated:

hook buffer BufWritePre .* %{
    evaluate-commands %sh{
        if [ -n "$kak_opt_formatcmd" ]; then
            echo format

You might need to do something with a shell-script anyway, if you want your config to fail gracefully when the external formatting tool isn’t installed on a particular machine.

1 Like

The latter would now produce an error on startup:

'hook' no buffer in context

any ideas on how to do this now?
I like the idea of having lint after write and format pre write.
I also liked the idea of having it somehow agnostiv to the installed tools.

Maybe put it into another WinCreate hook?

No, it should still work properly.

That error looks like you’ve just pasted the example directly into your kakrc. At the time kakrc runs, no buffers exist yet, so hook buffer ... fails to install the hook at buffer scope. You probably want to change it to hook global ... so it will be available in every buffer.

of course!

Thanks for pointing that out!