ホーム > タグ > lv2

lv2

Hack #130: :grepをより便利に利用する

問題

Hack #129: 複数のファイルから検索する では:grepについて紹介しました。 色々と便利なコマンドなのですが、頻繁に使っていると次のような不満が出てきます:

:grepの引数は基本的に

:grep {pattern} {file} ...

なのですが、同じファイル郡に対して異なるパターンで:grepする というケースは少なくありません。例えば

:grep rebase *.[ch]

で検索した後で

:grep rebase_cmd *.[ch]

と検索しなおすとしましょう。全てのコマンドを入力しなおすと面倒ですから、 通常は入力履歴を<Up>/<Down>で参照して以前入力した コマンドを修正する形になります。

ここで、入力履歴を手繰るまではよいのですが、 パターンを修正するところが問題です。 修正するためには<Left><Left><Left>...などとしてパターンの箇所まで カーソルを移動しなければならないのですが、これが面倒です。 特に{file} ...の指定が長くなると面倒さが倍増します。 どうにかして簡単に修正することはできないでしょうか。

解決方法

以下の内容をvimrcに追加します:

command! -complete=file -nargs=+ Grep  call s:grep([<f-args>])
function! s:grep(args)
  execute 'vimgrep' '/'.a:args[-1].'/' join(a:args[:-2])
endfunction

これにより:grepの代わりに 以下のような:Grepコマンドが使えるようになります:

:Grep {file} ... {pattern}

:grepでの煩雑さは最初の引数が{pattern}であることが 原因なので、その逆で最後の引数が{pattern}であるコマンドがあれば パターンの修正は<Up><C-w><C-w>...だけで済みます。

参考資料

kana

Hack #128: neocomplcache Hacks(3) キーワード補完

三回目の今回はneocomplcacheのキーワード補完と拡張プラグインを解説します。

キーワード補完とは

neocomplcacheのキーワード補完は、<C-n><C-p>で呼び出すことのできるVim組み込みのキーワード補完を模倣して設計されています。 言語ごとにキーワードパターンを定義して、一括して候補を検索できるのが最大の特徴です。 使用するキーワードパターンはg:NeoComplCache_KeywordPatternsで定義されています。

pluginとcomplfuncの違い

neocomplcacheには補完候補を収集するために、pluginとcomplfuncという二つの拡張プラグインが存在します。 それぞれ、autoload/neocomplcache/pluginautoload/neocomplcache/complfuncに配置します。 pluginはkeyword_complete.vimから一括して呼びだされる拡張プラグインで、単純なため実装が比較的簡単です。 complfuncは補完開始位置を拡張プラグイン側で計算しないといけません。 その代わり、補完開始位置は自由に決定できるので、ファイル名補完のような複雑な補完を実装できます。 初期のneocomplcacheでは、complfuncは一つのプラグインしか呼べないという制限がありました。 現在のバージョンでは、complfuncの候補も統合できるように改良されているため、そのような制限はありません。

標準添付のplugin

buffer_complete.vim

開いているバッファから補完候補を収集するプラグインです。バッファ内の単語を解析することで、使用頻度の学習も行います。

dictionary_complete.vim

g:NeoComplCache_DictionaryFileTypeListsから補完候補を収集するプラグインです。

include_complete.vim

バッファで開いているインクルードファイルから補完候補を収集するプラグインです。Vimにもインクルード補完はありますが、より拡張されています。

snippets_complete.vim

スニペットを補完するプラグインです。補完するだけではなく、単体でスニペット展開プラグインとしても動作します。

syntax_complete.vim

シンタックスファイルからキーワードを補完するプラグインです。Vim標準添付のsyntaxcomplete.vimよりも高機能であり、結果をキャッシュするので高速です。複雑なTeXのシンタックスも解析できます。

tags_complete.vim

タグファイルからキーワードを補完するプラグインです。

標準添付のcomplfunc

completefunc_complete.vim

補完関数を登録することで、自動呼び出しするプラグインです。neocomplcacheはcompletefuncを上書きしてしまうので、その対策に使えます。 手動補完として補完関数を個別に呼び出しすることもできます。

filename_complete.vim

