"Formatting XML in Vim with indent command"
September 08, 2011
Today I had a need to look at XML doc fetched from Google Calendar API. I saved it to a file and opened in Vim. Unfortunately API output was generated to be consumed by machines rather than humans.
First I tried gg=G
command. = is used to auto-indent selected line(s) and gg=G
re-indents whole file. Usually it works great, especially for source code files. It does not reformat code, it only changes indentation. And that's good, I should be the one to control look of my code. But for XML I want it to do full reformatting. I'm not writing XML and in all of the cases when I open such docs in my editor I only want to look at well-formatted, human-readable XML.
From Vim help on equalprg setting:
External program to use for "=" command. When this option is empty the internal formatting functions are used; either 'lisp', 'cindent' or 'indentexpr'. When Vim was compiled without internal formatting, the "indent" program is used. ...
"Bingo! Let's use xmllint for that!" - I thought immediately. xmllint command comes bundled with libxml package on Unix-like systems and does really good job at producing pretty output. You can use it like this:
# shell
xmllint --format --recover foo.xml
Okee, so my first approach to reformatting XML in Vim was:
:1,$!xmllint --format --recover - 2>/dev/null
Not bad. But writing it every time (or remembering) would be painful. Let's use mentioned equalprg option:
# .vimrc
set equalprg=xmllint\ --format\ --recover\ -\ 2>/dev/null
Ok... but Y U USE XMLLINT WHEN I'M INDENTIN' MY RUBY CODE?? Ahaa! equalprg need to be set locally only for XML-type buffers. Autocommand did the trick:
# .vimrc
au FileType xml setlocal equalprg=xmllint\ --format\ --recover\ -\ 2>/dev/null
Restarted Vim, typed gg=G
and said "Hell yeah!".