Home > Vim Hacks

Vim Hacks Archive

Hack #123: VimでSKK日本語入力環境を実現する

Emacsでは様々な日本語入力のプラグインがあります。
Vimでもkeymapなどの設定をいじれば可能ですが、
あまりkeymapファイルをいじった人は少ないでしょう。
そこでVimプラグインで日本語入力を実現しようと開発された、skk.vimを紹介します。

概要

skk.vimはYagi Noriaki氏によって作られたVimで日本語入力を実現するプラグインで、以下のような特徴を持ちます。

  • SKKによる日本語入力を実現する
  • so skk.vimのみで動作する (Windows環境では辞書ファイルのパスが異なるため、別途設定を.vimrcに書く必要があります)
  • 軽い

SKKについて簡単に説明すると、形態素解析(文節の区切り)をSKK自身が行わず、
使用者自身が行うように矯正することで、実装が簡単であり、
かつ慣れれば高速で正確なかな漢字変換が行えるInput Methodです。

形態素解析を行わないことで軽い動作を実現し、 かつ自分の意図した変換結果を得られやすいとされています。
詳しくは各自Wikipediaを見るなりググったりしてください。

導入

SKKの辞書を用意する

ここからダウンロードするか、Linuxだったら

skkdic skkdic-extra

のようなパッケージが用意されていればそれをインストールしてください。

skk.vim インストール

普通のVimプラグインと違いはありません。
www.vim.orgから最新版をダウンロードして解凍してVimのディレクトリにインストールするだけです。

メリット

  • sshのリモートホスト先で日本語入力ができない時もVim上で日本語を入力できる
  • 軽い
  • 自分の意図にあった変換をしてくれる(かもしれない)

デメリット

  • 他のInput Methodには戻れない
  • SKK信者でVim信者Vimmerは母数的に考えて少ない(要出典)

・・・はネタとして

  • Vimでしか使えない

MacならAquaSKK、Windowsならskkime、Linuxならuim-skkやscim-skkなど、
それぞれのOSのIMを変えてしまえばどのアプリケーションでも使えます。 ただ上で言った「sshのリモートホスト先で日本語入力ができない時もVim上で日本語を入力できる」は大きなメリットだと思います。
緊急時に備えてインストールしておくのもアリかもしれません。

  • SKKは人によっては慣れが必要かもしれない

SKKでもmecab-skkservというものを使えば普通の日本語入力と似た環境を手に入れられますが、残念ながらskk.vimはskkserv非対応です。

これまでのあらすじ

しかしskk.vimには一つ問題があり、 それはもう作者によるメンテナンスが行われていないことです。
skk.vimにはファンも多く、インターネット上でも野良パッチが散見されますが、
それらは本家にマージされることはなく www.vim.orgでの最終更新日は2006年10月15日で止まっています。

そんな中私はこの状況をなんとかしたいといった気持ちはまったくなく、
ふとした思いつきからGithubにskk.vimの改良版を登録し、それが一部の人の反響を受けます。(要出典)
気を良くした私は、勢いで作者である八木氏とメールで連絡をし、
ライセンスの確認と、メンテナンスの意志があるか、
また今後作者に無断で登録してしまったリポジトリに継続してコミットしていいかを尋ねました。
八木氏はこれに快く了承して、ライセンスは好きにしていいと仰ってくれました。

無事八木氏の了解が得られ、どんどんskk.vimのパッチをマージしていこうと考えたものの、
skk.vimがVimスクリプトの貧弱な時代に書かれたものだったため、互換性を維持するためのコードが散らばっていました。

ドキュメントはなんとか書いたものの、Vim6時代のコードを知らないために、変更をすることに怖気づいていたところ、
リポジトリのメンバーからもコードを一から書き直す必要があるとの声が高まってきます。
私はそれを喜んで賛成し、skk.vimのメンテナンスを続けることを約束しながらも、結局新しいskk.vimを作ることにしました。

skk7.vim (仮称)

新しいskk.vimは、今現在skk7.vimという仮称のもと開発が行われています。
それは今私のマシン上、完璧クローズドな環境で行われていて、
未だベータ版ですが、近々Githubに登録するつもりです。

しかしskk7.vimというのはあくまで仮称であって、正式名称ではありません。
未だ続々と希望が寄せられているものの、そもそも多数決で決めるのか、独断で決めるのか、それすらも決めていませんでした。

