Search code examples
vim

How to make vim traverse 4 spaces as if they were tabs?


The thing that bothers me about the (nearly) ubiquitous decision to move spaces is that in something like vim it still treats 4 spaces as 4 spaces for the sake of traversing cursor position with arrow keys.

I've figured out how to delete 4 spaces at a time... But how can vim be configured to traverse 4 consecutive spaces at a time as if it were really a tab?


Solution

  • I noticed the question explicitly mentions arrow keys while more seasoned Vim users would usually use hjkl for navigation. These have the minor advantage that they can be used without leaving the home row.

    Don't get me wrong, there's nothing inherently wrong with using the arrow keys. It's just that Vim offers more powerful alternatives.

    Even when going with l, the cursor moves only one character at the time.

    Traversing a file character by character reminds me of driving with someone shouting bad directions from the passenger's seat. Like "left, straight, right, right, straight, stop" instead of "go around that block, then turn into the parking lot". You will eventually get there, it's just not efficient and a little bit unnerving.

    In the comments, a lot of sensible ideas have been proposed and I throw in some more:

    • w jumps to the start of the next word.
    • ^ jumps to the first non-blank character.
    • [count]l (e.g. 4l) moves [count] characters to the right.
    • [count]| jump to [count]th column.
    • f<char> jump to the next occurrence of <char> on the line.

    In Vim, type :help left-right-motions to see a lot of commands for horizontal movement. There's a learning curve to it and I can see how a lot of commands to do something seemingly simple can be intimidating.

    There exist also other text editors besides Vim, even on relatively bare Linux systems. Different editors offer different features such as a heuristic to go by virtual tabs. If it's a must-have, I'd consider trying out other editors as well.

    Now that all the sensible ideas have been discussed, let's talk about bad ideas. For no other reason than to kill some time, I came up with the following Vim script which - I think - nobody should have in their vimrcs:

    function! JumpToNextTab()
        let c = col('.')
        let sw = shiftwidth(c)
        let ns = (c/sw + 1) * sw
        if match(getline('.'), '^ \{'.(c-ns).'}', c-1) > -1
            return ns.'|'
        endif
        return 'l'
    endfunction
    
    nnoremap <expr> <right> JumpToNextTab()
    xnoremap <expr> <right> JumpToNextTab()
    inoremap <expr> <right> '^O'.JumpToNextTab()
    

    Now this abomination of a function will move normally when on text but when on white space, it will look ahead if there's nothing but spaces until the next multiple of shiftwidth and if so, jump there. This only works for moving right and will break horribly when the vartabstop option is set and probably on several more occasions.

    This also offers mappings for normal, visual and insert modes. The mapping for insert mode needs to be prefixed with Ctrl-O (see :help i_CTRL-O) to execute the command. You can create the ^O thing by pressing Ctrl-VCtrl-O.

    Now that you've seen it, pressing w does not seem so bad after all, does it?