ファイル名を補完するプラグインです。詳しい解説は、[Hack #119: neocomplcache Hacks(2) オムニ補完]を参照してください。

keyword_complete.vim

pluginから候補を収集し、キーワードを補完するプラグインです。

omni_complete.vim

オムニ補完を呼び出し、候補を収集するプラグインです。詳しい解説は、[Hack #119: neocomplcache Hacks(2) オムニ補完]を参照してください。

vim_complete.vim

Vimのオムニ補完機能を提供するプラグインです。Vim標準の<C-x><C-v>よりも機能が拡張されていて、ローカル変数や引数の補完も可能です。

Shougo

Hack #127: !を含む外部コマンドを実行する

問題

UNIXのechoコマンドで"hello!"と表示させる必要があるとします。Vimの:!を使えば出来そうな気がします。試してみましょう。

:!echo helloecho 'echo echo 1'
[No write since last change]
helloecho echo echo 1

なにやら狂ったような返答がきました。これは一体…。

※ 実行結果は人によって異なります。

解決

次のようにして!をエスケープします。

:!echo hello\!
[No write since last change]
hello!

次のようにしても、エスケープされませんのでご注意ください。

:!’echo hello!’

解説

ヘルプ:h :!によると、:!の中での!は前回実行した:!の引数になるそうです。 迷惑でしかない恐ろしい仕様です。('cpoptions'に依存するようです)

プラギンを作るときにハマる仕様です。:!を使うときによくわからない挙動があれば、まずは!のエスケープ漏れがないか確認してみましょう。

ujihisa

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 #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 #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 #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

Hack #113: grex – 特定パターンにマッチする行をまとめて取り扱う

問題

Vimで大量のデータを取り扱う場合、 特にCSVなどの1レコード1行の形式のデータを取り扱うとき、 特定の条件にマッチする行を抽出するなど、 まとめて編集したいことがしばしばあります。

例えばバッファの内容が以下のようになっていたとします:

Name      Creator            First release Cost License          Open source
Diakonos  Pistos             2004          Free MIT              Yes
GNU Emacs Richard Stallman   1984          Free GPL              Yes
JED       John E. Davis      1992          Free GPL              Yes
Metapad   Alexander Davidson 1999          Free GPL              Yes
Notepad   Microsoft          1985          -    Proprietary      No
RText     Fifesoft           2003          Free GPL              Yes
SciTE     Neil Hodgson       1999          Free HPND             Yes
Vim       Bram Moolenaar     1991          Free GPL - compatible Yes
Yi        Don Stewart        2005          Free GPL              Yes

この中から 「19XX年にリリースされたエディタ(に対応する行)を削除する」 としましょう。 これは:globalを利用して行うことができます (:g/\<19\d\d>/d)。

では 「19XX年にリリースされたエディタ(に対応する行)をヤンクする」 としたらどうでしょうか。 すぐに思いつくのは:g/\<19\d\d>/yですが、 これはマッチする行で毎回ヤンクを行うため、 レジスタに残るのは最後にマッチした行のテキストだけになります。 つまり、ヤンクしたいテキストは以下の通りなのですが、

GNU Emacs Richard Stallman   1984          Free GPL              Yes
JED       John E. Davis      1992          Free GPL              Yes
Metapad   Alexander Davidson 1999          Free GPL              Yes
Notepad   Microsoft          1985          -    Proprietary      No
SciTE     Neil Hodgson       1999          Free HPND             Yes
Vim       Bram Moolenaar     1991          Free GPL - compatible Yes

実際にヤンクされるのは以下の1行だけになります。

Vim       Bram Moolenaar     1991          Free GPL - compatible Yes

この観点で考えると、最初の「削除」についても同様のことが言えます。 つまり、削除されたテキストを別の箇所にペーストした場合、 ペーストされるのは最後にマッチした行のテキストだけになります。

上記のように、特定パターンにマッチする行をまとめて削除/ヤンクして ペーストするにはどうすればよいでしょうか。

解決方法

ベタな解決方法としては、 削除/ヤンクされるテキストをレジスタに上書きするのではなく、 レジスタに追加するようにします。 これには"A-"Zなどの大文字のレジスタを使います。

例えば:g/{pattern}/y Aとすると、 "aレジスタにマッチする各行のテキストが追記されるので、 "ap (操作直後であればpだけ)で 各行のテキストを一度にペーストできます。

ところが既に"aに何か別のテキストが入っていた場合、 それに対してテキストが追加されていくため、 実際には:let @a = ''などとして 操作前にレジスタの内容を空にする必要があります。 これは結構面倒です。

幸いなことに、上記のような操作パターンをまとめたコマンドを提供する grex というプラグインがありますので、これを使うと簡単に行うことができます。

例えば特定パターンにマッチする行をまとめて削除する場合、 /\<19\d\d>などとしてマッチするかどうかを確認した後、 :Gredで行うことができます。 ヤンクであれば:Greyで行うことができます。

なお、各コマンドは:g/{pattern}/[cmd]と 同様の形式では実行できません。 これは通常の操作では 検索パターンを含むコマンドを一度に入力して実行することはなく、 ('incsearch'および'hlsearch'を有効にした上で)/{pattern}により 期待通りの検索パターンができたかどうかをインタラクティブに確認してから 実際のコマンドを入力・実行することがほとんどだからです。

参考資料

kana

Hack #112: 場所ごとに設定を用意する

Vim はファイルの種類によって独自の設定を自動的に読み込むことができます。しかしそれとは別に、ファイルの置いてある場所に応じて何かしら設定を行ないたい場合もあるでしょう。そのための方法を紹介します。

設定

以下の記述を vimrc ファイルに追記します。これは、ファイルを開いた際に、開いたファイルとその上位階層にある設定ファイルを探してそれを読み込むための設定です。 ここでは設定ファイルとして .vimrc.local と言うファイル名を使っていますが、ここは何でも構いません。ワイルドカードも使用可能です。

" Load settings for eacy location.
augroup vimrc-local
  autocmd!
  autocmd BufNewFile,BufReadPost * call s:vimrc_local(expand('<afile>:p:h'))
augroup END

function! s:vimrc_local(loc)
  let files = findfile('.vimrc.local', escape(a:loc, ' ') . ';', -1)
  for i in reverse(filter(files, 'filereadable(v:val)'))
    source `=i`
  endfor
endfunction

使用例

設定ファイルには、例えば以下のようなことを書いておきます。

lcd <sfile>:h

この例ではカレントディレクトリを設定ファイルがある階層に移動しています。これによってこの設定ファイルが置いてあるより下の階層のファイルのカレントディレクトリが統一できます。

他にもプロジェクト用にインデントの設定を変更したり、バッファローカルな Key mapping を定義したり、プラグインの設定用にバッファローカルな変数を定義したりと、応用範囲はかなり広いです。 また、この例の設定では複数の設定ファイルが見つかった場合ファイルシステムのルートに近いファイルから順に読み込むので、より深い階層で設定を上書きする、と言ったこともできます。

thinca

Home > Tags > lv2

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

    Return to page top