Home > Vim script

Vim script Archive

Hack #171: 編集している関数名を表示する

数あるエディタの中には現在編集中の関数名をステータスバーに表示させたりできるものがあります。
Vimでもできないでしょうか。

解決

current-func-info.vimを使います。
インストールしたあとstatuslineを次のように設定しましょう。

let &statusline = '[%{cfi#get_func_name()}()]'

こうすると現在編集中の関数名が

[func()]

のように表示されます。

cfi#get_func_name()は関数の外側にいる時は空文字を返すので
外側にいる時は「no function」と表示させたい場合は以下のようにします。

let &statusline = '%{cfi#get_func_name() == "" ? "no function" : "[" . cfi#get_func_name() . "()]"}'

これは少し面倒です。
cfi#format()というヘルパー関数を使うとこのように書けます。

let &statusline = '%{cfi#format("[%s()]", "no function")}'

current-func-infoは現在C, Perl, Ruby, Python, Vimスクリプトに対応しています。

ちなみに

statuslineは

set statusline=...

という風にセットすることもできますが

let &statusline = '...'

としたほうが空白を含む文字列をセットする時にエスケープする必要がなく便利です。

set statusline=this\ is\ my\ statusline

let &statusline = 'this is my statusline'

また

set statusline=%!...

のようにすることもできます。(:help 'statusline' 参照)

tyru

Hack #167: Vimスクリプトで無名関数やクロージャを使う方法

無名関数

function! s:foo()
    let foo = {}
    function foo.funcall() dict
        echo 'lambda'
    endfunction
    return foo
endfunction

call s:foo().funcall()

クロージャ

function! s:foo(num)
    let foo = {'i': a:num}
    function foo.funcall() dict
        let self.i += 1
        return self.i
    endfunction
    return foo
endfunction

echo s:foo(1).funcall()
let s:clos = s:foo(5)
" 6
echo s:clos.funcall()
" 7
echo s:clos.funcall()
" 8
echo s:clos.funcall()

説明

Vimスクリプトでは辞書型に関数をキーとして代入することができます。
その場合関数はほぼ無名のような存在になります。
また辞書型に格納した「dict」つきの関数からはその辞書を「self」という変数で参照できるので
辞書に関数内で使う変数などを辞書に保存しておけば関数内からその変数を参照できる、いわば疑似的なクロージャを実現することができます。

  1. 自分で変数を渡す必要がある
  2. obj.funcall() を自分で呼ぶ必要がある

などなど他言語と比べかなりプリミティブですが、これを駆使すればVimスクリプトでも現実的に無名関数やクロージャが扱えることがわかるでしょう。

またVimスクリプトでは辞書型を使ったプロトタイプ指向によりクラスなども扱うことができます。
そこまでしなくても辞書型を活用することでモジュールを分けられるのでいろんな活用方法があります。

tyru

Hack #163: VimをVimスクリプトインタプリタとして使う

viの前身であるedは、シェルスクリプトなどで文字列置き換えのために使うことができます。 (fileというファイルの中身を全行逆転させる例です)

ed - file <<EOS
g/^/m0
write
qall!
EOS

g/^/m0^にマッチする行に対して:m0という操作を適用するコマンドです。 :m0は分かりやすく書くと:move 0で、引数の行の下に現在の行を持っていくという動作をします。 ^はどの行にもマッチするので、:m0で全部の行に対して上からマッチした順に1行目に持っていきます。 操作が終わると全行が逆になっているというわけです。

また:write:qall!は全行逆になったバッファをfileに書き込むために必要です。

VimについてくるexというコマンドはedのVim版とも言えるものですのでもちろん上のようなことができます。 しかしデフォルトでは.vimrcやプラグインなども読み込んでしまうため、 「素のex」として使いたい場合は「-u NORC –noplugin」を指定する必要があります。 さらにVimmerとしてはVimの機能が使えず戸惑わないように「-N」も指定する必要があります。 よってexをVimスクリプトインタプリタとして使うには以下のように起動すればできそうです。

ex -N -u NORC --noplugin

