Question

I am trying to make Vim indent lines like Emacs (that is, "make the current line the correct indent" instead of "insert tab character"). Vim can do this with = (or ==) for one line). I have imap <Tab> <Esc>==i in my .vimrc but this makes the cursor move to the first non-space character on the line. I would like the cursor position to be preserved, so I can just hit tab and go back to typing without having to adjust the cursor again. Is this possible?

Example

  • What I have now (| represents the cursor):

    function f() {
    doso|mething();
    }
    

    Tab

    function f() {
        |dosomething();
    }
    
  • What I would like:

    function f() {
    doso|mething();
    }
    

    Tab

    function f() {
        doso|mething();
    }
    

    Also

    function f() {
     |  dosomething();
    }
    

    Tab

    function f() {
       |dosomething();
    }
    
Was it helpful?

Solution

I don't believe there's an "easy" way to do this (that is, with strictly built-in functionality) but a simple function does it just fine. In your .vimrc file:

function! DoIndent()       
    " Check if we are at the *very* end of the line
    if col(".") == col("$") - 1
        let l:needsAppend = 1
    else
        let l:needsAppend = 0
    endif

    " Move to location where insert mode was last exited
    normal `^

    " Save the distance from the first nonblank column
    let l:colsFromBlank = col(".")
    normal ^
    let l:colsFromBlank = l:colsFromBlank - col(".")

    " If that distance is less than 0 (cursor is left of nonblank col) make it 0
    if l:colsFromBlank < 0                            
        let l:colsFromBlank = 0
    endif

    " Align line
    normal ==

    " Move proper number of times to the right if needed
    if l:colsFromBlank > 0
        execute "normal " . l:colsFromBlank . "l"
    endif

    " Start either insert or line append
    if l:needsAppend == 0
        startinsert
    else
        startinsert!
    endif
endfunction                                   

" Map <Tab> to call this function                                          
inoremap <Tab> <ESC>:call DoIndent()<CR>

OTHER TIPS

There's always <C-T> and <C-D> (that is CtrlT and CtrlD) in insert mode to indent and outdent on the fly.

These don't change the cursor position – and they're built-in functionality.

Try using a mark of last insert mode, and use the append command to set the cursor back just where it was before, like:

:imap <Tab> <Esc>==`^a
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top