ホーム > タグ > lv3
lv3
Hack #169: neocomplcacheを拡張する 後編
- 2010-08-23 (月)
- Vim Hacks
前編からかなり間が空いてしまいましたが、ここではneocomplcacheのプラグインの記述方法を解説します。neocomplcache Ver.5.1ではプラグインの構成がかなり変化したので、この記事を参考にしてください。
プラグインの仕様
プラグインはautoload/neocomplcache/sourcesにインストールしたものが自動的に読み込まれます。 プラグインには、neocomplcache#sources#プラグイン名#define()が絶対必要です。 これはneocomplcacheが初期化するときに呼ばれ、neocomplcacheにディクショナリ変数を渡します。 ここではディクショナリ変数に必要な要素について説明をします。
name
プラグインの名前です。
kind
プラグインの種類を現します。plugin, ftplugin, complfuncの三種類があります。これらの違いについては後述します。
filetypes
ftpluginにのみ存在します。どのファイルタイプで補完するかを表すディクショナリ変数です。
initialize()
プラグインの初期化時に呼ばれます。コマンドの登録等を行います。ftpluginの場合、これが呼ばれるのはfiletypesに対応するバッファで補完されたときです。
finalize()
neocomplcacheの無効化されるときに呼ばれます。ここで不要になったコマンドやautocmdを削除します。
get_keyword_list(cur_keyword_str)
pluginにのみ存在します。a:cur_keyword_strにマッチするリストを返すために呼ばれる関数です。get_keyword_list()が返す補完リストは、特定のキーを含むディクショナリのリストとなっています。詳しくは「補完リストの仕様」の項を参照してください。
get_keyword_pos(cur_text)
ftpluginとcomplfuncに存在します。cur_textにマッチする補完位置を返します。
get_complete_words(cur_keyword_pos, cur_keyword_str)
ftpluginとcomplfuncに存在します。a:cur_keyword_strにマッチするリストを返すために呼ばれます。get_complete_words()が返す補完リストは、特定のキーを含むディクショナリのリストとなっています。詳しくは「補完リストの仕様」の項を参照してください。
補完リストの仕様
get_keyword_list()やget_complete_words()が返す補完リストは、特定のキーを含むディクショナリのリストとなっています。一部のキー以外はVim標準の補完で使用するものと同じです。
word, abbr, menu, info, icase, dup
Vim標準の補完で使用するものと同じです。word以外は省略することができます。詳しい解説は、[Hack #14: ]Insert mode補完 自作編を参照してください。 menuはどのプラグインの候補で補完しているかを[B]のような記号で表す習慣になっています。ftpluginは[vim]や[ghc]のように、長めの文字列を使います。
プラグイン用ヘルパ関数
autoload/neocomplcache.vimには、プラグインから呼び出せるようにヘルパ関数が実装されています。ここでは、よく使われる関数について解説します。
neocomplcache#keyword_filter(list, cur_keyword_str)
get_keyword_list()で使用できる、単純なフィルターです。a:listの中から、a:cur_keyword_strにマッチするリストを返します。filter()とは違って、listは変更されるとは限りません。
neocomplcache#unpack_dictionary(dict)
リストの辞書をリスト化して返します。
neocomplcache#unpack_dictionary_dictionary(dict)
辞書の辞書をリスト化して返します。
neocomplcache#keyword_escape(cur_keyword_str)
a:cur_keyword_strをマッチングに使えるようにエスケープします。
neocomplcache#get_cur_text()
現在のカーソル文字列を取得します。
neocomplcache#get_completion_length(plugin_name)
plugin_nameの自動補完する文字列長を返します。
neocomplcache#set_completion_length(plugin_name)
plugin_nameの自動補完する文字列長を設定します。ただし、これはプラグイン側で初期値を設定するためのもので、ユーザーが補完文字列長を設定している場合、そちらが優先されます。
neocomplcache#get_keyword_pattern_end(filetype)
文字列の最後にマッチするfiletypeのキーワードパターンを返します。filetypeは省略可能で、省略すると現在のバッファのfiletypeを参照します。
neocomplcache#get_keyword_pattern(filetype)
文字列にマッチするfiletypeのキーワードパターンを返します。filetypeは省略可能で、省略すると現在のバッファのfiletypeを参照します。
neocomplcache#is_auto_complete()
自動補完の時に1を返します。
neocomplcache#print_caching(string)
キャッシュ時のメッセージを表示します。
neocomplcache#print_error(string)
エラーメッセージを表示します。
キャッシュ用ヘルパ関数
autoload/neocomplcache/cache.vimには、プラグインから呼び出せるキャッシュのヘルパ関数が含まれます。
量が多いので、ここでは詳しく説明することは避けますが、うまく利用すると簡単にキャッシュを使ったプラグインを記述できます。
ちなみに、neocomplcache Ver.4以降では、ほとんどのプラグインがキャッシュ用ヘルパ関数を使うように書き直されています。
プラグインのサンプル
neocomplcacheに標準添付のプラグインを参考にしても良いのですが、機能が複雑化しているため、プラグイン作りの勉強のために見るのは大変です。 eagletmtさんが作成したghc_completeはfiletype pluginでほどよい長さなので、勉強に最適でしょう。
plugin, ftplugin, complfuncの違い
neocomplcache Ver.3.00より、complfuncが実装され、より自由度の高い補完が実装できるようになりました。 pluginとcomplfuncの違いは、pluginはカーソル前のキーワードから補完しますが、complfuncは独自に補完位置を決定できるというところです。 ftpluginとはneocomplcacheのオムニ補完です。 基本的な仕様はcomplfuncと同じです。ただし、必要な時にのみ初期化や呼び出しされるというところが違います。
Shougo- Comments: 0
- Trackbacks: 0
Hack #167: Vimスクリプトで無名関数やクロージャを使う方法
- 2010-08-13 (金)
- Vim Hacks | Vim script | その他
無名関数
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」という変数で参照できるので
辞書に関数内で使う変数などを辞書に保存しておけば関数内からその変数を参照できる、いわば疑似的なクロージャを実現することができます。
- 自分で変数を渡す必要がある
- obj.funcall() を自分で呼ぶ必要がある
などなど他言語と比べかなりプリミティブですが、これを駆使すればVimスクリプトでも現実的に無名関数やクロージャが扱えることがわかるでしょう。
またVimスクリプトでは辞書型を使ったプロトタイプ指向によりクラスなども扱うことができます。
そこまでしなくても辞書型を活用することでモジュールを分けられるのでいろんな活用方法があります。
- Comments: 0
- Trackbacks: 0
Hack #144: 分かりやすく副作用のないKey-mappingsを定義する
- 2010-05-04 (火)
- Vim Hacks | Vim script
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>マッピングを使うことで
見通しがよく副作用のないマッピングを定義することができます。
- Comments: 3
- Trackbacks: 0
Hack #142: Vimでシェルを起動する
- 2010-04-26 (月)
- Vim Hacks
VimがEmacsと比較して劣っているのは、コマンドの非同期実行だけではなく、シェルとの連携も挙げられます。ここでは現状のシェル呼び出しの問題点とEmacsとの比較、その解決方法について議論を行います。
:shellの欠点
Vimに搭載されている:shellコマンドは、一時的にシェルを実行できます。しかし当然使用するシェルの設定に左右される上、実行している間はVimが止まってしまいます。
この状態ではコマンドの出力もバッファにとれないですし、VimScriptとの連携もできません。
さらにLinux上のGVimではエスケープシーケンスを解釈しない上、WindowsのGVimでは邪魔なDOS窓が一瞬開くという問題もあります。
根本的な問題として、WindowsのシェルであるCMD.exeは貧弱なので、使う気になれません。
かといって、Windowsの場合は代わりとなるシェルも選択肢が少ないです。
screenの欠点
:shellの代わりに、GNU screenやそれをforkしたtscreen、GNU screenの後継であるtmuxを用いるという解決策もあります。 しかしこれらのソフトウェアは端末を要求するため、当然Windows環境やGVimでは動作しません。 さらにscreen上で起動しているプログラムではVimのキーバインドを使えない、Vimとのデータのやりとりが大変、などの問題点があります。
Vim-Shellパッチについて
Vim-Shellパッチとは、Vimに外部プロセスを実行させる機能を付け加える巨大パッチです。 エスケープシーケンスもきちんと解釈するので、優れたシェル環境なのですが、 パッチは本家に取り込まれることがなく、しかもVim 7.2には対応していません。 Windows上では使えず、GVimでも使えないなど、欠点も多いです。
そのほかのプラグインについて
そのほかにもシェルを模倣するプラグインはありますが、どれも提供される機能に難があったり、 Windows環境やGVimでは使えないものばかりです。
Emacsとの比較
対するEmacsはどうでしょう。Emacsでは、標準的に搭載されているshell-modeを用いてシェルを実行できます。
起動が遅いですが、さらに高機能なeshell-modeを用いて100% Emacs Lispなシェルを使うこともできます。
eshell-modeは端末機能としては不完全なので、端末がほしいだけなら、ansi-termを用いると良いでしょう。
この優れたシェル環境を得るためだけにEmacsへと移行した人々も多いのではないかと思います。
最近では、ansi-termを改良したmulti-termというものが人気らしいです。
vimshellについて
Emacsへの対抗馬になりうるのが、私が開発しているvimshellです。 完全な端末機能を目指すのではなく、純粋な対話シェルとしてeshellを目標にしています。 自動補完プラグインであるneocomplcacheと連携させることで、自動補完のできるシェル環境になります。 vimprocと連携させれば非同期実行も可能、対話プログラムを起動できる、と開発途中の現在でもかなりの機能を誇ります。 vimshellはzshの機能を一部取り込んでいて、コマンドラインスタックや優れた履歴検索機能もあります。
Conqueとの比較
その他のライブラリとして、vimprocやvimshellをもとにNico Raffatoさんが製作しているConqueというプラグインがあります。まだVer.1.0がリリースされたばかりですが、現在も精力的に開発されています。 これは内部でPythonインタフェースを用いて外部プロセスとの通信を行っているので、安定性に難があるのと、Pythonインタフェースが必須になっています。 Emacsのansi-termを目標にしているようで、端末としてはかなりの完成度を誇ります。 ただし日本語が使えなかったり、Windows環境で動作しないという問題があります。 キー入力をすべて奪いとってしまうので、他のプラグインとの連携もしづらいです。 Emacsも内部で動かせるなど、ネタとしてはかなり面白いのですが……。
Shougo- Comments: 0
- Trackbacks: 2
Hack #135: ]で補完する
- 2010-03-29 (月)
- Vim Hacks
多くの方はTabキーを補完のために使うため、以下のような設定をしていると思います。
inoremap <Tab> <C-n>
Tabキーを打鍵し続けると、左手小指が破壊されます。公平のため、右手小指も使うべきではないでしょうか。Tabキーと対称な位置にあるキーは[または]です。後述する理由のため、]をTabキーのかわりに補完用のキーに設定してみましょう。
まずは素直に、先ほどのTabキーと同様の方法で設定します。
inoremap ] <C-n>
これは便利なのですが、本当に]を入力したいときに、<C-v>]と打鍵しなければならないのがつらいです。
解決法1
そもそも]を入力しないで済むように、自動で入力するようにします。
inoremap [ []<Left>
[を入力した時点で自動的に]が入力されるので、]を手動で入力する必要がなくなります。 大抵の場合は]は対応する[があってこそ意味があるので、この解決方法でうまくいくことでしょう。
解決法2
実際には、勝手に]が入力されてしまうのは直感に反するとして嫌悪する方が多いのではないでしょうか。私がまさにそうです。 すこし複雑ですが、以下のような対処法はどうでしょうか。
- 通常は]が<C-n>として動作する
- カーソル位置より手前に閉じていない[があれば、]は]として動作する
これを実現するには、~/.vimrcに以下を記述します。
inoremap <expr> ] searchpair('\[', '', '\]', 'nbW', 'synIDattr(synID(line("."), col("."), 1), "name") =~? "String"') ? ']' : "\<C-n>"
ちょっとややこしいので、具体例で動作を説明します。
カーソル位置を_とします。まず、
aaa[bbb_
この状態で]を打鍵すると、
aaa[bbb]_
となります。いっぽう、
aaa bbb_
この状態で]を打鍵すると、
aaa bbba
|bbbb|
|bbbc|
|bbbd|
+----+
このように補完のポップアップメニューが出てきます。
また、""で囲まれた部分は無視します。
"[".t_
この状態で]を打鍵すると、
"[".t]_
ではなく、補完がはじまります。
謝辞
thincaさんの添削により、オリジナルで32行だった実装が1行になりました。そのときの履歴はこちらを参照ください。 https://gist.github.com/24e46f72cc08e53c59a1
ujihisa- Comments: 0
- Trackbacks: 0
Hack #124: Vimで非同期実行を行う
- 2010-02-13 (土)
- Vim Hacks
VimがEmacsと比較して一番劣っている機能として、コマンドの非同期実行があげられます。ここでは現状のコマンド実行の問題点とEmacsとの比較、その解決方法について議論を行います。
Vimのコマンド実行の欠点
Vimはsystem()や:readを用いて外部コマンドを実行し、その結果を得ることができます。これは非常に便利なのですが、Vimが起動した外部コマンドの終了を待ち合わせるため、Vimが停止してしまうという欠点があります。これは特にquickrunや:makeを実行しているときに問題となります。プログラムをバックグラウンドで実行すれば、終了を待ち合わせずにすみますが、それでは結果がとれません。さらにWindows上のGVimの場合、外部コマンドを実行するたびにDOS窓が開いて煩わしいです。
処理内容がシェルに依存するという欠点もあります。たとえば、Windowsでプログラムを起動するためには適切にエスケープしなければいけません。
Emacsとの比較
対するEmacsはどうでしょう。Emacsでは、start-process関数を用いてプロセスを生成することにより、コマンドを非同期的に実行できます。
comint-modeでもこれを用いてインタプリタを起動し、非同期で通信しています。
ただし、Emacsにはマルチスレッド関数がありません。全ての処理はシングルスレッドです。
外部インタフェースの欠点
RubyやPerl, Pythonといった外部インタフェースを用いるという解決策もあります。 しかし、外部インタフェースは通常のVimScriptとは文法が異なるため、連携が非常にややこしいです。時折フリーズしたり、エラーが起こったときにデバッグしづらいという欠点もあります。さらに、すべての環境で使えるわけでもありません。インストールしているRubyやPerl, Pythonのバージョンにも依存するなど、 非同期に通信するためだけに外部インタフェースを用いるのは大げさすぎます。 ただし外部インタフェース内ではマルチスレッドが使えるので、真の非同期通信をするためには、外部インタフェースを用いるほかありません。
vimprocについて
外部ライブラリであるvimprocを用いて外部コマンドと通信すれば、上記に挙げたほとんどの欠点が解消されます。 vimprocとはYukihiro Nakadairaさんが開発している、優れた非同期実行ライブラリです。私が改良したものをgithub上で開発しています。 http://github.com/Shougo/vimproc/tree/master ソースからコンパイルしてVimのautoloadディレクトリに、「proc.soまたはproc.dll」と「vimproc.vim」をコピーすれば準備完了です。
ここでは、vimprocで実装されているvimproc#system関数を紹介します。これは、標準のsystem関数を置き換えることができます。
ただしシェルを起動しないので、シェルの内部コマンドは動作しません。パイプやリダイレクトも動かないので注意してください。
パイプやリダイレクトについては、今後実装予定です。
let l:result = vimproc#system('ls')
vimprocを駆使すれば非同期実行をエミュレーションできますが、スレッドの存在しないVimでは使い方がとてもややこしいので、ここでは説明を省略します。
興味がある場合にはvimprocのtestディレクトリにあるサンプルスクリプトを参照してください。
ネットワーク通信もできるので、Twit.vimみたいなプログラムも簡単に作成できます。
いずれはcomint-modeのように、インタプリタ実行機能を統合させたいと思っています。
ちなみにVimScriptでのシェル実装であるvimshellでも、vimprocを用いて非同期実行を行っています。
その他の非同期実行ライブラリ
その他のライブラリとして、vimprocやvimshellをもとにNico Raffatoさんが製作しているConqueというプラグインがあり、とても精力的に開発されています。Emacsのansi-term.elを目標にしているようで、動作が散漫なのが欠点ですが、多機能のようなので使用してみるといいかもしれません。
CursorHoldイベントの落とし穴
しかも、Vimには指定された時間が経過したら関数を呼び出すタイマー機能がありません。
CursorHoldIやCursorHoldイベントで代用するという手がありますが、これにはイベントごとに時間を設定できない、
ポップアップが表示されているときは呼ばれない、カーソルが動くまで呼ばれないといった欠点があります。
この欠点は本質的に回避不能です。Vim本体にタイマー実行機能が搭載されるのを待つしかありません。
clientserver機能を使う
Vimのclientserver機能を用いると、処理が完了した際に機能を呼び出すコールバック機能を実装することが可能です。
ただし、X環境が必要になります。Windows上でも使用できますが、あらかじめ別のVimを用意しておく必要があります。詳しくは:help clientserverを参照してください。
- Comments: 0
- Trackbacks: 0
Hack #118: ホームディレクトリをラクに入力する
- 2010-01-20 (水)
- Vim Hacks
問題
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
- Comments: 0
- Trackbacks: 0
Hack #115: Vimのバージョンや拡張機能をチェックする
- 2010-01-08 (金)
- Vim Hacks
自分でプラグインを書く場合、プラグインが動作している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- Comments: 0
- Trackbacks: 1
Hack #110: Vimでプレゼンをする (Mac OS X編)
- 2009-12-19 (土)
- Vim Hacks
Vimというプレゼンツールソフトウェアは、ソフトウェア開発にも用いることができるということで知られています。 本HackではVimをMac OS Xでプレゼンツールとして便利に使うための手法を公開します。
iTerm + Vim
定番の組み合わせはiTermとターミナル上で動作する素のVimです。 特別なことがなければ、この組み合わせを選択するのがもっとも無難でしょう。
利点
- 文字の大きさの変更が柔軟で容易 (単にCmd+やCmd-を連打するだけ)
- screenを用いることにより、Vimからシェルへの移動をスムーズに行なうことができる
- フルスクリーンなので無駄なスペースがない
欠点
- 画像を表示することができない
- 等幅フォント固定
- 部分的にフォントサイズを変更することができない
(KeyNoteと組み合わせて使うこともできます)
MacVim
ターミナルではなく、単独のGUIアプリケーションであるMacVimを使う方法もあります。 フォントサイズの変更が柔軟でない一方、このパッチを適用することにより、プロポーショナルフォントを使うことができるという利点があります。
ただし、フルスクリーンにできない、文字のサイズ変更が容易でないなどデメリットが多過ぎますので、あまりお勧めしません。
シェルを使うときはvimshellを用いるとよいでしょう。
:TOHtml + Opera
もはやVimではないですが、見た目はVimですので、多くの観客を騙すことができます。 フルスクリーンにすることのできるブラウザならば何でも良いのですが、Operaが最も手っ取り早いでしょう。
:TOHtmlした結果のHTMLに対して画像のタグを貼付けることによって、Vimの素晴らしい見た目でかつ画像を表示でき、最高のプレゼン環境と言えるでしょう。
文字のサイズも柔軟に変更できます。
唯一の問題点は、Vim上で動作しているわけではないので、その場でquickrunやvimshellを動かすことができない点です。
ujihisa- Comments: 0
- Trackbacks: 0
Hack #109: 本当は怖いVim script – var{ia}ble編
- 2009-12-15 (火)
- Vim Hacks
問題
Hack #105: surroundをより便利に使う では、surroundの設定例として以下のものを取り上げました:
let g:surround_{char2nr('j')} = "「\r」"
Hack #105では本筋でないのため軽く流しましたが、 よくよく確認してみると変数名の記述が変態的なものになっています。 一体これはどういうことなのでしょうか。
解説
Vimでは変数名(および関数名)の中に任意の式を
{expr}の形で埋め込むことができます。
変数名中に{expr}が含まれる場合、
実行時に{}中の式exprが評価され、
その結果で{expr}が置き換えられます。
最終的には{expr}が置き換えられた
変数名が参照されることになります。
例えばg:surround_{char2nr('j')}の場合、
式char2nr('j')を評価した結果(= 106)で
{char2nr('j')}が置き換えられ、
最終的にg:surround_106が参照されることになります。
ですから、
let g:surround_{char2nr('j')} = "「\r」"
は
let g:surround_106 = "「\r」"
と等価です。
ただ{expr}による表記の方が意図するところが分かり易くなります。
現代的なVim scriptならば
let g:surround = {}
let g:surround['j'] = "「\r」"
のような形で記述するところですが、 surroundの場合は過去のバージョン(6.x)のVimでも動作するように記述されており、 またlistやdictionaryなどの現代的な要素はVim 7.xから追加されたものであるため、 このようになっています。
言い換えると、Vim scriptにはつい最近まで配列すら存在しなかったのです。
var{ia}ble表記が導入された理由の一つは、
値として数値と文字列しか存在しなかった時代に、
なんとかして配列を実現するための手段としてです。
参考資料
- :help curly-braces-names
- :help version6.txt (「curly」でページ内を検索)
- Comments: 0
- Trackbacks: 0
Home > Tags > lv3
- Search
- Feeds
- Links

