quickrun で filetype ごとの初期値を設定する

[目的]

quickrun_config で各 filetype ごとに細かく config を設定をする場合、

let g:quickrun_config = {
\
\   "cpp/msvc" : {
\       "command" : "cl.exe",
\       "exec"    : "%c %o %s:p",
\       "hook/output_encode/encoding" : "sjis"
\       "hook/add_include_option/enable" : 1,
\       "hook/unite_quickfix/enable_full_data" : 1,
\       "hook/close_buffer/enable_success" : 1
\   },
\
\   "cpp/clang++" : {
\       "command"   : "clang++",
\       "exec" : "%c %o %s -o %s:p:r ",
\       "hook/add_include_option/enable" : 1,
\       "hook/unite_quickfix/enable_full_data" : 1,
\       "hook/close_buffer/enable_success" : 1
\   },
\
\   "cpp/g++4.8-pedantic" : {
\       "command"   : "g++.exe",
\       "exec" : "%c %o %s -o %s:p:r ",
\       "hook/add_include_option/enable" : 1,
\       "hook/unite_quickfix/enable_full_data" : 1,
\       "hook/close_buffer/enable_success" : 1
\   },
\}

:QuickRun cpp/clang++


このように各 config ごとに hook を設定しているのですが、これだと無駄が多いです。
と、いうことで quickrun_config に filetype ごとの初期値を設定出来るようにしましょう。

[既存の機能]

quickrun では config.type の設定が参照されるので下記のような書き方が出来ます。

let g:quickrun_config = {
\
\   "cpp" : {
\       "type" : "cpp/msvc",
\       "hook/add_include_option/enable" : 1,
\       "hook/unite_quickfix/enable_full_data" : 1,
\       "hook/close_buffer/enable_success" : 1
\   },
\
\   "cpp/msvc" : {
\       "command" : "cl.exe",
\       "exec"    : "%c %o %s:p",
\       "cmdopt"  : s:msvc_release_option,
\       "hook/output_encode/encoding" : "sjis"
\   },
\
\   "cpp/clang++" : {
\       "command"   : "clang++",
\       "exec" : "%c %o %s -o %s:p:r ",
\   },
\
\   "cpp/g++4.8-pedantic" : {
\       "command"   : "g++.exe",
\       "exec" : "%c %o %s -o %s:p:r ",
\   },
\}

" cpp → cpp.type(cpp/msvc) の設定が適用される
:QuickRun cpp


config.type を使用することで、このように定義することが出来ます。

[問題点]

さて、基本的には上記のままでもいいんですが、これにも問題点があります。
上記の場合、quickrun の仕様では cpp が優先されてしまい、cpp/msvc の設定が適用されません。
例えば、下記のように cpp/test で hook を enable 0 にしても cpp の方が優先されてしまい適用されません。

let s:hook = {
\   "name" : "test",
\   "kind" : "hook"
\}

function! s:hook.on_ready(...)
    echom "hook test"
endfunction

call quickrun#module#register(s:hook, 1)
unlet s:hook


let g:quickrun_config = {
\
\   "cpp/_" : {
\       "hook/test/enable" : 1
\   },
\
\   "cpp/test" : {
\       "hook/test/enable" : 0,
\   }
\}

" cpp  → cpp/test の順で適用され、cpp が優先されるので
" hook/test/enable 1 が適用され "hook test" がコマンドラインに出力される
:QuickRun cpp


と、いうことで quickrun-hook を使って解決します。

[quickrun-hook-extend_config]

let s:hook = {
\   "name" : "extend_config",
\   "kind" : "hook",
\   "config" : {
\       "enable" : 0,
\       "target" : "&filetype/_",
\       "override" : 0,
\   }
\}

function! s:hook.init(session)
    if self.config.enable
        let quickrun_config = g:quickrun_config
        if has_key(quickrun_config, self.config.target)
            call extend(a:session.config, quickrun_config[self.config.target], self.config.override ? "force" : "keep")
        endif
    endif
endfunction

call quickrun#module#register(s:hook, 1)
unlet s:hook


let g:quickrun_config = {
\
\   "cpp" : {
\       "type" : "cpp/msvc",
\        "hook/extend_config/enable" : 1,
\   },
\
\   "cpp/_" : {
\       "hook/add_include_option/enable" : 1,
\       "hook/unite_quickfix/enable_full_data" : 1,
\       "hook/close_buffer/enable_success" : 1
\   },
\
\   "cpp/msvc" : {
\       "command" : "cl.exe",
\       "exec"    : "%c %o %s:p",
\       "cmdopt"  : s:msvc_release_option,
\       "hook/output_encode/encoding" : "sjis"
\   },
\
\   "cpp/clang++" : {
\       "command"   : "clang++",
\       "exec" : "%c %o %s -o %s:p:r ",
\   },
\
\   "cpp/g++4.8-pedantic" : {
\       "command"   : "g++.exe",
\       "exec" : "%c %o %s -o %s:p:r ",
\   },
\}


hook で初期化時に指定された config を extend しています。
デフォルトでは quickrun_config.{&filetype}/_ を extend 対象として参照し、config.type の設定が優先されます。
これですっきり。