Replace tabs/spaces on save/load

Hi good people of this community,

I’m experimenting with kakoune and I would like to know if there is easy way to achieve
replacing spaces to tabs on opening buffer and tabs to spaces on saving.

For now I just do %|unexpand -t 2 and %|expand -t 2. But could not figure out how to put them into hooks.

Thank you

You don’t need an external tool, the <@> normal-mode command converts tabs to spaces, and <a-@> converts spaces to tabs, using the current value of the tabstop option as the conversion ratio.

The easiest way to automatically do the conversion would be:

# Make sure the tabstop width is set correctly
set-option global tabstop 2

# Every time any file is opened...
hook global BufOpenFile .* %{
    # % selects the entire buffer
    # <a-@> converts spaces to tabs
    # -draft means the actual selection won't be disturbed
    #    by the "select all" operation
    execute-keys -draft %<a-@>
}

# Every time any file is about to be written out...
hook global BufWritePre .* %{
    # Convert all the tabs to spaces
    execute-keys -draft %@
}

# After a file has finished being written out...
hook global BufWritePost .* %{
    # Convert all the spaces back to tabs so we can continue editing
    execute-keys -draft %<a-@>
}

The only downside here would be that the BufWritePost hook modifies the buffer, so every time you save it will be marked as unsaved immediately, and you’ll have to quit Kakoune with :q! every time instead of just :q.

1 Like

Thank you, I tried your code and I just need add quotes

#	Convert	tabs to	spaces
hook global	BufOpenFile .* %{
	execute-keys -draft	'%<a-@>'
}

#	Convert	spaces to	tabs
hook global	BufWritePre	.* %{
	execute-keys -draft	'%@'
}

#  Convert tabs back to spaces to continue editing files
hook global	BufWritePost .*	%{
	execute-keys -draft	'%<a-@>'
}

Another problem is that it is converting to tabs even spaces hook and global for some reason :frowning: (I tested it on mi kakrc, this sample is copy pasted from kakoune so if you copy paste to any editor you will see)

But still thank you, I think I can solve it now

Or maybe I can’t, I tried also

# Convert tabs to spaces
hook global BufOpenFile .* %{
  execute-keys -draft '%|unexpand -t $kak_opt_tabstop'
}

# Convert spaces to tabs
hook global BufWritePre .* %{
  execute-keys -draft '%|expand -t $kak_opt_tabstop'
}

# Convert tabs back to spaces to continue editing files
hook global BufWritePost .* %{
  execute-keys -draft '%|unexpand -t $kak_opt_tabstop'
}

but is doing nothing

I noticed that when I experiment during runtime with :, and I add space after pipe in execute keys, I end up with pipe: unexpand -t $kak_opt_tabstop

execute-keys '%| unexpand -t $kak_opt_tabstop', but I'm not sure how to send enter

I think you want to select only the leading spaces/tabs before doing the conversion with @/<a-@>, since otherwise it would affect the spaces/tabs everywhere.

E.g. tabs to spaces:

execute-keys -draft	'%s^\t+<ret>@'

Spaces to tabs:

execute-keys -draft	'%s^ +<ret><a-@>'

I’m not sure how to send enter

As you can see above too, you can use <ret> to send an enter key in execute-keys.

Also, I noticed that your comments are incorrect in this post.

Thank you, that worked, last thing I could not figure out, how to select in hook all files beside Makefile