Vimtab.kak - a more faithful implementation of vim's expandtab and softtabstop

I’m sure most people are happy with the implementation of vim’s expandtab and softtabstop options in @andreyorst’s smarttab.kak , but I wanted a more faithful implementation, so I wrote one in my personal kakrc and pulled it out into this gist.

What exactly does it mean that my implementation is more faithful? For example, if expandtab is false and softtabstop is different than tabstop, then if you press the <tab> key, my version inserts a mix of <tab>s and <space>s as needed (like vim does). Or if you press <backspace> it correctly removes whitespace until it reaches a column that is a multiple of softtabstop, splitting tabs into spaces as needed. In contrast, smarttab.kak does not handle these intricacies.

Give it a shot and let me know if you run into any issues!

1 Like

I wasn’t aware of that behavior :slight_smile:

And about this. In fact, I’ve always used Vim with these setting set to the same value, because I never had an idea why would you want them to be different.

I see these changes welcoming in smarttab.kak, so I would appreciate if you wanted to contribute those.

I think lots of vim users aren’t aware of this fact, that’s why I said I’m sure most people are fine with your implementation. Heck, even though I know about it, I also set my tabstop and softtabstop to the same value.

The main reason I bothered writing this was to support the most useful part of softtabstop for me — if I press <backspace> on some whitespace, I want it to erase whitespace until the cursor reaches a display column that is a multiple of softtabstop or a non-whitespace character, whichever is first. That’s not something your plugin supports, and none of the suggestions in the various issues discussing expandtab on kakoune’s github repo addressed that. Along the way, I decided I might as well support vim’s approach fully, especially since as a side project I started contributing to an open source repo that happened to use tabs rather than spaces.

I appreciate that, but I’m not sure it makes sense. To contribute my changes would likely mean replacing everything in rc/smarttab.kak with what I’ve written (except your code for displaying the current <tab> mode in the modeline).

I guess I could break my code out into a proper plugin file if it becomes popular enough and people want it. I didn’t go that route since I’ve tried to adopt a more minimalistic philosophy with my usage of kakoune, so I don’t currently use plugins (or a plugin manager) like I did with vim (though I do use kak-lsp).

A deeper dive for the truly curious

In case you’re interested, the second sentence of the option description when you type :help softtabstop in vim mentions it adds a mix of <tabs> and <spaces>. Additionally, the documentation for tabstop strongly cautions against changing tabstop from it’s default value of 8 and to just set shiftwidth and softtabstop to your desired value. The reasoning? To provide better support for printing text edited in vim — that seems like a very infrequent occurrence to me. Vim also has a smarttab option which conflict’s with smarttab.kak’s approach.

NOTE: I would have included more links, but apparently as a new user I’m limited to at most two links in a post/comment.

I mean, that’s fine by me too :smiley: (as long as user configurations aren’t broken), but I see your point and I won’t insist :slight_smile:

Ideally, though, I’d wish to see this feature shipped with the Kakoune itself, but, well… :sweat_smile:

For the record, it’s already a proper plugin file - if it’s a .kak file somebody can put into their autoload directory, it’s a plugin. Heck, since it’s in a GitHub gist, it’s already in an online GitHub repo that people can git submodule into their dotfiles repo if they want.

Hmm… maybe @mawww would be willing to reconsider? I know the issue has been brought up a bunch, but I believe the complexity of properly implementing expandtab and softtabstop support is quite high (it was non-trivial to implement). That said, I’m not sure how necessary it is. The following insert mode mappings (wrapped in hooks to allow disabling) work reasonably well to emulate expandtab while allowing indentation, without requiring any new options.

def insert-tab -hidden %{
    # Fallback to insert <tab> or <space>s based on indentwidth
    # when hooks are disabled with '\'
    evaluate-commands %sh{
        if [ $kak_opt_indentwidth -eq 0 ]; then
            echo "execute-keys <tab>"
        else
            printf "execute-keys '""%$kak_opt_indentwidth""s'\n"
        fi
    }
}
def insert-tab-mapping -hidden -params 1 %{
    %arg{1} window insert <tab> '<a-;><a-gt>'
    %arg{1} window insert <s-tab> '<a-;><a-lt>'
}
map global insert <tab> '<a-;>:insert-tab<ret>'
hook global ModeChange 'push:.+:insert' %{ insert-tab-mapping 'map' }
hook global ModeChange 'pop:insert:normal' %{ insert-tab-mapping 'unmap' }

My main programming language these days is python and I believe the above mappings are sufficient to handle day-to-day editing. That said, learning the intricacies of these settings is not easily surfaced to users, so it’s understandable why the issue has been brought up a bunch. Most users likely expect it to be simple and very straightforward to set something like this up.

TBH, I might try the minimal kakrc settings I listed above rather than the vimtab.kak approach for a while and see if it scratches the itch. This minimal approach isn’t quite as elegant as it doesn’t cover all the cases, but I don’t know how often I’ll run into an issue in practice (i.e. how often will I press <tab> that expands to multiple <space>s that I subsequently want to delete).

1 Like