wrapping text in vim

For long time, I wanted the following functionality in vim: I select text and say “wrap the text by a tag”. Now I’m formatting texts for HTML, and this functionality is so much required that I’ve got it.

Google suggested:

Tip #346: Wrap text in HTML/XML tags after prompting for the tag name

I’ve put the code from the comment labelled as “David Fishburn, May 8, 2006″ to the file tagwrap.vim, and stored the file in the folder $HOME/.vim/plugin. To trigger wraping, I press the button “,” three times.


" These mappings and TagSelection function will allow you to place
" an XML tag around either the current word, or the current selected
" text.
" If the visual select is on a single line, the tag is wrapped
" around the text <this>way</this>.  If the visual select extends
" over multiple lines, the tag is wrapped around the text
"     <this>
"     way
"     </this>
"    
" When you are prompted for the tag name, you can enter:
"     Tag name?  p class="classname" attri="bute"
" The select is wrapped with:
"     <p class="classname" attri="bute">
"     Your selection
"     </p>
" Notice the attributes have been stripped from the closing tag.
"
" Use nmap, not nnoremap, since we do want to use an existing mapping
nmap ,,, viw,,,
vnoremap ,,, <Esc>:call TagSelection()<CR>

function! TagSelection()
  let tag = input("Tag name (include attributes)? ")

  if strlen(tag) == 0
      return
  endif

  " Save b register
  let saveB       = @b
  " <C-R> seems to automatically reindent the line for some filetypes
  " this will disable it until we have applied our changes
  let saveIndent  = &indentexpr
  let curl        = line(".")
  let curc        = col(".")
  let &indentexpr = ''

  " If the visual selection is over multiple lines, then place the
  " data between the tags on newlines:
  "    <tag>
  "    data
  "    </tag>
  let newline = ''
  if getline("'>") != getline("'<")
      let newline = "\n"
      let curl  = line("'>")
  endif

  " Strip off all but the first word in the tag for the end tag
  let @b = newline . substitute( tag, '^[ \t"]*\(\<\S*\>\).*', '<\/\1>\e', "" )
  let curc = curc + strlen(@b)
  exec "normal `>a\<C-R>b"

  let @b = substitute( tag, '^[ \t"]*\(\<.*\)', '<\1>\e', "" ) . newline
  let curc = curc + strlen(@b)
  exec "normal `<i\<C-R>b"

  " Now format the area
  exec "normal `<V'>j="

  " Restore b register
  let @b          = saveB
  let &indentexpr = saveIndent

  call cursor(curl, curc)
endfunction

5 Responses to “wrapping text in vim”

  1. Ivar Refsdal Says:

    This is pretty nice, but somehow the indenting doesn’t quite work for me.
    Could be my settings.
    (I want it to be:)

    *TAB*selected
    *TAB*text

    to:

    *TAB*
    *TAB**TAB*selected
    *TAB**TAB*text
    *TAB*

    I made this one-liner, not as advanced as your function though,
    but does the indenting correct for me:

    vmap ss >`”zdkok$”zp:%s/rafftag//g

    The indenting has been a problem for me too.
    b doesn’t work too well. “bp works much better.
    Or you can do :set paste and :set nopaste)afterwards.

  2. Ivar Refsdal Says:

    Original post without escaped tags:

    http://www.pasteserver.net/2205

  3. olpa Says:

    It’s hard for me to comment… Sorry, I’m not a vim expert.

  4. sdfadsf Says:

    Take a look at the surround plugin:

    http://www.vim.org/scripts/script.php?script_id=1697

  5. sdfadsf Says:

    Also, next time you don’t know how to do something in vim, you might want to try asking in #vim on freenode.

    http://vim.wikia.com/wiki/Vim_on_Freenode

Leave a Reply