というわけで

  • 新しい名前希望!
    • 決め方は決めるつもり
  • skk.vimかskk7.vimの開発に興味があるなら、私かリポジトリのメンバーになんらかのコンタクトをとってくれれば、すぐにメンバーに招待したい
    • GithubのIDを取得している必要があります
    • 参加表明して何もしなくてもOKな気楽っぷり
    • 気が向いた時に機能追加なり修正を新しいブランチにプッシュしてもらえれば適当に拾ってマージします
  • その他要望等あれば下の連絡先からどうぞ

連絡先

参考リンク

tyru

Hack #122: 行末までヤンクする

問題

カーソル位置から行末まで削除するにはDします。 カーソル位置から行末まで編集する(削除して挿入モードに入る)にはCします。

さて、カーソル位置から行末までヤンクするにはどうすればいいでしょうか。 答えはYではなく、y$です。

VimのYの挙動は、「カーソル行をヤンク」です。カーソル位置より左もまとめてヤンクされてしまいます。 オリジナルのviとの互換性のためか、このような仕様になっているみたいです。 オリジナルのviがなぜこのような仕様になっているかは不明です。

解決

~/.vimrcに以下を記述します。

nnoremap Y y$

これで、Yの挙動がDCと同様に、「カーソル位置から行末までヤンクする」になります。 一貫性がとれる上に、$というとても人間には入力不可能な記号の入力を省略することができ、開発効率の大幅な向上が期待されます。

解説

なお、ヘルプ :h Y を引くと以下のように説明されています。

