77 dicwin2.vim (5-3) pedit コマンドで表示するようにした

昨日、一昨日あたりから書いている「辞書引きプラグイン」。pedit で表示するようにしたのが、今日の主な変更点。

substitute() の \= は便利

alice.vim の AL_urlencode() を参考に修正してみた。AL_urlencode() から学んだ一番大きいことが \= だ。 substitute() の sub-replaced-special の一つで sub-replace-expression というものらしい。詳しくはヘルプを参照してほしい。一文字ずつスクリプトローカル変数 strpart2() で回していたのを、substitute() 一つに収めることができた。

1バイトずつなら char2nr() は encoding に影響されない

他に学んだことといえば、1バイトずつ char2nr() するとき、 encoding の値が結果に影響しないということ。iconv() で変換したら、あとは1バイトずつ処理さえすれば encoding を考慮する必要はない。

で、今回の修正点は

修正点としては、「pedit コマンドを使用するようにしたこと」と「上記の二点を反映して全体的にコードをシンプルにしたこと」と「簡単なメッセージを表示するようにしたこと」と「古い側のマッピング \dy を削除し、\dY に割り当てていたものを \dy に割り当てた」この四点だ。

以下はそのコード。

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')
  if t == '' || d == ''
    return {} 
  else
    return {'title': t, 'description': d}
  endif
endfunction

let g:dicwin2_dict = {
      \ 'encoding': 'utf-8',
      \ '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 <SID>dicwin2()<CR>

function! s:dicwin2()
  let dict = g:dicwin2_dict
  let cmd = 'curl "%URL%"'
  if type(dict) != type({}) ||
        \ !has_key(dict, 'encoding') ||
        \ !has_key(dict, 'url') ||
        \ !has_key(dict, 'parser')
    echohl WarningMsg
    redraw | echo printf("dicwin2: '%s' is invalid", 'dicwin2_dict')
    echohl None
    return
  endif
  let keyword = expand('<cword>')
  let kw_enc = iconv(keyword, &encoding, dict['encoding'])
  let kw_enc = s:encodeURIComponent2(kw_enc)
  let kw_enc = iconv(kw_enc, dict['encoding'], &encoding)
  let url = s:replace(dict['url'], '%keyword%', kw_enc)
  let cmd = s:replace(cmd, '%URL%', url)
  redraw | echo 'dicwin2: searching...'
  let html = system(cmd)
  redraw | echo 'dicwin2: parsing...'
  let result = call(dict['parser'], [html])
  if type(result) != type({}) ||
        \ !has_key(result, 'title') ||
        \ !has_key(result, 'description')
    echohl WarningMsg
    redraw | echo printf("dicwin2: '%s' is not found", keyword)
    echohl None
    return
  endif
  pclose
  silent! pedit +set\ noswapfile\ buftype=nofile dicwin2
  wincmd P
  let s = result['title'] . "\n" . result['description']
  " url . "\n\n" . 
  silent! put =s
  normal ggdd
  wincmd p
  redraw!
endfunction

function! s:char2hex(c)
  if a:c =~# '^[:cntrl:]$' | return '' | endif
  let r = ''
  for i in range(strlen(a:c))
    let r .= printf('%%%02X', char2nr(a:c[i]))
  endfor
  return r
endfunction

function! s:encodeURIComponent2(s)
  return substitute(a:s, '[^0-9A-Za-z-._~!''()*]',
        \ '\=s:char2hex(submatch(0))', 'g')
endfunction

function! s:encodeURI2(s)
  return substitute(a:s, '[^0-9A-Za-z-._~!''()*#$&+,/:;=?@]',
        \ '\=s:char2hex(submatch(0))', 'g')
endfunction

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