vim settings for [x]html

http://d.hatena.ne.jp/janus_wel/20090131/1233609383 の続き。とりあえず以前の記事 ( http://d.hatena.ne.jp/janus_wel/20080527/1213598995 ) が紹介された ( http://blog.blueblack.net/item_342 ) のでちょいと見直してみた。使える tag は omni 補完でなんとかして閉じ tag も適当に補完させながらガリガリ書く。で、最後に HTML Tidy に整形させて :make で文法的におかしいところをつぶしていく感じ。ちゃんと設定したら quick reference とか開かなくてよくなった。 vim 実はすごい子。

  • .vimrc
    • filetype が xhtml じゃないと omni completion での tag 補完が大文字になってしまうので autocmd + setfiletype で先に決定させる。 setfiletype は autocmd で使用かつ filetype が決定してないときのみ filetype を書き換えるらしい ( :help :setfiletype ) 。
" I will write xhtml only
autocmd BufNewFile,BufRead *.html :setfiletype xhtml
  • 閉じ tag 補完
    • </ と打ったあとに omni completion を利用するのもいいんだけど "</" すら打ちたくないので http://www.stripey.com/vim/html.html の InsertCloseTag() を xhtml 用に書き換えたものを ~\vimfiles\ftplugin\html.vim に書き込む。っても適用する filetype を追加して tag を減らしてるだけ。