["x]Y yank [count] lines [into register x] (synonym for yy, |linewise|). If you like "Y" to work from the cursor to the end of line (which is more logical, but not Vi-compatible) use ":map Y y$".

しかし、このやりかたは2点留意事項があります。

  • ヘルプに書いている方法ですと、y$の挙動が上書きされているときに、上書きされた側の挙動で今回定義したYが実行されます。多くの場合それは意図した挙動ではないため、本Hackではmapではなくnoremapとしました
  • ビジュアルモードなどでは今回のYは関係ないため、mapではなくnmapがより好ましいです

組み合わせて、本Hackではnnoremapとしました。

ujihisa

Hack #121: バッファ名をペーストする

問題

ときおりバッファ名をペーストしたいことがあります。 短い名前なら手動で入力しても構いませんし、 ファイルに対応するバッファならばファイル名補完で多少の手間を省けますが、 面倒臭いことには変わりありません。 直接バッファ名をペーストできないでしょうか。

解決方法

Normal modeの場合は以下のコマンドを実行します:

"%p

Insert modeやCommand-line modeの場合は以下のコマンドを入力します:

<C-r>%

上記のコマンドはカレントバッファ名をペーストします。 %の代わりに#を用いると 代替バッファ の名前をペーストします。

解説

上記のコマンドは実際には指定されたレジスタの内容をペーストするコマンドです。 Vimには特殊なレジスタとしてカレントバッファ名や代替バッファ名を表すものがあり、 この二つを組み合わせることで上記のようにバッファ名のペーストができます。

Vimには他にも様々な 特殊レジスタ があるので、一度確認しておくとより便利に使うことができるでしょう。

参考資料

kana

Hack #120: gVim でウィンドウの位置とサイズを記憶する

GUI アプリケーションではよく終了時にウィンドウの位置とサイズを記憶し、次回起動時に復元するものを見かけます。Vim でも設定次第で同様のことが可能です。

設定

.gvimrc に以下のように書きます。

let g:save_window_file = expand('~/.vimwinpos')
augroup SaveWindow
  autocmd!
  autocmd VimLeavePre * call s:save_window()
  function! s:save_window()
    let options = [
      \ 'set columns=' . &columns,
      \ 'set lines=' . &lines,
      \ 'winpos ' . getwinposx() . ' ' . getwinposy(),
      \ ]
    call writefile(options, g:save_window_file)
  endfunction
augroup END

if filereadable(g:save_window_file)
  execute 'source' g:save_window_file
endif

解説

g:save_window_file

この変数で指定するファイルにウィンドウの位置やサイズを保存します。expand() は ~ を $HOME に展開するのに必要で、その必要がない場合はなくても問題ありません。

設定の書き出し

augroup SaveWindow 〜 augroup END で、Vim の終了時に発生するイベントを登録しています。

ここでは Vim の終了時に s:save_window() と言う関数を呼ぶようにしています。そしてこの関数のなかで、g:save_window_file にウィンドウの位置とサイズの情報を Vim スクリプトの形式で書き出しています。

設定の読み出し

最後の if でウィンドウ情報ファイルが存在するかをチェックし、存在した場合はそのファイルを :source で読み込みます。情報ファイルは Vim スクリプトとして書き出されているので、:source するだけで位置とサイズが復元されます。

thinca

Hack #119: neocomplcache Hacks(2)  オムニ補完

二回目の今回はオムニ補完です。AutoComplPopでも自動呼び出しが可能ですが、neocomplcacheでは、それに改良を加え、設定しやすくなっています。

オムニ補完とは

オムニ補完とは、Vim組み込みで用意されている補完とは違い、文脈を解析して行う補完です。関数を'omnifunc'に設定し、<C-x><C-o>のキーシーケンスを入力することで呼び出されます。標準でもいくつかの言語のオムニ補完関数が用意されていますが、ユーザーが自分で定義することができます。

inoremap <expr><C-x><C-o> &filetype == 'vim' ? "\<C-x><C-v><C-p>" : neocomplcache#manual_omni_complete()

私はこのようにキーマッピングを設定し、Vim組み込みのオムニ補完を置き換えています。

拡張機能

neocomplcacheのオムニ補完には次のような拡張機能があります。

自動補完の文脈定義

g:NeoComplCache_OmniPatterns[filetype]を設定すれば、呼び出し条件をカスタマイズしたり、呼び出しを無効化することができます。

多数の言語に対応

AutoComplPopでは標準でPerl/Ruby/html/CSS/Pythoのオムニ補完が可能です。neocomplcacheではPerl以外の確認できたすべての言語に対応しています。キーワードパターンに追加するだけなので、新たな言語に対応させることが容易です。

補完スキップ

g:NeoComplCache_EnableSkipCompletionが1ならば(デフォルト)、候補の取得に時間がかかりすぎる場合、補完をスキップすることができます。

ワイルドカード

ほかの補完と同様、ワイルドカードによる絞り込みに対応しています。

エラーを出さない

特定のオムニ補完では、変な場所で呼び出すとエラーを出したりすることがあります。neocomplcacheではエラーをcatchしているので、neocomplcache内部にバグがない限り、オムニ補完中にエラーになることはありません。

補完環境の厳密な判定

PythonやRubyのオムニ補完は:python:rubyが正常に動作する環境でなければ動作しません。よって、内部で判定しています。

ファイル名補完やバッファ名補完との同時呼び出し

オムニ補完とほかの補完を同時に呼び出せないAutoComplPopとは違い、neocomplcacheのオムニ補完はほかの補完と統合されています。 よって、同時に候補を出すことができるので、さらに便利に使えます。 ただし、オムニ補完の開始パターンが先にマッチした場合、オムニ補完の候補のみが計算されて表示されます。 これはVim自体の仕様です。これを防ぐためには、一度補完のポップアップを閉じて、補完を再呼び出しするしかありません。

キーワードの収集

空文字列でオムニ補完を呼び出してキーワードを収集してキャッシュし、オムニ補完候補として利用することができます。

neocomplcacheからオムニ補完関数を呼び出すときの注意

neocomplcacheは大抵のオムニ補完関数に対応していますが、オムニ補完関数を内部で無理矢理呼んで変換するという動作を行っているので、呼び出す関数によっては補完がうまく働かないことがあります。現在、complete_add()関数を内部で呼んでいる場合には動作がおかしくなることがわかっています。これはオムニ補完関数側がcomplete_add()を呼ばないようにするしかありません。 他に、Rubyのオムニ補完は時々フリーズする現象があることが報告されています。 これはRubyのオムニ補完が外部インタフェースを内部で使用しているためだと思われます。 Vimの外部インタフェース機能は不安定なので、時々エラーをはいたりフリーズすることがあります。 無効にしたい場合は.vimrcで

if !exists('g:NeoComplCache_OmniPatterns')
let g:NeoComplCache_OmniPatterns = {}
endif
let g:NeoComplCache_OmniPatterns['ruby'] = ''

と設定すると、無効にできます。これでは不便なので、Rubyのオムニ補完を書き直してくれる人を現在募集中です。

Shougo

Hack #118: ホームディレクトリをラクに入力する

問題

Vimのコマンドラインでホームディレクトリを入力する機会は比較的多いものの、~/という文字列を見ただけで小指に疲労が走ってくるのは、ほとんどのVimユーザに共通するのではないでしょうか。 もしも入力しやすいキー、例えばバックスラッシュなどで一発で~/が入力できれば、どんなに素晴らしいことでしょうか。

解決

以下のコードを~/.vimrcに記述することで、コマンドラインモードでバックスラッシュで~/が入力できる上、~/が来て欲しくなさそうなところではそのままバックスラッシュが入力されます。

function! HomedirOrBackslash()
  if getcmdtype() == ':' && (getcmdline() =~# '^e ' || getcmdline() =~? '^r\?!' || getcmdline() =~? '^cd ')
    return '~/'
  else
    return '\'
  endif
endfunction
cnoremap <expr> <Bslash> HomedirOrBackslash()

この設定を有効にしたVimで:e \と打鍵すると、ただちに:e ~/に展開されます。 また、:s/\と打鍵した場合は、:s/\とそのままになります。(:s/~/のように展開されません)

発展

本Hackはcho45さんの.zshrcへのハックへのアナロジーで考案されました。 残念ながら現在cho45さんの最新版の.zshrcにはそのコードは存在していないようですが、 少し古いところに残っています。 著者の手元の.zshrcから引用すると、以下のようなコードでした。

expand-to-home-or-insert () {
  if [ "$LBUFFER" = "" -o "$LBUFFER[-1]" = " " ]; then
    LBUFFER+="~/"
  else
    zle self-insert
  fi
}
zle -N expand-to-home-or-insert
bindkey "\\"  expand-to-home-or-insert
ujihisa

Hack #117: 置換行為を繰り返す

問題

:substitute (:s)による置換処理は頻繁に使います。 バッファ全体を対象にする場合は:%s/foo/bar/gなどでできますし、 特定範囲のみを対象にする場合はVisual modeで選択しておいて :s/foo/bar/gでできます。

では飛び飛びの場所で置換を行なう場合はどうでしょうか。 例えばソースコード中の特定の関数3つに対して置換を行なうとしましょう。 この場合は3箇所それぞれを対象として置換を実行することになりますが、 毎回 :s/foo/bar/g のような長ったらしいコマンドを入力したくはありません。 <Up>/<Down> でコマンドの入力履歴を辿って実行してもいいのですが、 これらのキーは概して遠い位置にあるため押下が面倒ですし、 押し易いキーバインドを設定することも面倒です。 どうにかして最小の手数で置換行為を繰り返せないでしょうか。

解決方法

以下のコマンドを実行します:

:s

通常、:sには検索パターンと置換文字列を指定しますが、 それらを省略した場合は最後に実行された :sと同じ検索パターンと置換文字列で置換が行なわれます。

なお:sでは :s/foo/bar/gc などのフラグは無視されます。 フラグまで同一にする場合は:sの代わりに

:&&

を使います。

また1行だけ繰り返す場合には:sの代わりに

&

を使うこともできます。

参考資料

kana

Hack #116: 機能を割り当てるキーを探す際のヒント

Vim に新しくプラグインをインストールした際や、自分で便利な設定を書いた場合、それらの機能を素早く呼び出すために Key mapping を定義したいと思うでしょう。しかし、Vim では標準で多くの機能が各キーに割り当てられていて新しい機能を割り当てる場所が見つからないことがあります。本 hack ではそういった場合の手助けをします。

キーボードを眺める

キーボードを眺めて Vim における各キーの機能を思い出してください。思い出せないキーがあった場合、それはつまりあなたがそのキーの機能を使っていないということです。まずは :help でそのキーの機能を確認し、本当に必要ないと思えばそのキーには新しい便利な別の機能を割り当てられます。

プレフィックスキーを活用する

プレフィックスキーを使うことで、より多くの機能を割り当てることができます。ストローク数は 1 つ増えてしまいますが、キーボードのキーの数を考えるとこれは仕方がないでしょう。

以下にプレフィックスキーとして使えそうなキーを紹介します。

\

\ キーは標準の mapleader キーです。つまり、最初からプレフィックスキーとして使えるように空けられています。

<Space>

<Space> は非常に押し易い位置にあるにも関わらず、Normal mode ではカーソルを右に移動させるだけで、これは l と同じなので使われることは滅多にありません。これを使わない手はないでしょう。

m

m には標準でマークを付けると言う機能が割り当てられていますが、今は Visual mode もあるのでそれほど使われません。これをプレフィックスキーにしてしまうのも良いでしょう。

q

q はキーボードマクロの記録を開始するキーです。キーボードマクロは便利な機能なので潰すべきではありませんが、マクロとして記録できる場所は a から z まで 26 個もあります。そして、大抵はどこに記録したかなどは覚えていられないので、使い慣れた特定のキーを使うと思います。その場合、残りの使わないキーに対して機能を割り当てることができます。

また、再生用の @ キーも同様に使えるでしょう。

あまり使わないキーを退避させる

人によっては、たまにしか使わない、けれどたまには使うので使えないと困る、というキーがある場合があります。s f t などがその例です。 その場合、それらのキーをプレフィックス付きの場所に再マップすることでプレフィックスキーとして使えます。

nnoremap s <Nop>
nnoremap ss s
nnoremap sa func-a
nnoremap sb func-b
thinca

Hack#115: Vimのバージョンや拡張機能をチェックする

自分でプラグインを書く場合、プラグインが動作しているVimのバージョンやVimで有効になっている機能を確認したい場合があります。ここでは、そんなときに役立つ関数について解説します。

Vimのバージョンをチェックする方法

Vimのバージョンをチェックするには、v:version変数をチェックすればよいです。百の位がVimのメジャーバージョン、十の位と一の位がマイナーバージョンを表します。例えばVim 7.2で:echo v:versionすると、702が表示されます。720ではありません。Vimがバージョン7以上であることをチェックするには次のようにします。

if v:version < 700
    echoerr 'Does not work this version of Vim "' . v:version . '".'
    finish
endif

ちなみに、パッチレベルはhas('patch100')などでチェックします。詳しくは、:help has-patchを参照してください。

有効になっている拡張機能をチェックする方法

自分のVimがどのような拡張機能を持っているかは、:versionを実行するのが早いですが、 プラグインがチェックする場合には使えません。スクリプトでチェックするには、has()を用います。 たとえば、Windowsかどうかをチェックするには、

if has('win32') || has('win64')
    " Windowsの場合の処理
endif

です。GVimかどうかをチェックするには、has('gui_running')です。これはhas('gui')と間違えやすいので気をつけてください。has('gui')はGUI機能付きでコンパイルされているかどうかをチェックします。has('gui_running')でうまく条件を切り分ければ、.gvimrcを用いずにGVim用の設定を.vimrcだけで完結させることも可能です。 ただし、最初vimで起動して:guiでGUIになる場合は.vimrcのhas('gui_running')設定は読み込まれません。注意してください。(mattnさん情報)

使用上の注意

Vim6以下の場合はスクリプト機能が全然違うので、切り捨てても良いですが、Vim7以降の差異はそこまでありません。 本当にそのバージョンをチェックするべきなのかをよく考えましょう。 拡張機能も本当に必要なものだけを使うようにしましょう。

Shougo

Hack #114: Vimを再起動することなくロードパス$PATHを書き換える

Vimとそれ以外のソフトウェアを組み合わせて使うにあたって、:!:r!が非常に重要な役割を果たしています。 このとき、:!lsとすることで/bin/lsが呼ばれるのは、$PATH/binが含まれているためです。 $PATHはVimを起動したシェルから与えられます。シェルの$PATHを上書きしても、既に起動したVimの$PATHは変化しません。 Vimを起動したまま$PATHに新たなロードパスを追加するにはどうすればいいのでしょうか。

解決

let $PATH="/the/new/path:".$PATH

とします。

ただし、~は使えません。フルパスを指定する必要があります。

解説

let $PATH="/the/new/path:$PATH"

としたいところですが、$PATHは""の中で展開されません。また、

set path="/the/new/path,."

というのもありますが、これは:!用ではなく、gfなどのためです。詳しくは:h 'path'をご覧ください。

謝辞

本Hackはnb1839さんにlingrで教えていただいた情報を元に執筆しています。

ujihisa

ホーム > Vim Hacks

Search
Feeds
Links
  • 公式
  • 勉強会
  • 情報
  • コミュニティ
  • プラグイン
  • vimrc
  • Meta
    Etc
    Creative Commons License
    This blog is licensed under a Creative Commons License.

    Return to page top