Is there a way in vim to move backwards a tab as it does move forward a tab? For example, if my line is:

 *   *   *   *   *   *
 hello     |      =      4
           cursor is here

If I pressed [tab] it would go to the next tabstop, so:

 *   *   *   *   *   *
 hello       |      =      4
             cursor is here

How would I do un-tab, so my cursor would go here:

 *   *   *   *   *   *
 hello   |      =      4
         cursor is here

Note: I'm not looking for a >>/<<, or ctrl-d/ctrl-t, which tabs or untabs the entire line. I only want from the cursor position forward.

Update: I added a bounty for this question. I'd like to see how to add a 'forward-delete' with ctrl-d and a backward-delete with delete. Here is an example from TextMate: https://gyazo.com/c16d903c1a28c307e3875d9fdf11fe60

The closest I could find is:

*i_CTRL-I* *i_<Tab>* *i_Tab*
<Tab> or CTRL-I Insert a tab.  If the 'expandtab' option is on, the
    equivalent number of spaces is inserted (use CTRL-V <Tab> to
    avoid the expansion; use CTRL-Q <Tab> if CTRL-V is map
  • 1
    I'm not sure what you want. You seem to say you don't want to insert tabs (only move between them), while your example shows otherwise. Which one is it?
    – Biggybi
    Jul 20, 2020 at 10:10

1 Answer 1


It is called softtabstop and smarttab, you can read it in help :h 'softtabstop':

Number of spaces that a <Tab> counts for while performing editing
operations, like inserting a <Tab> or using <BS>.  It "feels" like
<Tab>s are being inserted, while in fact a mix of spaces and <Tab>s is
used.  This is useful to keep the 'ts' setting at its standard value
of 8, while being able to edit like it is set to 'sts'.  However,
commands like "x" still work on the actual characters.
When 'sts' is zero, this feature is off.
When 'sts' is negative, the value of 'shiftwidth' is used.

:h smarttab

When on, a <Tab> in front of a line inserts blanks according to
'shiftwidth'.  'tabstop' or 'softtabstop' is used in other places.  A
<BS> will delete a 'shiftwidth' worth of space at the start of the

Usually, one can set it to -1 to be equal to shiftwidth which is used to insert number of spaces instead of tab.

set softtabstop=-1 shiftwidth=4 expandtab smarttab

expandtab is needed to insert spaces instead of tabs, but I guess you have it somewhere in your settings (otherwise you would have used tabs and they behave the way you showed us).

PS, it doesn't work with <Delete>, backspace only (as far as I know). I guess it is possible to come up with insert mode remapping of <Delete> key to delete forward shiftwidth number of spaces.

enter image description here

PPS, proof of concept to forward delete:

func! DumbForwardDelete() abort
    let line = strcharpart(getline('.'), col('.'), shiftwidth())
    if line =~ '^\s*$' && strchars(line) == shiftwidth()
        return repeat("\<Del>", shiftwidth())
        return "\<Del>"

inoremap <expr> <Del> DumbForwardDelete()

Not very robust but might guide you to further improvements.

  • great, thanks for the thorough answer.
    – David542
    Jul 26, 2020 at 22:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.