冒頭の例のex版はこのようになります。

ex -N -u NORC --noplugin file <<EOS
g/^/m0
write
qall!
EOS

デフォルトでもこのようにVimスクリプトインタプリタのように使えなくはないのですが、以下のような難点があります。

  1. ファイルに対して実行するには末尾に必ず:write:qall!をつけなければならず面倒
  2. ファイルに対して実行する際に元のデータを壊してしまう
  3. いくつかの定型的なオプションを付けるのが面倒
  4. 標準入力からスクリプトを読み込むのでファイルを標準入力から読み込めない

解決

iexを使います。 これはVimスクリプトをPerl、Ruby、Pythonなどの多くのLLのインタプリタと同じ感覚でVimスクリプトを実行させることができる優れ物です。

$ echo 'g/^/m0' >reverse.vim
$ cat ~/.vimrc | iex reverse.vim -

# -eオプションで指定することも可能
$ cat ~/.vimrc | iex -e 'g/^/m0' -

$ iex    # /bin/exが開く

詳しくはiex -hを見てください。

いくつかのVimスクリプト

おまけとしていくつかのUNIXコマンドをVimスクリプトで実装します。

tac

$ cat tac.vim
g/^/m0
$ iex tac.vim file

sort

$ cat sort.vim
sort
$ iex sort.vim file

sort -u (sort | uniq)

$ cat uniq.vim
sort u
$ iex uniq.vim file

grep

$ cat grep.vim
edit `=ARGS[1]`
execute 'v/' . ARGS[2] . '/d'
$ iex -s grep.vim ~/.vimrc vim

("vim"のみを含んだ行が表示される)

また-eオプションを使ったやり方を示すと

$ iex -s -e 'edit `=ARGS[1]' -e 'execute "v/" . ARGS[2] . "/d"' ~/.vimrc vim

のようになります。
これは一般のLLインタプリタと同じようにワンライナーのようなものを書くのに適しています。

また-sを与えることで引数の扱いを変えています。
-sを与えると中身を読み込まずにg:ARGSというListに代入するだけにします。
その他細かい違いなどはiex -hを見てください。

tyru

Hack #144: 分かりやすく副作用のないKey-mappingsを定義する

Hack #59: 分かりやすいKey-mappingsを定義するの方法だとグローバルなマッピング空間を使ってしまうのが玉に瑕です。
そのせいで、例えば

nnoremap [tag] <Nop>
nmap     t     [tag]

" ...

" tag jump
nnoremap [t    <C-]>

としている場合に[tと押しても[tag]がまだ候補にあるために
&timeout&timeoutlenなどの値によりますが)すぐには実行されずに
キー入力を一瞬待たされるようになります。

