Vim cursor position after expanding html tag

@RandyMorris and @romainl have posted good solutions for your exact problem.

There are some other possibilities you might be interested in if you are typing out these tags yourself: there's the ragtag.vim plugin for HTML/XML editing.

With ragtag.vim you type this to create your "before" situation (in insert mode):

div<C-X><Space>

To create your "after" situation you would instead type:

div<C-X><Enter>

So if you know beforehand that you are going to "expand" the tag, typing just the element name and the combo CtrlX followed by Enter is enough.

There are also other more advanced plugins to save keystrokes when editing HTML, such as ZenCoding.vim and Sparkup.


The only correct behavior of <CR> in insert mode is to break the line at the cursor.

What you want is an enhanced behavior and you need to add something to your config to get it: a mapping, a short function or a full fledged plugin.

When I started to use vim, that behavior was actually one of the first things I added to my vimrc. I've changed it many times in the past but this mapping has been quite stable for a while:

inoremap <leader><CR> <CR><C-o>==<C-o>O

I've used <leader><CR> to keep the normal behavior of <CR>.


Here is a small function that seems to do what you want:

function! Expander()
  let line   = getline(".")
  let col    = col(".")
  let first  = line[col-2]
  let second = line[col-1]
  let third  = line[col]

  if first ==# ">"
    if second ==# "<" && third ==# "/"
      return "\<CR>\<C-o>==\<C-o>O"

    else
      return "\<CR>"

    endif

  else
    return "\<CR>"

  endif

endfunction

inoremap <expr> <CR> Expander()

This little snippet will remap Enter in insert mode to test whether or not the cursor is between > and < and act accordingly if it is. Depending on your indent settings the \<Tab> may need to be removed.

It will not play nice with other plugins that might be also be mapping the Enter key so be aware that there is probably more work to do if you want that compatibility.

function EnterOrIndentTag()
  let line = getline(".")
  let col = getpos(".")[2]
  let before = line[col-2]
  let after = line[col-1]

  if before == ">" && after == "<"
    return "\<Enter>\<C-o>O\<Tab>"
  endif
   return "\<Enter>"
endfunction

inoremap <expr> <Enter> EnterOrIndentTag()

I have only tested the simple cases (beginning of the line, end of the line, inside and outside of ><), there are probably edge cases that this would not catch.