scriptで簡単なアプリケーションが書けるレベルになっていると信じています。scriptをちゃんとマスターして、来年の夏には引き締まったボディでビーチを歩いてみませんか。貴方のvimrcに皆の視線が釘付けになる事は間違いないでしょう。あの人が書いたVimプラグイン、どうやって動いてるんだろう。あの人が書いたVimプラグインと同じ事がやりたい。思った貴方もこれを理解すれば、おおよそ仕組みが分かる程度を記述したつもりです。script特有の制限になります。数値は一般的な言語と同じ様に四則演算できます。文字列については.を用いて連結します。"hello"[1:3]という記述が出来ます。evalに詳しく記述されています。型同士の比較についてはthincaさんの記事が役立ちます。流行ってるみたいなので遅ればせながら便乗。http://d.hatena.ne.jp/thinca/20100201/1265009821気をつけなければいけないのが、数値については.を用いて文字列と結合し、文字列化することが出来ますが、浮動小数点については特殊で文字列に直す場合にはstring()を使って文字列化する呼び出す必要があります。文字列からfloatに直す場合においてもstr2float()を使う必要があります。その他、それぞれの型での操作方法についてもthincaさんの記事が詳しいです。thincaさんの記事をVimのhelp化した物が提供されています。よろしければインストールしてVimから参照できる様にしておくと便利です。VimScriptは他の言語と比べ癖があり、Vimの仕様と直結している為、他の言語と同等の機能が無かったり、もしくはやり方が異なったりするものも中にはあります。scriptでも関数が定義出来ます。Foo()fooと表示されます。同じ関数名を定義するにはfunction!を指定します。scriptはエラーが発生した場合においても処理が続行します。これが他の言語と大きく異なる所です。asdfasdffoobarと表示されます。不明なコマンドを検出してもfooは表示されますし、barも表示されます。前述の様にスタックトレースの様な物がドバーーーと出るのはこれが原因です。エラーの出た行が変数宣言および代入文であった場合、エラーによりその変数は定義されなかった物となります。これにより、以降その変数を参照する処理において全てエラーが発生する事になります。scriptにおいても例外処理が無い訳ではありません。その2つをご紹介します。try/catch/finallyこれは他の言語でも実装されている物と同様です。上記の例でasdfasdfをtry/catchで囲ってみましょう。Bar()実行するとbarだけ表示されますね。うまくエラーが回避出来た事を意味します。このcatch区で関数をreturnさせても良いのですが、可能ならばエラー情報を引き継いで関数を抜けたいものです。scriptの場合は他の言語と少し異なる形式になりますabort識別こんどは以下の様に記述してみましょう。asdfasdfbarfooが表示されませんでした。abort識別はエラーが発生した際に即時で関数を抜ける事を明示します。Bar()こうする事で例外を山を見る事無くグレイスフルなエラーメッセージが表示される様になります。try/catch/finallyに加えてthrowも使えます。文字列を指定して例外を投げます。自ら例外を投げる場合に使用しますが、先頭がVimから始まる文字列は内部処理の為に予約されています。スコープさて一度ここでスコープの説明をします。scriptには、関数内で有効なローカルスコープl:、スクリプトファイル内で有効なスクリプトスコープs:、グローバル域で有効なグローバルスコープg:が存在し、それ以外にもバッファスコープb:、ウィンドウスコープw:、タブスコープt:が存在します。変数はこれらのスコープに宣言出来ますが、関数はグローバルスコープ、スクリプトスコープに限られます。それ以外で宣言してもエラーは出ませんが、それは単にそういう名前のグローバルスコープ関数が定義された物として扱われます。このスコープ内関数ですがスコープとは言えど外から呼び出す事が出来ます。外部からはSIDという修飾を付けれる事で呼び出す事が出来ます。参照して頂いた方が分かりやすいでしょう。range識別abort識別と同じ様にrange識別という物があります。これはVim独特の物になりますが、この識別を指定するとa:というプレフィックスでアクセス出来る引数にa:firstlineとa:lastlineという変数が参照出来る様になります。g:MakeYouVim()と実行すると、全ての行で毎回この関数が呼ばれるのですが、range識別を付ける事で行範囲を纏めて1回で呼び出す事が出来る様になります。その際、最初の行番号と最後の行番号を意味するのがa:firstlineとa:lastlineです。endforendfunctionよってこの様にループを回す事も出来ます。scriptで扱える型の一つにDictionaryがありますが、このDictionaryにはメンバ関数を定義する事も出来ます。s:foo.bar()この際、s:foo.barは暗黙でdict識別が付けられている事を意味します。dict識別が付いている関数でself変数を使ってDictionary自身を参照する事が出来ます。このdict識別は通常の関数にも指定出来ます。s:foo.bar()通常の関数にdict識別を付け、Dictionaryのメソッドを書き換える事で通常と異なる処理を実行出来ます。これを使う事で、結構いろんな事が出来る様になります。バッファをHTML化するコマンド:TOHtmlは内部ではプログレスバーウィジェットという物を使っているのですが、これのオリジナルが以下の物になります。scriptからプログレスバー(実際にはステータスバーの表示を変えてるだけ)を表示出来る様になります。pb.restore()このプログレスバーの表示方式を変えてみましょう。オリジナルのソースからs:progressbar.paintを貰ってきてs:progressbar_paintとしてローカルにdict識別付きで宣言しましょう。pb.restore()この様にメソッドを上書きしてあげる事で、アイコンがグルグルまわるプログレスバーが実現出来る様になります。scriptで関数リファレンスを取るにはfunction()関数を用います。function()で得た関数リファレンスは直接()をつけて呼び出せますが、call関数を使用すると引数を配列で渡して動的に呼び出す事が出来ます。scriptはキーマップを提供します。全てのモードにマップするmap、それぞれのモードにマップするimap(インサートモード)、nmap(ノーマルモード)、cmap(コマンドモード)、vmap(ビジュアル選択モード)、そしてそれらを再帰的にマップさせないinoremap、nnoremap、cnoremap、vnoremapが一般的に使われます。その他幾らかありますが、おそらく使わない事の方が多いでしょう。マップの実行は以下の様に行います。Foo()cr>もちろん、インサートモードから関数を実行しようと思えば、:の前にを入れなければなりません。現在のバッファのみにマップされ、は実行する関数でのメッセージ表示を抑制します。インサートモードにおいて、関数の評価結果から入力文字列を挿入させる為には指定をつける事で実現出来ます。Foo()commandコマンドモードから実行出来るコマンドを定義します。ユーザが作るコマンドはユーザコマンドと呼ばれ、名前の先頭が大文字である必要があります。:command-argsに詳しく記述されています。scriptにはよくfoo#bar#baz()という記述をよく見かけます。これはautoloadとよばれます。これまでVim起動時にはpluginフォルダは以下の.vimファイルがすべて読み込まれていました。これにより、目的の編集作業に必要ない関数や変数の宣言、初期化処理が実行されていました。これでは起動が重くなるだけです。そこで登場したのがautoloadです。foo#bar#baz#XXX()というアクセスの瞬間にbaz.vimが読み込まれるという仕組みを持っています。scriptはpluginではコマンドやキーマップのみを宣言するのが最近の流儀です。f-args>)しかありません。autocmdVimの操作に伴い、イベント処理を行う事が出来ます。g:MyHtmlSetup()この例では、*.htmlの様なファイル名としてバッファが作られた、もしくはファイルが読み込まれたタイミングでイベントが発動し、MyHtmlSetupという関数を呼び出す例になっています。多くのVimプラグインはこれを使ってファイルタイプ独自の処理を行っています。:autocmdを参照して下さい。scriptにはlambdaがありません。使いたくなるのがプログラマです。scriptのsort関数の第二引数には関数リファレンスを取ります。既述の様に名前を付けて宣言しても良いのですが、lambdaの様に指定出来たら気持ちいいですよね。ここで大きな問題があります。scriptには構文を変えられるだけの力量がありませんし、eval関数で関数を宣言する事が出来ません。前者については言語の仕様なので仕方ありません。後者について、これが何を意味しているのかというと「関数を作ろうと思ったら関数宣言しないと駄目」という事なのです。scriptの:execute命令を使えば関数も定義出来ます。ライブラリとして:execute命令を使って関数を宣言する物を作ったとしましょう。g:MakeLambda("a:1+a:2")(1,2)もちろんこの関数には欠陥があります。関数リファレンスを返しますが、2回目の呼び出しで1回目の関数を壊してしまいます。ここは以前の余地がありますね。この関数、実行されるのがg:MakeLambdaを宣言したスコープと同じになってしまうのです。lambdaは通常、実行したスコープと同じスコープでキャプチャされるべき物ですが、これが出来ません。scriptの:execute命令は実行位置スコープで動作するのでは無く、宣言位置スコープで実行されるのです。よっていくら工夫しても呼び出し元のスコープでは実行されないのです。"をパロったものです。suginoyさんの許可を得て公開します。ない落とし穴があります。http://d.hatena.ne.jp/thinca/20090826/1251258056を読んでもらえると分かります。あがいてもスコープ指定でeval実行する事は出来ないという事です。scriptにはjavascriptで言うところのwithやFunction.bindがありません。scriptでlispエンジンを書いた時に再度実装し気付きました。要は、スコープ参照したい位置に関数を作れば良いのです。https://github.com/mattn/lambda-vimこれを使うには以下の様にします。a:1')(3)上記の「:executeは実行スコープ」というのを逆手に取り、lambda#setup()から関数定義の文字列を貰います。s:XXX()の形式では呼び出せない関数を作ります。この関数が内部でeval()を実行する為、上記の例の様にlambda内からs:fooを参照する事が出来る様になります。最初のlambda#setup()が気持ち悪い気がしますが、幾分便利になった気がします。このライブラリには毎回個別の関数リファレンスを返すlambda#genと、毎回関数を壊して1度しか使わないlambdaの為の関数生成処理、lambda#onceが用意されています。2)の様に_という名前の配列で参照出来ます。良かったら使ってみて下さい。scriptにもライブラリという概念が入ってきました。webapi-vimVimからhttp通信を行う際に便利なユーザエージェント、XMLパーサ、HTMLパーサ、JSONパーサ、OAuthライブラリ、Atomライブラリ、XMLRPCライブラリ、などWebのAPIに関する色々な物が入っています。wwwrenderer-vimwebapi-vimでHTMLをパースしたDOMからテキストブラウザの様な表現を行う為のライブラリです。vital.vimバンドル型のライブラリセットで、ポータビリティ、バージョン管理に優れています。ujihisaさん、Shougoさん、tyruさん、thincaさん、と私が開発しています。vimprocVimからプロセスを制御する事が出来るライブラリです。コンパイルが必要です。以前は中平さんが開発していた物をShougoさんが引き継いでいます。弱いのですが、それをVimのremoteプロトコルを使って通信出来る様にライブラリ化した物です。中平さんが開発しています。open-browser主にURLの抽出やブラウザの起動に特化したライブラリです。tyruさんが開発しています。openbufバッファの生死管理やイベントハンドリングに使用します。thincaさんが開発しています。その他、もっと沢山あって書ききれませんが、日本人が開発していて著名な所だと問い合わせも容易ですし、間違いなく日本語に対応しています。上達方法これについて先日、日本人Vimmer達が議論していましたが、ブログやヘルプ、www.vim.orgにあるスクリプトを見て勉強したと言ってました。コードを読め...と言うのが先人からの教えでしょうか。scriptの関数は他の言語から比べると、かなり取っ付きにくい性質を持っています。DISられても当然と思われるでしょう。これはエディタが先に生まれ、設定ファイルを記述するべくして生まれ、それがアプリケーションを記述する為に進化していったという過程を考えると、必要最低限な実装と制限であったと言えるでしょう。scriptは無くならないでしょう。その制限された中でも上記の様なトリッキーな技によって皆を沸かせる事が出来るのも、Vimが持っている性質であるのではないでしょうか。