はじめて公開するVimPlugin

Brogramming with Tom
はじめてVimPluginを公開してみました。今回は、VimScriptの書き方からVimPluginの公開までを分かりやすく解説します。

photo credit: ryanoshea via photopin cc


Vim Advent Calendar 2012 の238日目の記事です。昨日の記事は @manga_osyo さんの「Vim で前のカーソル位置に戻るプラグインをつくった - C++でゲームプログラミング」でした。


はじめて公開する Vim Plugin



cscroll.vim



cscroll.vimchrome-scrollの略です。このプラグインは、AppleScriptを使ってVim上で、Google-Chromeというブラウザを操作するものです。Macでしか起動しませんが、非常に単純な仕組みになっています。よって、以下、WindowsとLinux用の解説も行います。


できる操作は、非常に単純な 上スクロール下スクロールタブを閉じるができます。


インストール



NeoBundle "syui/cscroll.vim"



Vundleなどのプラグイン管理ツールを使わない場合は、以下のようにします。

mkdir -p ~/.vim/bundle/

cd ~/.vim/bundle/

git clone https://github.com/syui/cscroll.vim.git

cp cscroll.vim/plugin/cscroll.vim ~/.vim/plugin/



設定ファイル



当該プラグインでは、コマンドを用意しましたが、キーでも操作できるようにしてみましょう。

nnoremap <silent> <Leader>j :ChromeScrollDown<CR>
nnoremap <silent> <Leader>k :ChromeScrollUp<CR>
nnoremap <silent> <Leader>q :ChromeTabClose<CR>



それぞれの意味は、以下のようになっています。この部分を任意の値に書き換えることによって、様々な応用ができます。





連携



他のプラグインと連携することで、 cscroll.vimはますます便利になります。例えば、 submode.vimと連携してみましょう。このプラグインは、仮想モードの中でキーを設定できるプラグインです。仮想モードに入るキーやそこで使用するキーを指定します。


NeoBundle 'kana/vim-submode'



call submode#enter_with('cscroll', 'n', '', '<Leader>j', ':ChromeScrollDown<CR>')
call submode#enter_with('cscroll', 'n', '', '<Leader>k', ':ChromeScrollUp<CR>')
call submode#leave_with('cscroll', 'n', '', 'n')
call submode#map('cscroll', 'n', '', 'j', ':ChromeScrollDown<CR>')
call submode#map('cscroll', 'n', '', 'k', ':ChromeScrollUp<CR>')



これで、 <Leader>と以下のキーを連続で押すことで、 Google Chromeを操作しやすくなります。例えば、 <Leader> + jjjjjjと押すことで、下に連続してスクロールします。


キー 効果
j 下スクロール
k 上スクロール
q タブを閉じる
n 仮想モードを抜ける



さらに、 vimshell上で使うと、色々なコマンドを実行しながらブラウジングできるので、便利。

NeoBundle 'Shougo/vimshell.vim'






上記画像では、ブラウジングしたあとにURLとタイトルを取得し、 TweetVimを使って、URLとタイトルをツイートしています。


ちなみに、ウィンドウの透過は、私は、Terminalで一括制御していますが、Vimでも個別制御することは出来ます。


Vim Scriptの書き方



私は、まず外部ツールやコマンドを使用して、 Vim Scriptを書きました。そして、慣れてきたら、 Vim Scriptで書ける範囲を増やしていけたらな、と思っています。


例えば、私が書いたものは、以下のようになっています。

command! -bar ChromeScrollDown silent !osascript $HOME/.vim/bundle/cscroll.vim/plugin/chrome_scroll.scpt next



そして、それぞれが何を意味するのかは、以下の通りです。





ハイライトした部分を変更することで、色々と応用ができます。例えば、WindowsやLinuxでは、以下の様なものが作れます。これらをコマンドの定義と言います。


WindowsのコマンドプロンプトでVimを使う



" cmd window size
" http://koturn.hatenablog.com/entry/2013/07/06/151940
augroup MyAutoCmd
  autocmd!
augroup END

if has('win16') || has('win32') || has('win64')
  command! FullSize call s:full_size()

  if !has('gui_runnig')
    if has('vim_starting')
      let s:is_fullsize = 0
      let s:lines   = 0
      let s:columns = 0
      let s:x_pos   = ''
      let s:y_pos   = ''
    endif
    autocmd MyAutoCmd VimLeave *
          \   if s:is_fullsize
          \ |   exec 'winpos' . s:x_pos . s:y_pos
          \ | endif
    function! s:full_size()
      if s:is_fullsize
        exec 'winpos' . s:x_pos . s:y_pos
        let &lines   = s:lines
        let &columns = s:columns
        let s:is_fullsize = 0
      else
        let s:lines   = &lines
        let s:columns = &columns
        let s:wstrlst = split(s:get_winpos_strs(), ',')
        let s:x_pos   = s:wstrlst[0][2:]
        let s:y_pos   = s:wstrlst[1][2:]
        winpos -8 -8
        set lines=999 columns=999
        let s:is_fullsize = 1
      endif
    endfunction
    function! s:get_winpos_strs()
      let l:wstr = ''
      redir => l:wstr
      silent! winpos
      redir END
      let l:wstr = substitute(l:wstr, '[\r\n]', '', 'g')
      return l:wstr[17:]
    endfunction

  else
    if has('vim_starting')
      let s:is_fullsize = 0
    endif
    function! s:full_size()
      if s:is_fullsize
        simalt ~r | let s:is_fullsize = 0
      else
        simalt ~x | let s:is_fullsize = 1
      endif
    endfunction
  endif
  noremap  <silent> <F11>   :<C-u>FullSize<CR>
  noremap! <silent> <F11>   <Esc>:FullSize<CR>
  noremap  <silent> <M-F11> :<C-u>FullSize<CR>
  noremap! <silent> <M-F11> <Esc>:FullSize<CR>