この場合は[tを[Tに変えるなどすれば問題は解決しますが、
こうした副作用を気にかけながらマッピングを定義するのは少々面倒です。
なんとかして副作用のないマッピングを定義できないでしょうか。

解決

マッピングを<SID>で定義します。

nnoremap <SID>[tag] <Nop>
nmap     t          <SID>[tag]

” …

” 重複する候補がないためすぐに実行される
nnoremap [t    <C-]>

<SID>を先頭につけることでスクリプトローカルなマッピングを定義することができます。

発展

これを使ってさらに.vimrcを見通しをよくすることもできます。

nnoremap <SID>[yank-$] y$
nnoremap <SID>[register-+] "+
nnoremap <SID>[register-*] "*

nmap Y  <SID>[yank-$]
nmap ;Y <SID>[register-+]<SID>[yank-$]
nmap ,Y <SID>[register-*]<SID>[yank-$]

複雑なマッピングを定義する時は<SID>マッピングを使うことで
見通しがよく副作用のないマッピングを定義することができます。

tyru

Hack #126: クリップボードを利用する

問題1

ふつうのテキストエディタであれば クリップボードにあるテキストがペーストされ、 コピーしたテキストはクリップボードに保存されます。

しかしVimではコピー/ペーストされるテキストは レジスタと呼ばれるVim内部の領域から読み書きされるため、 そのようにはなっていません。

クリップボードに対してコピー/ペーストを行なうにはどうすればよいのでしょうか。

解決方法1

Vimには クリップボードを表す仮想的なレジスタ"*があるため、 コピー/ペーストする際にそのレジスタを使用するよう指定します。 例えばクリップボードへ1行分のテキストをコピーする場合は 以下のコマンドを入力します:

"*Y

クリップボードからテキストをペーストする場合は 以下のコマンドを入力します:

"*p

問題2

Vimからクリップボードにアクセスする方法は分かりました。 しかし毎回"*を指定しなければならず、入力が面倒です。 Vim内でテキストのコピー/ペーストを行なう場合に、 何も指定しなくても自動的にクリップボードを利用するようにできないでしょうか。

解決方法2

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

:set clipboard=unnamed

この設定を行なうと、 特にレジスタを指定せずにコピー/ペーストを行なった場合は クリップボードを利用するようになります。

また、xtermなどのX Window System下のアプリケーションでは 選択されたテキストが自動的にクリップボードへコピーされます。 VimのVisual modeでも同様の挙動にしたい場合は以下のコマンドを実行します。

:set clipboard=autoselect

もし両方の挙動が必要な場合は以下のように値をコンマ(,)区切りで指定します:

:set clipboard=unnamed,autoselect

問題3

基本的にGUI版のVimでしかクリップボードに関する機能は利用できません。 つまり、諸事情で端末エミュレータ内でVimを利用している場合は クリップボード関連の機能は使えません。

幸いなことに、 一部の環境ではクリップボードにアクセスするためのコマンドがあります。 例えばMac OS Xの場合はpbcopy/pbpasteでクリップボードの読み書きができるため、 :read !pbpasteなどとすればクリップボードの内容を取り込むことが できます。

しかしこのようなコマンドは入力が煩雑ですし、 何よりd/p/yのような Vim本来の操作と比べると不便です。 どうにかして"*と同様の操作性を実現できないでしょうか。

解決方法3

fakeclipを使います。 このプラグインをインストールすると Cygwin、Mac OS X、X Window Systemの非GUI版Vimでも "*Y"*pなどの操作ができるようになります (バージョン0.2.6現在)。

解説

Q. なぜ"*Yのようなまどろっこしい操作になっているのですか?

A. 祖先のviが生まれた頃にクリップボードなんてものはなかったからです。

Q. なぜ:set clipboard=unnamedがデフォルトでないのですか?

A. Vimのデフォルト設定は可能な限りviライクだからです。 そして祖先のviが生まれた頃にクリップボードなんてものはなかったからです。

参考資料

kana

Hack #100: vimrcにパスワード等を記述しなくてもよくする

問題

blogger.vim などの Plugin を利用する場合、 .vimrc にパスワード等の設定を記述する必要があります。 GitHubVimrcbox に .vimrc を公開している場合、そのままでは利用することができません。

解決

pitconfig.vim もしくは rbpit.vim を利用することで .vimrc に直接記述することなくパスワード等を設定することが可能です。

準備

pitconfig.vim を利用する場合は Perl インターフェイス付きの、 rbpit.vim を利用する場合は Ruby インターフェイス付きの Vim を準備してください。手元の Vim がこれらのインターフェイス付きでない場合は、ソースからコンパイルする必要があります。コンパイル方法については本 Hack の範囲を超えるので省略します。

また pitconfig.vim なら Config::Pit を CPAN から、 rbpit.vim なら pit を Rubygems からインストールします。

Plugin のインストール

pitconfig.vim または rbpit.vim を Plugin Directory へコピーしてください。 Plugin Directory については :h add-global-plugin を参照してください。

pitconfig.vim と rbpit.vim の違いは Perl インターフェイスを利用するか Ruby インターフェイスを利用するかの違いのみで、動作は同一です。1

設定

設定は Config::Pit の ppit コマンドや pit の pit コマンドから設定することが可能です。デフォルトのプロファイル名は vimrc ですが、変更することも可能です。

 pit set vimrc 

設定はYAMLとして記述します。例として blogger.vim の設定方法を記述します。

---
blogger_blogid = 7772225564702673313
blogger_email = blogger.vim@gmail.com
blogger_pass = bloggervimvim

また、 Vim の Command Mode から以下の要領で設定を行うこともできます。例として blogger.vim の設定方法を記述します。

:let g:blogger_blogid = 7772225564702673313
:let g:blogger_email = "blogger.vim@gmail.com"
:let g:blogger_pass = "bloggervimvim"
:PitAdd g:blogger_blogid g:blogger_email g:blogger_pass
:PitSave

デフォルトプロファイル名の設定

デフォルトでのプロファイル名は vimrc になっていますが、 g:pitconfig_default でデフォルトのプロファイル名を変更することが可能です。

コマンド

:PitLoad (プロファイル名)

プロファイル名に保存された設定をロードします。

:PitReload

デフォルトプロファイルをリロードします。

:PitAdd (変数名)

引数で指定した変数を :PitSave で保存する対象に設定します。変数名は複数指定可能です。

:PitDel (変数名)

引数で指定した変数を :PitSave で保存する対象から外します。変数名は複数指定可能です。

:PitSave (プロファイル名)

引数で指定したプロファイル名を使用して設定を保存します。引数なしで実行した場合はデフォルトプロファイルに保存します。

注意

MacVimを利用している場合、 pit は Mac OSX 標準の Rubygems (/usr/bin/gem) を利用してインストールする必要があります。 MacPorts を利用して ruby 及び rb-rubygems をインストールしていたとしても、使われるのは Mac OSX 標準の Rubygems になります。

from_kyushu

Hack #77: 縦に揃える

問題

Vimで表を記述するとき、整形のため自分でスペースを追加する必要があるシーンがあります。 また、yaccHaskellなど一部の言語では|などの記号を区切りとしてソースコードを縦に美しく揃える必要がある場合があります。

解決 — Align.vim

Align.vimをインストールし、さらに.vimrcに以下を記述します。

let g:Align_xstrlen=3

この設定は日本語など幅広文字に対応するためです。

以後、:[range]Align {separators}で指定した範囲を縦に整形することができます。

具体例

[range]を指定する方法は様々ありますが、例としてVisualモードで選択した範囲を対象として|という文字を区切り文字にして縦に整形してみましょう。

1

まずは範囲を選択。Vしてjjjと移動していき、

2

ここで:を打鍵すると:'<,'>まで勝手に入力されるので、続いてそのままAlign |と入力、

3

<Enter>で確定すると、

4

ばっちりできました。

議論

先ほど紹介した:[range]Align以外に様々なインタフェースが提供されています。詳しくは:h alignを参照ください。

なお、2009年9月24日現在の最新版のAlign.vim version 35では、:[range]Alignを実行するとカーソルが全く異なる場所に飛ばされてしまうというバグがあります。 しかも、<C-o>で元の場所に戻ることができません。 最もてっとりばやい解決方法は、uでAlign操作を取り消した上で元の位置に戻り、そのまま<C-r>で再実行することです。この場合なぜかカーソルは移動しません。

参考

ujihisa

Vimpressのご紹介

Vim-users.jpはWordPressを用いているのですが、このWordPressに投稿するvim scriptがありましたのでご紹介します。

Vimpress – Manage wordpress blog posts from Vim : vim online

インストール

vimpress.tar.gz を取得して展開したものを.vimディレクトリに保存してください。

また、このvim scriptはPythonを使用して書かれており、標準添付でないxmlrpclibというライブラリを使用しています。別途インストールを行ってください。

使用方法

.vim/plugin/blog.vimを開き、Settingsセクション内に以下の内容を入力して保存します。

  • blog_username: ユーザーID
  • blog_password: ユーザーパスワード
  • blog_url: http://vim-users.jp/xmlrpc.php

コマンドは以下になります。

  • 新規作成: :BlogNew
  • エントリ一覧: :BlogList
  • エントリ編集: :BlogOpen id
  • エントリ投稿: :BlogSend

ホーム > Vim script

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

    Return to page top