76 dicwin2.vim (5-2) echo で表示できるようにした

辞書引きプラグイン作成のお話。手ごろな名前が思い浮かばないのでひとまず dicwin2.vim としておく。

昨日はごめん ( AL_urlencode() )

昨日、あたかも当然のように encodeURI, encodeURIComponent を書いたんだけど、よくよく見てみると alice.vim の AL_urlencode() なんてのがある。ほとんど同じ動作みたい。既存のものを有効活用してください。そちらをご利用ください。うん。

今日は HTML の取得、解釈、表示

さてさて、車輪のなんとかをしてしまったわけだが、気にしないで進む。昨日は、ブラウザで表示までができた。今日は、 HTML を取得して解釈して echo コマンドで表示と、ここまでやってみる。そしてこちらにできあが(ry

function! s:YahooKokugo(html)
  let s = iconv(a:html, 'utf-8', &enc)
  let s = get(matchlist(s, '<body\>\_.\{-}>\(\_.*\)</body>'), 1, '')
  let s = get(matchlist(s, '<div id="contents">\(\_.*\)</div>'), 1, '')
  let s = get(matchlist(s, '<div align="center">\(\_.*\)</div>'), 1, '')
  let s = get(matchlist(s, '<td valign="top">\(\_.*\)</td>'), 1, '')
  let t = get(matchlist(s, '<b>\(.\{-}\)</b>'), 1, '')
  let s = get(matchlist(s, '<table\(\_.\{-}\)</table>', 0, 3), 1, '')
  let d = get(matchlist(s, '<td>\(.\{-}\)</td>'), 1, '')
  let d = substitute(d, '<br\s*/\{0,1}>', "\n", 'g')
  let t = substitute(t, '<.\{-}>', '', 'g')
  let d = substitute(d, '<.\{-}>', '', 'g')
  return {'title': t, 'description': d}
endfunction

let g:dicwin2_dict = {
      \ 'url':
      \ 'http://dic.yahoo.co.jp/dsearch?enc=UTF-8&stype=0&dtype=0&p=%keyword%',
      \ 'parser':
      \ function('s:YahooKokugo')
      \ }

silent! nnoremap <unique> <silent> \dy :call AL_open_url(
      \ 'http://dic.yahoo.co.jp/dsearch?enc=UTF-8&stype=0&dtype=2&p=' .
      \ <SID>encodeURIComponent(expand('<cword>')), '')<CR>
silent! nnoremap <unique> <silent> \dY :call <SID>dicwin2()<CR>

function! s:dicwin2()
  let dict = g:dicwin2_dict
  let keyword = s:encodeURIComponent(expand('<cword>'))
  let url = s:replace(dict['url'], '%keyword%', keyword)
  let cmd = 'curl "%URL%"'
  let cmd = s:replace(cmd, '%URL%', url)
  let html = system(cmd)
  let list = call(dict['parser'], [html])
  echo list['title']
  echo list['description']
endfunction

function! s:encodeURI(str)
  let to_enc = 'utf8'
  let t = ''
  let s = iconv(a:str, &enc, to_enc)
  let save_enc = &enc
  let &enc = to_enc
  let i = 0
  let c = s:strpart2(s, i, 1)
  while c != ''
    if c =~# '[0-9A-Za-z-._~!''()*]' || c =~# '[#$&+,/:;=?@]'
      let t = t . c
    elseif c =~# '[:cntrl:]'
    else
      let n = strlen(c)
      let j = 0
      while j < n
        let t = t . printf('%%%02X', char2nr(strpart(c, j, 1)))
        let j = j + 1
      endwhile
    endif
    let i = i + 1
    let c = s:strpart2(s, i, 1)
  endwhile
  let &enc = save_enc
  let t = iconv(t, to_enc, &enc)
  return t
endfunction

function! s:encodeURIComponent(str)
  let to_enc = 'utf8'
  let t = ''
  let s = iconv(a:str, &enc, to_enc)
  let save_enc = &enc
  let &enc = to_enc
  let i = 0
  let c = s:strpart2(s, i, 1)
  while c != ''
    if c =~# '[0-9A-Za-z-._~!''()*]'
      let t = t . c
    elseif c =~# '[:cntrl:]'
    else
      let n = strlen(c)
      let j = 0
      while j < n
        let t = t . printf('%%%02X', char2nr(strpart(c, j, 1)))
        let j = j + 1
      endwhile
    endif
    let i = i + 1
    let c = s:strpart2(s, i, 1)
  endwhile
  let &enc = save_enc
  let t = iconv(t, to_enc, &enc)
  return t
endfunction

function! s:replace(s, t, r)
  return substitute(a:s, '\C\V' . escape(a:t, '\'), escape(a:r, '&~\'), 'g')
endfunction

function! s:strpart2(src, start, ...)
  let len = exists('a:1') ? a:1 : 0
  let pat = ''
  let pat = pat . '^.\{' . a:start . '}\zs.'
  let pat = pat . (len > 0 ? '\{' . len . '}' : '*' ) . '\ze'
  return matchstr(a:src, pat)
endfunction

ごちゃごちゃしているけど、まだ vimrc に書いてる段階だから気にしない。folding を使用すればこれくらいなら気にならない。

まず、マッピング \dY を追加した。これがスクリプトローカル関数 dicwin2() を呼び出す。この関数では、辞書型のグローバル変数 dicwin2_dict から、アクセスする先の URL である url と、それを解釈するための関数参照型である parser を取り出して、使用する。カーソルの下のキーワードを URL に適当に組み込んで、curl で HTML を取得する。取得した HTML を parser に渡す。辞書型が帰ってくるので、title と description を表示する。

とりあえず Yahoo の国語辞典を解釈できるようにしてみた。表示形式変わったら困るだろうけど、それはスクリプトローカル関数 YahooKokugo() の修正で対応する。これは、よくあるパターンのはず。

ごちゃごちゃ書いてるけど、要は、昨日ブラウザで表示されてたものが echo コマンドで表示されるようになったってこと。

見つからなかったときの処理がされていなかったり、 echo コマンドだから引用がしにくかったり。そのあたりをまた改良していくつもり。