endif


注目すべきポイントは、 command! FullSize call s:full_size()の部分と noremap <silent> <F11> :<C-u>FullSize<CR>のあたりです。前者は、コマンドを作り、後者は、コマンドにキーを設定しています。


Linux



次は、もっとわかり易い例です。Vimの:Firefoxコマンドで、 Firefoxを起動するプラグインです。Ubuntuで有効だと思います。

command! -bar Firefox silent !firefox


参考になる記事



Vimスクリプトの初心者がコマンドを定義してみた

突然のVimコマンドを作った


Vim Plugin を公開するまで



ここで、 Vim Pluginとは、 ~/.vim/plugin/などに置くと起動するプログラムを言います。このようなプログラムを公開するには、 GitHubというサービスを利用するのがオススメです。


このサービスは、 Gitというバージョン管理システムを基本に、人をつなげる目的で運用されているサービスだと私は認識しています。


ここで、バージョン管理システムとは、プログラムのそれぞれのバージョンを分かりやすく表示したり、場合によっては前のバージョンに戻ったりすることを簡単にできるようにするシステムです。例えば、プログラムというものは、アップデートしたり、バグ修正したりすることがよくあります。ここで、プログラムのアップデートや修正をバージョンと呼ぶことにします。このバージョンが増えていくと、手動では、管理が難しくなってくることがよくあります。よって、その困難を緩和し、バージョン管理を簡単、便利にするためにこのようなシステムが注目されます。


そして、GitHubを使うことで、バージョン管理しているプログラムの公開や当該プログラムへの提案や質問などが非常に簡単にできるようになりますので、とても便利です。


以下、ローカルリポジトリという自分のパソコンで作ったプログラムを公開手順するまでを一気に紹介します。


まず、個人ページにアクセスします。URLは、 https://github.com/usernameのようになります。例えば、私の場合は、 https://github.com/syuiです。そこで、 repositoriesページを開き、新しいリポジトリを作成します。リポジトリ名は後に使いますので、覚えておいてください。







mkdir sample

touch README.md

echo "hello github" >> README.md

cat README.md

git init

git add .

git commit -m "f commit"

git remote add origin git@github.com:username/sample

git remote -v

git push --set-upstream origin master


usernameの部分は自分のユーザー名を入れてください。


また、SSH鍵を設定していない場合は、設定しておきます。


初心者Git日記その五~GitHubにSSH公開鍵登録~


VimPluginの場合は、 pluginフォルダを用意しましょう。後、 README.mdは、説明書のようなもので Markdownで書けます。 docフォルダには、バージョンや内部情報を書き込んだテキストファイルを置くのが一般的みたいです。


以下、 README.mdのサンプルです。

#sample

hi, hello sample world.

##code

```
fu -a code

fu -c 1

echo "The date is: $(date +%D)"
```

#to-do

add sample2.

#japanese

こんにちは、サンプルの世界こんにちは。

SAMPLE2を追加。



to-doという項目で今後のプログラムの方向性、追加する機能などを書き込む人も多いです。


また、 japaneseという日本語訳を付ける人もいます。日本語から英語に訳す場合は、元の日本語を明示するのもわかりやすいと思います。 README.mdは、一番に分かりやすさを重視すべきと思います。私の場合は、長くても気にならないです。


あと、リポジトリの修正や新しいファイルの追加などは以下の手順で行います。

cd ~/sample

mkdir doc

touch doc/sample.txt

git add doc

git commit -m "s commit"

git push


Vim プラグインを github で公開するまで


コメント



コードは1つずつその役割や動作を見ていけば、あまり怖くないと思います。そして、わからない部分は、基本、飛ばします。皆様も是非、簡単なプラグインから作ってみてはどうでしょう。そして、既にあるプラグインのコードなどを読んでみるのも面白いかもしれません。


明日の担当は @thinca さんです。


追記


@manga_osyo さんから、以下の指摘をいただきました。ありがとうございます。


実行する chrome_scroll.scpt へのパスが絶対パスになっているんですけど、これだと環境によっては動作しないので相対パスのほうがよいかと

let s:current = expand("%:p:h")
command! -bar ChromeScrollDown silent execute "!osascript" s:current."/chrome_scroll.scpt next"


続きは、以下の記事になります。

Vimのコマンド定義で引数を使う方法