" function to close tag
function! InsertHTMLCloseTag()
" inserts the appropriate closing HTML tag; used for the \hc operation defined
" above;
" requires ignorecase to be set, or to type HTML tags in exactly the same case
" that I do;
" doesn't treat <P> as something that needs closing;
" clobbers register z and mark z
"
" by Smylers http://www.stripey.com/vim/
" 2000 May 3

    if &filetype == 'html' || &filetype == 'xhtml'

        " list of tags which shouldn't be closed:
        "let UnaryTags = ' Area Base Br DD DT HR Img Input LI Link Meta P Param '
        let UnaryTags = ' area base br hr img input link meta param '

        " remember current position:
        normal mz

        " loop backwards looking for tags:
        let Found = 0
        while Found == 0
            " find the previous <, then go forwards one character and grab the first
            " character plus the entire word:
            execute "normal ?\<LT>\<CR>l"
            normal "zyl
            let Tag = expand('<cword>')

            " if this is a closing tag, skip back to its matching opening tag:
            if @z == '/'
                execute "normal ?\<LT>" . Tag . "\<CR>"

            " if this is a unary tag, then position the cursor for the next
            " iteration:
            elseif match(UnaryTags, ' ' . Tag . ' ') > 0
                normal h

            " otherwise this is the tag that needs closing:
            else
                let Found = 1

            endif
        endwhile " not yet found match

        " create the closing tag and insert it:
        let @z = '</' . Tag . '>'
        normal `z"zp

    else " filetype is not HTML
        echohl ErrorMsg
        echo 'The InsertCloseTag() function is only intended to be used in HTML ' .
                    \ 'files.'
        sleep
        echohl None
    endif " check on filetype

endfunction " InsertHTMLCloseTag()
    • で、こいつを使うための key mapping は以下。これを .vimrc に書いとく。 html を編集してる buffer ( tab ) のみで有効にするために 指定してるのと補完させたあとに closing tag の直前に cursor を持ってくるようにしてるのがポイント ?
" complete closing tab
autocmd Syntax html,xhtml :inoremap <buffer><C-f> <Esc>:call InsertHTMLCloseTag()<CR>b2hi
  • template
    • 新しく html ファイルをつくるときの template の準備。やり方はいろいろなところで紹介されているのでうちでは template の準備方法を。好みはいろいろあると思うんだけど http://heaven7.sakura.ne.jp/reference/xhtml_ref/xhtmltmp.html で出力して自分好みに変えると楽。っていうか後述する HTML Tidy に書き戻させてから自分好みに変えると良さげ。っても :set fileformat=unix:set fileencoding=utf-8 しただけなんだけど。うちの場合以下のような感じ。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <meta http-equiv="Content-Script-Type" content="text/javascript" />
  <meta http-equiv="Content-Style-Type" content="text/css" />
  <meta name="description" content="内容説明" />
  <meta name="author" content="janus_wel" />
  <link rev="Made" href="mailto:janus.wel.3@gmail.com" />
  <link rel="Contents" href="URL" />
  <link rel="Index" href="URL" />
  <link rel="Parent" href="URL" />
  <link rel="Start" href="URL" />
  <link rel="Next" href="URL" />
  <link rel="Prev" href="URL" />

  <title>title</title>
</head>

<body>
  <h1>title</h1>

  <p>contents</p>
</body>
</html>
" load xhtml template automatically
autocmd BufNewFile *.html 0r $VIMPERSONAL/template/xhtml.html
  • with HTML Tidy
    • QuickFix を覚えたので簡単に :make ( validation check ) できるようにしたり、書き戻すときの設定を見直したりと http://d.hatena.ne.jp/janus_wel/20080527/1213598995 からいろいろ変更。まず html.vim に HTML Tidy と連携するための設定を書く。
    • 構文を check するのに :make を使うので makeprg を設定する ( :help makeprg ) 。とりあえず "-raw" 指定がないと HTML Tidy さんは日本語使うなとか無茶をいいやがるので指定。あと主に Windows 用に path に空白が含まれててもいいように % を " でかこってる。
    • HTML Tidy で html を整形して書き戻すための設定は ModifyByHTMLTidy() 。大層に関数定義してるけど update して変更を反映させたあとに config file 指定アリで tidy を呼び出してるだけ。 update がないといろいろうっとうしいので指定してる。あと file の位置が固定なのは手抜きです。
" for make
" double quotation for % ("%") is needed for Windows
setlocal makeprg=tidy\ -raw\ -quiet\ -errors\ --gnu-emacs\ yes\ \"%\"

" check, fix, form document and write it back
setlocal autoread
function! ModifyByHTMLTidy()
    update
    !tidy  -config ~/.tidyrc -quiet -modify "%"
endfunction
    • で、書き戻しのときに使用する HTML Tidy の config file は以下のような感じで。 newline は LF で固定だけど default のままだと Windows の場合強制的に CRLF にされてしまうのでこうしてる。用途に応じていくつか準備しておいて ( CRLF 版とか ) 必要に応じて切り替えるのが HTML Tidy 流ぽいので http://tidy.sourceforge.net/docs/quickref.html を参考にしながらいろいろいじってみるのがいいかも。ただこの page の英語は非常に読みづらいので try and error 必須。
bare:yes
char-encoding:raw
clean:yes
fix-backslash:yes
fix-bad-comments:yes
indent-attributes:no
indent-cdata:no
indent-spaces:2
indent:auto
newline:LF
replace-color:yes
wrap-asp:no
wrap-attributes:no
wrap-jste:no
wrap-php:no
wrap-script-literals:no
wrap-sections:no
wrap:0
    • 最後に .vimrc に以下を書くと書き戻しも楽に呼び出せるようになる。やっぱり を指定して buffer ( tab ) 限定 key mapping にしてる。 :make での構文チェックは自分で打つか適当に key mapping しとく方向で。てか :make なら普通に key mapping しといたほうが便利だと思う。
" modify by HTML Tidy
autocmd BufNewFile,BufRead *.html :nnoremap <buffer><silent><Leader>h :call ModifyByHTMLTidy()<CR>
  • miscs
    • 最後にいくつか細かいところ。 tabstop / shiftwidth は 4 派なんだけど html は nest が深くなるのでの 2 に。あと上記で挙げた autocmd をすべて xhtml という augroup にまとめたりしてる。なんか autocmd 使う前には autocmd! して既存のを消してから定義するとか augroup でまとめて扱いやすくするとかは定石らしい ( :help augroup ) 。