vim-jp / vimdoc-ja / usr_41

usr_41 - Vimドキュメント

メインヘルプファイルに戻る
usr_41.txt    For Vim バージョン 8.2.  Last change: 2021 Sep 10

                     VIM USER MANUAL - by Bram Moolenaar

                              Vim script 書法


Vim script 言語は vimrc ファイルや構文ファイルなど、さまざまな目的に使われま
す。この章では Vim script の書き方を説明します。説明することがたくさんあるので
大きな章になってます。

41.1  はじめに
41.2  変数
41.3  式
41.4  条件式
41.5  式を実行する
41.6  関数を使う
41.7  関数を定義する
41.8  リストと辞書
41.9  例外
41.10 注意事項
41.11 プラグインを書く
41.12 ファイルタイププラグインを書く
41.13 コンパイラプラグインを書く
41.14 プラグインを書く (高速ロード版)
41.15 ライブラリスクリプトを書く
41.16 Vim script を配布する

次章: usr_42.txt  新しいメニューを追加する
前章: usr_40.txt  新しいコマンドを作る
目次: usr_toc.txt

==============================================================================
41.1  はじめに                                vim-script-intro script

誰もが最初に触れる Vim script は vimrc ファイルです。Vim が起動するときに読み
込まれ、書かれているコマンドが実行されます。それにより好きなように設定を変更で
きます。vimrc の中ではすべてのコロンコマンドが使えます (":" で始まるコマンドの
こと。Ex コマンドやコマンドラインコマンドと呼ばれることもある)。
シンタックスファイルも Vim script です。シンタックスファイルは、ファイルタイプ
別にオプションを設定するファイルの一種です。複雑なマクロ定義を別ファイルに分け
て保存しておくこともできます。このように、いろいろな使用方法が考えられます。

        あなたが Python に親しんでいるなら、Python と Vim script 間の比較につ
        いて、以下で他のドキュメントへの参照を見付けることができます:
           https://gist.github.com/yegappan/16d964a37ead0979b05e655aa036cad0
        そしてあなたが JavaScript に親しんでいるなら:
           https://w0rp.com/blog/post/vim-script-for-the-javascripter/

簡単な例から始めましょう:

        :let i = 1
        :while i < 5
        :  echo "count is" i
        :  let i += 1
        :endwhile

        Note:
        実際には ":" を書く必要はありません。":" が必要なのはコマンドラインで
        入力するときだけです。Vim script ファイルを書くときは省略できます。
        このヘルプでは、コロンコマンドであることを強調し、ノーマルモードと区別
        するためにコロンを表記しています。
        Note:
        例文をヤンクして :@" コマンドで実際に実行できます。

出力は次のようになります:

        count is 1
        count is 2
        count is 3
        count is 4

一行目では ":let" コマンドで変数に値を代入しています。書式は次のとおりです:

        :let {変数名} = {式}

例では、変数名が "i"、式が 1 です。
":while" コマンドでループを開始します。書式は次のとおりです:

        :while {条件式}
        :  {ステートメント}
        :endwhile

条件式が真である間、ステートメントが実行されます。例では、条件式は "i < 5" で
す。これは、i が 5 より小さい場合に真になります。
        Note:
        何かのミスで while ループが止まらなかった場合は、CTRL-C を押せば中断で
        きます (MS-Windows では CTRL-Break)。

":echo" コマンドは引数を出力します。例では、"count is" という文字列と、変数 i
の値を出力しています。i が 1 なら、次のように表示されます:

        count is 1

":let i += 1" は ":let i = i + 1" と同じ意味です。変数 i に 1 を加算し、新しい
値を同じ変数に代入します。
Note: これは旧来の Vim script で動かす方法で、このファイルで検討します。Vim9
script の場合はちょっと違います。usr_46.txt を参照。

上述の例は、実際にはもっと簡潔に書くことができます:

        :for i in range(1, 4)
        :  echo "count is" i
        :endfor

:for と range() の説明はもっと先です。すぐに知りたい人はリンク先にジャンプ
してください。


4種類の数値
------------

数値は10進数、16進数、8進数および2進数のいずれかで表記します。

16進数は "0x" か "0X" で開始します。例えば "0x1f" は10進数の 31 です。

8進数は "0o" か "0O" あるいは "0" とつづく他の数値で開始します。例えば "0o17"
は10進数の 15 です。Vim9 script では前置詞が "0" だけの利用はサポートされませ
ん。

2進数は "0b" か "0B" で開始します。例えば "0b101" は10進数の 5 です。

10進数は数値そのままです。注意: 10進数で書くときは先頭に "0" を付けないでくだ
さい。旧来のスクリプトでは8進数として扱われてしまいます!

":echo" コマンドは常に10進数で出力します。例:

        :echo 0x7f 0o36
        127 30

数値にマイナス記号を付けると負数になります。8進数、16進数や2進数も負数にできま
す。マイナス記号は減算記号としても使われます。次の例を上の例と比べてみてくださ
い:

        :echo 0x7f -0o36
        97

式の途中にある空白は無視されますが、可読性を高めるために、適切に空白で区切るこ
とをお勧めします。例えば上記の数値が負数であると勘違いしてしまわないように、マ
イナス記号と数値の間に空白をいれましょう:

        :echo 0x7f - 0o36

==============================================================================
41.2  変数

変数名にはアルファベット、数字、アンダースコアが使えます。変数名を数字で開始す
ることはできません。次のような変数名が使えます:

        counter
        _aap3
        very_long_variable_name_with_underscores
        FuncLength
        LENGTH

"foo+var" や "6var" のような名前は使えません。
例に挙げた変数はグローバル変数です。定義されている変数の一覧を見るのは次のコマ
ンドを使います:

        :let

グローバル変数はどこでも使えます。そのため、あるスクリプトファイルで "count"
という変数を使ったとき、その変数は他のスクリプトでも使われている可能性がありま
す。これは混乱を招きますし、トラブルの元です。それを避けるには "s:" を付けてス
クリプトローカル変数を使います。例えば、次のように使います:

        :let s:count = 1
        :while s:count < 5
        :  source other.vim
        :  let s:count += 1
        :endwhile

"s:count" はスクリプトローカル変数なので、他のスクリプトファイルによって変更さ
れる心配はありません。他のスクリプトファイルで "s:count" 変数が使われていたと
しても、それは別の変数です。スクリプトローカル変数についての詳細は
script-variable を参照してください。

変数の種類は他にもあります。internal-variables 参照。次の変数がよく使われま
す:

        b:name          バッファローカル変数
        w:name          ウィンドウローカル変数
        g:name          グローバル変数 (関数内では g: 必須)
        v:name          Vim が定義する変数


変数の削除
----------

変数はメモリを消費します。":let" コマンドの出力にも表示されます。変数を削除す
るには ":unlet" コマンドを使います。例:

        :unlet s:count

スクリプトローカル変数の "s:count" が削除され、使用されていたメモリが開放され
ます。変数が存在しない場合でもエラーを起こしたくない場合は ! を付けてください:

        :unlet! s:count

スクリプトの実行が終了したとき、ローカル変数は自動的には削除されません。次に同
じスクリプトを実行したときにその変数を使うことができます。例:

        :if !exists("s:call_count")
        :  let s:call_count = 0
        :endif
        :let s:call_count = s:call_count + 1
        :echo "called" s:call_count "times"

"exists()" 関数は変数が定義されているかどうかをチェックします。引数に調べたい
変数の名前を指定します。変数自体を指定するのではありません。例えば:

        :if !exists(s:call_count)

これは、s:call_count の値を変数名として exists() 関数を呼び出しているので、意
味が違ってしまいます。
感嘆符 (! 記号) は値を反転します。値が真なら偽になり、偽なら真になります。この
記号は "not" と読むことができます。つまり、"if !exists()" は "if not exists()"
と読むことができます。
Vim では、0 以外の値はすべて真です。0 は偽です。
        Note:
        数値が必要なところで文字列を使ったとき、文字列は自動的に数値に変換され
        ます。文字列の先頭が数字ではなかった場合は 0 に変換されます。つまり:
                :if "true"
        "true" は 0 に変換されるので偽になります。


文字列変数と定数
----------------

ここまでは変数の値に数値だけを使っていましたが、文字列を使うこともできます。
Vim は数値と文字列を基本型としてサポートしています。変数は動的に型付けされま
す。型は ":let" コマンドで変数に値を代入するたびに変化します。詳しくは41.8
を参照してください。
変数に文字列を代入するには文字列定数を使う必要があります。文字列定数には二つの
種類があります。一つはダブルクォート文字列です:

        :let name = "peter"
        :echo name
        peter

文字列の中でダブルクォートを使いたい場合は、バックスラッシュを前置してくださ
い:

        :let name = "\"peter\""
        :echo name
        "peter"

バックスラッシュを使いたくない場合はシングルクォート文字列を使ってください:

        :let name = '"peter"'
        :echo name
        "peter"

シングルクォート文字列の中ではすべての文字がそのまま使われます。ただし、シング
ルクォートだけは特別で、一つのシングルクォートを表すためには二つのシングル
クォートを書く必要があります。バックスラッシュはそのまま使われるので、特殊文字
は使えません。
ダブルクォート文字列の中では特殊文字が使えます。次のようなものがあります:

        \t              <Tab>
        \n              <NL>, 改行
        \r              <CR><Enter>
        \e              <Esc>
        \b              <BS>, バックスペース
        \"              "
        \\              \, バックスラッシュ
        \<Esc>          <Esc>
        \<C-W>          CTRL-W

最後の二つはただの一例です。"\<name>" 形式で "name" という特殊キーを使うことが
できます。
文字列で使える特殊表記については expr-quote を参照してください。

==============================================================================
41.3  式

Vim の式は高機能でシンプルです。式の定義については expression-syntax を参照
してください。ここでは基本的なことだけを説明します。
数値と文字列と変数はそれ自体が式です。つまり、式が必要なところでは数値でも文字
列でも変数でも使えます。他にも次のようなものが使えます:

        $NAME           環境変数
        &name           オプション
        @r              レジスタ

例:

        :echo "The value of 'tabstop' is" &ts
        :echo "Your home directory is" $HOME
        :if @a > 5

&name 形式を使うと、オプションを保存し、別の値に設定し、何かを実行して、オプ
ションを元に戻す、というようなことができます。例:

        :let save_ic = &ic
        :set noic
        :/The Start/,$delete
        :let &ic = save_ic

'ignorecase' オプションをオフにしてから "The Start" パターンを検索しています。
しかし設定は変更されません。(パターンに "\C" を加える方法でも同じことができま
す。/\C 参照。)


数値計算
--------

基本的な要素を組み合わせると面白くなってきます。まずは数値計算です:

        a + b           加算
        a - b           減算
        a * b           乗算
        a / b           除算
        a % b           剰余演算(余りを得る)

演算子の優先順位は一般的な規則と同じです:

        :echo 10 + 5 * 2
        20

カッコを使って優先順位を変更できます:

        :echo (10 + 5) * 2
        30

文字列は ".." で連結できます(expr6 参照)。例:

        :echo "foo" .. "bar"
        foobar

":echo" コマンドに複数の引数を指定すると、スペースで区切られて表示されます。こ
れらの例では一つの式しか使われていないので、スペースは挿入されていません。

C 言語と同じ条件演算子も使えます:

        a ? b : c

"a" が真なら "b" が使われ、そうでなければ "c" が使われます。例:

        :let i = 4
        :echo i > 5 ? "i is big" : "i is small"
        i is small

被演算子の部分は優先的に評価されるので、次のように見なすことができます:

        (a) ? (b) : (c)

==============================================================================
41.4  条件式

":if" コマンドは条件が真の場合に ":endif" までのステートメントを実行します。書
式は次のとおり:

        :if {condition}
           {statements}
        :endif

{condition} を評価した結果が真 (0以外) であれば、{statements} の内容が実行され
ます。{statements} は正しく記述されている必要があります。不正な記述があると
":endif" までたどり着けません。
":else" を使うこともできます。書式は次のとおり:

        :if {condition}
           {statements}
        :else
           {statements}
        :endif

二つ目の {statements} は条件が偽の場合にだけ実行されます。
":elseif" を使うこともできます:

        :if {condition}
           {statements}
        :elseif {condition}
           {statements}
        :endif

これは ":else" に続けて "if" 文を使うのと同じ動作ですが、余計な ":endif" を使
わなくて済みます。
vimrc ファイルで便利に使える例を示しましょう。'term' オプションの値を調べ、そ
の値に応じて処理を分けます:

        :if &term == "xterm"
        :  " xterm 用の設定
        :elseif &term == "vt100"
        :  " vt100 端末用の設定
        :else
        :  " その他の端末用の設定
        :endif


論理演算子
----------

今までの説明で既に論理演算子を使いました。次の演算子がよく使われます:

        a == b          等しい
        a != b          等しくない
        a >  b          より大きい
        a >= b          より大きいか等しい
        a <  b          より小さい
        a <= b          より小さいか等しい

条件が成立するなら 1、そうでなければ 0 が返ります。例:

        :if v:version >= 700
        :  echo "おめでとう"
        :else
        :  echo "古いバージョンを使っています。更新してね!"
        :endif

"v:version" は Vim によって定義されている変数で、Vim のバージョンが入っていま
す。バージョン 6.0 なら 600、バージョン 6.1 なら 601 です。これは複数のバージョ
ンに対応するスクリプトを書くときに便利です。v:version

論理演算子は数値でも文字列でも扱えます。文字列どうしを比較するときは数学的な差
が比較されます。文字のバイト値を比較するので、一部の言語では正しい結果にならな
いかもしれません。
文字列と数値を比較するときは、文字列を数値に変換します。文字列が数字ではなかっ
たときは 0 になるので注意してください。例:

        :if 0 == "one"
        :  echo "yes"
        :endif

これは "yes" と表示されます。"one" は数字ではないので 0 に変換されるのです。

文字列にはさらに二つの論理演算子があります:

        a =~ b          パターンにマッチする
        a !~ b          パターンにマッチしない

左辺の "a" は文字列として扱われます。右辺の "b" は検索パターンとして扱われま
す。例:

        :if str =~ " "
        :  echo "str にはスペースが含まれている"
        :endif
        :if str !~ '\.$'
        :  echo "str の末尾はピリオドではない"
        :endif

パターンを指定するのにシングルクォート文字列を使うのがコツです。ダブルクォート
文字列ではバックスラッシュを二重に書く必要があり、そして、検索パターンではバッ
クスラッシュをよく使うので、バックスラッシュだらけになってしまいます。

文字列を比較するときは 'ignorecase' オプションが使われます。大文字小文字の区別
を明示的に指定したい場合は比較演算子に "#" (区別する) または "?" (区別しない)
をつけます。大文字小文字を区別せずに等しいかどうかを比較したい場合は "==?" を
使います。"!~#" ならパターンにマッチしないことを、大文字と小文字を区別して確認
できます。演算子の一覧は expr-== を参照してください。


他のループコマンド
------------------

":while" コマンドは既に説明しました。":while" ループの中では二つのステートメン
トが使えます:

        :continue               ループの先頭にジャンプしてループを継続する。
        :break                  ":endwhile" までジャンプしてループを脱ける。

例:

        :while counter < 40
        :  call do_something()
        :  if skip_flag
        :    continue
        :  endif
        :  if finished_flag
        :    break
        :  endif
        :  sleep 50m
        :endwhile

":sleep" コマンドは Vim を一定時間停止します。"50m" は 50 ミリ秒です。
":sleep 4" なら 4 秒間スリープします。

":for" コマンドを使ってループすることもできます。41.8を参照。

==============================================================================
41.5  式を実行する

今まではコマンドを直接書いてきました。":execute" コマンドを使うと、式の評価結
果をコマンドとして実行できます。これによってコマンドを動的に生成することができ
ます。
例えば、変数に格納された文字列を使ってタグジャンプするには次のようにします:

        :execute "tag " .. tag_name

文字列 "tag " と変数 "tag_name" の値を ".." で連結しています。仮に "tag_name"
の値が "get_cmd" だった場合、次のコマンドが実行されることになります:

        :tag get_cmd

":execute" コマンドはコロンコマンドのみ実行できます。":normal" コマンドでノー
マルモードコマンドを実行できますが、このコマンドの引数は文字がそのまま使われ、
式としては評価されません。例:

        :normal gg=G

このコマンドは一行目にジャンプしてから "=" オペレータですべての行を整形します。
":normal" コマンドで式の値を使いたい場合は ":execute" と組み合わせてください。
例:

        :execute "normal " .. normal_commands

変数 "normal_commands" にはノーマルモードコマンドを入れておく必要があります。
":normal" には完結したコマンドを指定するようにしてください。引数が最後まで実行
された段階でコマンドは中断されます。例えば、挿入モードを開始した場合は挿入モー
ドを終了しなくてはなりません。次のコマンドは正しく動作します:

        :execute "normal Inew text \<Esc>"

これは現在行に "new text" を挿入します。特殊キー "\<ESC>" を使っていることに注
目してください。これによりスクリプトの中で本物の <Esc> 文字を使わないですみま
す。

文字列を実行するのではなく、その式の値を得たい場合は、eval() 関数を使います:

        :let optname = "path"
        :let optval = eval('&' .. optname)

文字 "&" と "path" を連結しているので eval() の引数は "&path" になります。戻り
値は 'path' オプションの値です。
次のようにすることもできます:
        :exe 'let optval = &' .. optname

==============================================================================
41.6  関数を使う

たくさんの関数があらかじめ定義され、豊富な機能が提供されています。このセクショ
ンの説明にもいくつか登場します。関数の一覧は functions を参照してください。

関数は ":call" コマンドで呼び出します。引数はカッコで囲み、それぞれをコンマで
区切ります。例:

        :call search("Date: ", "W")

これは "Date: " と "W" を引数にして search() 関数を呼び出しています。search()
関数は一つ目の引数を検索パターンとして使い、二つ目の引数をフラグとして使いま
す。"W" フラグを指定するとファイル末尾で検索が終了します (折り返さない)。

関数は式の中で使うこともできます。例:

        :let line = getline(".")
        :let repl = substitute(line, '\a', "*", "g")
        :call setline(".", repl)

getline() 関数はカレントバッファから行を取得する関数です。引数には行番号を指定
します。この例では "." ですが、これはカーソルのある行を示します。
substitute() 関数は ":substitute" コマンドとほぼ同じです。最初の引数は置換対象
の文字列、二つ目の引数はパターン、三つ目は置き換え文字列、最後はフラグです。
setline() 関数は行の内容を置き換えます。最初の引数は行番号、二つ目の引数は置き
換える文字列です。この例では、substitute() の結果で現在行を置き換えています。
上記の三行のコマンドは次のコマンドと同じことをしています:

        :substitute/\a/*/g

substitute() の呼び出しの前後にいろいろな処理を入れたりするときに、関数を使え
ばもっと面白いことができるようになります。


関数一覧                                                function-list
--------

たくさんの関数があります。ここでは機能別に分類して紹介します。アルファベット順
の一覧は functions を参照してください。関数の名前の上で CTRL-] を押すと、詳
細な説明にジャンプできます。

文字列繰作:                                             string-functions
        nr2char()               数値から文字を得る
        list2str()              数値のリストから文字列を得る
        char2nr()               文字の数値を得る
        str2list()              文字列から数値のリストを得る
        str2nr()                文字列を数値に変換する
        str2float()             文字列を浮動小数点数に変換する
        printf()                書式付き文字列を整形する
        escape()                文字列の特定の文字を '\' でエスケープ
        shellescape()           シェルコマンドで使えるように文字列をエスケープ
        fnameescape()           Vim コマンド用にファイル名をエスケープ
        tr()                    ある文字の集合から別の文字の集合へ置換する
        strtrans()              文字列を印字可能な状態とする
        tolower()               文字列を小文字にする
        toupper()               文字列を大文字にする
        charclass()             文字のクラス
        match()                 文字列の中でパターンにマッチした位置
        matchend()              文字列の中でパターンにマッチした末尾の位置
        matchfuzzy()            リスト内の文字列についてファジーマッチした文字列
        matchfuzzypos()         リスト内の文字列についてファジーマッチした文字列
        matchstr()              文字列の中でパターンにマッチした文字列
        matchstrpos()           文字列の中でパターンにマッチした文字列と位置
        matchlist()             matchstr()と同様だが、部分マッチも返す
        stridx()                文字列の中で部分文字列が見つかった最初の位置
        strridx()               文字列の中で部分文字列が見つかった最後の位置
        strlen()                文字列のバイト単位での長さ
        strcharlen()            文字列の文字単位での長さ
        strchars()              文字列内の文字数
        strwidth()              表示された文字列のサイズ
        strdisplaywidth()       表示された文字列のサイズ、タブを扱う
        setcellwidths()         文字の幅の上書き設定
        substitute()            パターンにマッチする文字列を置換
        submatch()              ":s" と substitute() の中で部分マッチを得る
        strpart()               文字列の一部分を得る(バイト数指定)
        strcharpart()           文字のインデックスで指定された部分文字列を得る
        slice()                 Vim9 script での文字インデックスを用いて、文字
                                列のスライスを取る
        strgetchar()            文字のインデックスで指定された文字コードを得る
        expand()                特殊キーワードを展開する
        expandcmd()             :edit のようにコマンドを展開する
        iconv()                 テキストのエンコーディングを変換する
        byteidx()               文字列中の文字のバイトインデックス
        byteidxcomp()           byteidx() と同様だが合成文字を数に入れる
        charidx()               文字列中のバイト値の文字インデックス
        repeat()                文字列を複数回繰り返す
        eval()                  文字列を式として評価する
        execute()               Ex コマンドを実行し出力を得る
        win_execute()           execute() に似ているが指定ウィンドウで実行する
        trim()                  文字列から文字を取り除く
        gettext()               翻訳メッセージの検索

リスト操作:                                             list-functions
        get()                   要素を取得。存在しないインデックスでもエラーを
                                出さない
        len()                   リスト中の要素の個数
        empty()                 リストが空であるか判定する
        insert()                リストの任意の位置に要素を挿入する
        add()                   リストに要素を追加する
        extend()                リストにリストを連結する
        extendnew()             あるリストとリストを結合して新しいリストを作成
                                する
        remove()                リストから1個以上の要素を取り除く
        copy()                  リストの浅いコピーを作成する
        deepcopy()              リストの完全なコピーを作成する
        filter()                リストから選択された要素を取り除く
        map()                   リストの各要素を変換する
        mapnew()                変換した要素で新しいリストを作成する
        reduce()                リストの畳み込みの値を算出する
        slice()                 リストのスライスを取る
        sort()                  リストをソートする
        reverse()               リストの並び順を反転させる
        uniq()                  隣接して繰り返される要素のコピーを削除する
        split()                 文字列を分割し、リストにする
        join()                  リストの要素を連結し、文字列にする
        range()                 数列リストを返す
        string()                リストの文字列表現
        call()                  リストを引数として関数を呼ぶ
        index()                 リスト中の要素のインデックス
        max()                   リスト中の最大値
        min()                   リスト中の最小値
        count()                 ある要素がリスト中に出現する回数を返す
        repeat()                リストを複数回繰り返す
        flatten()               リストの平坦化
        flattennew()            リストのコピーを平坦化

辞書操作:                                               dict-functions
        get()                   辞書の要素を返す。存在しないキーでもエラーを出
                                さない
        len()                   辞書の要素の個数
        has_key()               あるキーが辞書に含まれているか判定する
        empty()                 辞書が空であるか判定する
        remove()                辞書から要素を取り除く
        extend()                ある辞書の要素をすべて別の辞書に追加する
        extendnew()             ある辞書の要素と別の辞書を合せて新しい辞書を作
                                成する
        filter()                辞書から選択された要素を取り除く
        map()                   辞書の各要素を変換する
        mapnew()                変換した要素で新しい辞書を作成する
        keys()                  辞書の全キーのリストを取得する
        values()                辞書の全値のリストを取得する
        items()                 辞書の全キー・値のペアを取得する
        copy()                  辞書の浅いコピーを作成する
        deepcopy()              辞書の完全なコピーを作成する
        string()                辞書の文字列表現
        max()                   辞書中の最大値
        min()                   辞書中の最小値
        count()                 ある値が出現する回数を返す

浮動小数点数の計算:                                     float-functions
        float2nr()              Float を Number に変換
        abs()                   絶対値 (Numberも処理可能)
        round()                 丸め
        ceil()                  切り上げ
        floor()                 切り下げ
        trunc()                 小数点以下切り捨て
        fmod()                  除法の余り
        exp()                   指数
        log()                   自然対数 (eを底とする対数)
        log10()                 10 を底とする対数
        pow()                   x の y 乗
        sqrt()                  平方根
        sin()                   正弦 (サイン)
        cos()                   余弦 (コサイン)
        tan()                   正接 (タンジェント)
        asin()                  逆正弦 (アークサイン)
        acos()                  逆余弦 (アークコサイン)
        atan()                  逆正接 (アークタンジェント)
        atan2()                 逆正接 (アークタンジェント)
        sinh()                  双曲線正弦 (ハイパボリックサイン)
        cosh()                  双曲線余弦 (ハイパボリックコサイン)
        tanh()                  双曲線正接 (ハイパボリックタンジェント)
        isinf()                 無限大かのチェック
        isnan()                 数値でないかどうかのチェック

Blob 操作:                                              blob-functions
        blob2list()             blobから数値のリストを取得する
        list2blob()             数値のリストからblobを取得する

その他の計算:                                           bitwise-function
        and()                   ビットごとの論理積
        invert()                ビットごとの否定
        or()                    ビットごとの論理和
        xor()                   ビットごとの排他的論理和
        sha256()                SHA-256 ハッシュ
        rand()                  疑似乱数を得る
        srand()                 rand() を使うためのシード値の初期化

変数:                                                   var-functions
        type()                  数値による変数の型
        typename()              テキストによる変数の型
        islocked()              変数がロックされているか判定する
        funcref()               関数参照へのFuncrefを取得する
        function()              関数名からFuncrefを取得する
        getbufvar()             指定バッファの変数値を得る
        setbufvar()             指定バッファに変数を設定する
        getwinvar()             指定ウィンドウの変数値を得る
        gettabvar()             指定タブページから変数値を得る
        gettabwinvar()          指定ウィンドウ・タブページから変数値を取得する
        setwinvar()             指定ウィンドウに変数を設定する
        settabvar()             指定タブページに変数を設定する
        settabwinvar()          指定ウィンドウ・タブページに変数を設定する
        garbagecollect()        解放可能なメモリを解放する

カーソルとマークの位置:                 cursor-functions mark-functions
        col()                   カーソルやマークの列番号を取得する
        virtcol()               カーソルやマークの画面上の列番号を得る
        line()                  カーソルやマークの行番号を取得する
        wincol()                カーソルのウィンドウでの列番号
        winline()               カーソルのウィンドウでの行番号
        cursor()                カーソルを指定した位置に移動させる
        screencol()             カーソルのスクリーン列を取得する
        screenrow()             カーソルのスクリーン行を取得する
        screenpos()             テキスト文字のスクリーン行と列
        getcurpos()             カーソルの位置を取得する
        getpos()                カーソルやマークなどの位置を取得する
        setpos()                カーソルやマークなどの位置を設定する
        getmarklist()           グローバル/ローカルのマークのリスト
        byte2line()             指定のバイト位置の行番号を取得する
        line2byte()             指定の行のバイト位置を取得する
        diff_filler()           ある行より上の詰め行の数を取得する
        screenattr()            スクリーン列/行の属性を取得する
        screenchar()            スクリーン列/行の文字コードを取得する
        screenchars()           スクリーン列/行の文字コードのリストを取得する
        screenstring()          スクリーン列/行の文字列を取得する
        charcol()               カーソルもしくはマークにある文字の数値
        getcharpos()            カーソル、マーク、その他の位置の文字の取得
        setcharpos()            カーソル、マーク、その他の位置の文字の設定
        getcursorcharpos()      カーソル位置の文字の取得
        setcursorcharpos()      カーソル位置の文字の設定

カレントバッファで動作するもの:                         text-functions
        getline()               バッファから行を得る
        setline()               バッファの行を置き換える
        append()                行または行のリストをバッファに追加する
        indent()                行のインデントを得る
        cindent()               C 言語におけるインデントを得る
        lispindent()            Lisp 言語におけるインデントを得る
        nextnonblank()          次の非空行を探す
        prevnonblank()          前の非空行を探す
        search()                パターンにマッチする場所を探す
        searchpos()             パターンにマッチする場所を探す
        searchcount()           カーソルの前後でマッチした数を得る
        searchpair()            start/skip/end の対を探す
        searchpairpos()         start/skip/end の対を探す
        searchdecl()            名前が宣言されている場所を探す
        getcharsearch()         文字検索情報を返す
        setcharsearch()         文字検索情報を設定する

他のバッファのテキストで動作するもの:
        getbufline()            指定したバッファから行のリストを得る
        setbufline()            指定したバッファ内の行を置き換える
        appendbufline()         指定したバッファに行のリストを追加する
        deletebufline()         指定したバッファから行を削除する

                                        system-functions file-functions
システム関数とファイル繰作:
        glob()                  ワイルドカードを展開する
        globpath()              複数のディレクトリを対象にワイルドカードを展開
        glob2regpat()           glob パターンを正規表現に変換する
        findfile()              複数のディレクトリからファイルを探す
        finddir()               複数のディレクトリからディレクトリを探す
        resolve()               ショートカットのリンク先を得る
        fnamemodify()           ファイル名を修飾する
        pathshorten()           パス中のディレクトリ名を短くする
        simplify()              パスの意味を変えずに簡略化する
        executable()            実行形式ファイルかどうかをチェックする
        exepath()               実行ファイルのフルパスを得る
        filereadable()          ファイルが読み込み可能かどうかをチェックする
        filewritable()          ファイルが書き込み可能かどうかをチェックする
        getfperm()              ファイルのパーミッションを得る
        setfperm()              ファイルのパーミッションを設定する
        getftype()              ファイルの種類を得る
        isdirectory()           ディレクトリの存在をチェックする
        getfsize()              ファイルのサイズを得る
        getcwd()                カレントディレクトリを得る
        haslocaldir()           カレントウィンドウが :lcd または :tcd を使
                                用したかどうかをチェックする
        tempname()              一時ファイルの名前を得る
        mkdir()                 ディレクトリを作成する
        chdir()                 現在の作業ディレクトリを変更する
        delete()                ファイルを削除する
        rename()                ファイルの名前を変更する
        system()                シェルコマンドを実行し、その結果を文字列で得る
        systemlist()            シェルコマンドを実行し、その結果をリストで得る
        environ()               すべての環境変数を得る
        getenv()                環境変数を得る
        setenv()                環境変数を設定する
        hostname()              システムの名称を得る
        readfile()              ファイルを読み込み、行のリストを得る
        readblob()              ファイルを読み込み、Blobに格納する
        readdir()               ディレクトリ内のファイル名のリストを得る
        readdirex()             ディレクトリ内のファイル情報のリストを得る
        writefile()             行のリストまたは Blob をファイルに書き込む

日付と時刻:                             date-functions time-functions
        getftime()              ファイルの最終更新日時を得る
        localtime()             現在時刻を秒単位で得る
        strftime()              時刻を文字列に変換する
        strptime()              日付/時刻の文字列を時刻に変換する
        reltime()               現在時刻または経過時間を正確に取得する
        reltimestr()            reltime()の結果を文字列に変換する
        reltimefloat()          reltime()の結果を浮動小数点に変換する

                        buffer-functions window-functions arg-functions
バッファ、ウィンドウ、引数リスト:
        argc()                  引数リストの大きさ
        argidx()                引数リスト中の現在の位置
        arglistid()             引数リストのIDを得る
        argv()                  引数リストの中身を得る
        bufadd()                バッファのリストにファイルを追加する
        bufexists()             バッファの存在をチェックする
        buflisted()             バッファが存在し、リストされているかどうか
        bufload()               バッファがロードされていることを保証する
        bufloaded()             バッファが存在し、ロードされているかどうか
        bufname()               バッファの名前を得る
        bufnr()                 バッファの番号を得る
        tabpagebuflist()        タブページ中のバッファのリストを返す
        tabpagenr()             タブページの番号を取得する
        tabpagewinnr()          タブページを対象にwinnr()と同様
        winnr()                 カレントウィンドウの番号を得る
        bufwinid()              バッファのウィンドウIDを得る
        bufwinnr()              バッファのウィンドウ番号を得る
        winbufnr()              ウィンドウのバッファ番号を得る
        listener_add()          変更を監視するためのコールバックを追加する
        listener_flush()        リスナーコールバックを呼び出す
        listener_remove()       リスナーコールバックを削除する
        win_findbuf()           バッファが含まれるウィンドウを探す
        win_getid()             ウィンドウのウィンドウIDを得る
        win_gettype()           ウィンドウの種別を得る
        win_gotoid()            IDで指定されたウィンドウへ移動する
        win_id2tabwin()         IDで指定されたタブとウィンドウの番号を得る
        win_id2win()            IDで指定されたウィンドウの番号を得る
        win_splitmove()         分割したもう片方へウィンドウを移動する
        getbufinfo()            バッファの情報一覧を得る
        gettabinfo()            タブページの情報一覧を得る
        getwininfo()            ウィンドウの情報一覧を得る
        getchangelist()         変更リストのエントリ一覧を得る
        getjumplist()           ジャンプリストのエントリ一覧を得る
        swapinfo()              スワップファイルの情報を得る
        swapname()              バッファのスワップファイルパスを得る

コマンドライン:                                 command-line-functions
        getcmdline()            現在のコマンドラインを取得
        getcmdpos()             コマンドラインにおけるカーソル位置を取得
        setcmdpos()             コマンドラインにおけるカーソル位置を設定
        getcmdtype()            現在のコマンドラインの種類を返す
        getcmdwintype()         現在のコマンドラインウィンドウの種類を返す
        getcompletion()         マッチするコマンド補完リストを返す
        fullcommand()           完全なコマンド名の取得

Quickfixとlocationリスト:                       quickfix-functions
        getqflist()             quickfixエラーのリスト
        setqflist()             quickfixを変更する
        getloclist()            locationリストの項目のリスト
        setloclist()            locationリストを変更する

挿入モード補完:                                 completion-functions
        complete()              補完候補を設定する
        complete_add()          補完候補を追加する
        complete_check()        補完処理を終えるべきかどうかをチェックする
        complete_info()         現在の補完情報を得る
        pumvisible()            ポップアップメニューが表示されているかチェック
        pum_getpos()            表示されているポップアップメニューの位置とサイ
                                ズを得る

折り畳み:                                       folding-functions
        foldclosed()            行が折り畳まれているかどうかをチェックする
        foldclosedend()         foldclosed()と同様。折り畳み末尾の行番号を返す
        foldlevel()             行の折り畳みレベルを得る
        foldtext()              閉じた折り畳みを代替表示するテキストを生成
        foldtextresult()        閉じた折り畳みを代替表示するテキストを得る

シンタックスハイライト:           syntax-functions highlighting-functions
        clearmatches()          matchadd():matchコマンドで定義されたマッ
                                チをクリアする
        getmatches()            matchadd():matchコマンドで定義されたすべ
                                てのマッチを得る
        hlexists()              ハイライトグループの存在をチェック
        hlget()                 ハイライトグループの属性を取得する
        hlset()                 ハイライトグループの属性を設定する
        hlID()                  ハイライトグループのIDを得る
        synID()                 指定位置のシンタックスIDを得る
        synIDattr()             シンタックスIDから指定の属性を得る
        synIDtrans()            変換したシンタックスIDを得る
        synstack()              指定位置のシンタックスIDのリストを得る
        synconcealed()          conceal の情報を得る
        diff_hlID()             差分モードの指定位置のシンタックスIDを得る
        matchadd()              強調表示するパターンを定義する
        matchaddpos()           強調表示する位置のリストを定義する
        matcharg()              :matchの引数の情報を得る
        matchdelete()           matchadd():matchコマンドで定義されたマッ
                                チを削除する
        setmatches()            getmatches()で得たマッチを使って復元する

スペリング:                                     spell-functions
        spellbadword()          カーソル位置以降のスペルミスを探す
        spellsuggest()          スペル訂正の候補を返す
        soundfold()             単語の同音等値(sound-a-like equivalent)を返す

履歴:                                           history-functions
        histadd()               履歴に項目を追加
        histdel()               履歴から項目を削除
        histget()               履歴の項目を得る
        histnr()                履歴リストの最大インデックスを得る

対話インターフェイス:                           interactive-functions
        browse()                ファイル選択ダイアログを開く
        browsedir()             ディレクトリ選択ダイアログを開く
        confirm()               ユーザーに選択をさせる
        getchar()               ユーザーが入力した文字を得る
        getcharstr()            ユーザーが入力した文字を文字列として得る
        getcharmod()            最後に入力した文字の修飾子(modifier)を得る
        getmousepos()           最後に取得したマウスの位置を得る
        echoraw()               文字をそのまま出力する
        feedkeys()              先行入力キューに文字を入れる
        input()                 ユーザーが入力した行を得る
        inputlist()             ユーザーにリストから項目を選択させる
        inputsecret()           ユーザーが入力した行を得る。ただし表示はしない
        inputdialog()           ダイアログを使ってユーザーが入力した行を得る
        inputsave()             先行入力キューを保存して空にする
        inputrestore()          inputsave()で保存した状態に戻す

GUI:                                            gui-functions
        getfontname()           現在使われているフォントの名前を取得
        getwinpos()             Vimウィンドウの座標
        getwinposx()            VimウィンドウのX座標
        getwinposy()            VimウィンドウのY座標
        balloon_show()          バルーンの内容を設定する
        balloon_split()         バルーン用にメッセージを分割する
        balloon_gettext()       バルーンのテキストを得る

Vimサーバー:                                    server-functions
        serverlist()            サーバー名のリストを返す
        remote_startserver()    サーバーをスタートする
        remote_send()           Vimサーバーにコマンド文字を送る
        remote_expr()           Vimサーバーで式を評価する
        server2client()         Vimサーバーのクライアントに応答を返す
        remote_peek()           Vimサーバーから返信があったかどうかをチェック
        remote_read()           Vimサーバーからの返信を読む
        foreground()            Vimのウィンドウを前面に持ってくる
        remote_foreground()     Vimサーバーのウィンドウを前面に持ってくる

ウィンドウサイズと位置:                         window-size-functions
        winheight()             ウィンドウの高さを取得
        winwidth()              ウィンドウの幅を取得
        win_screenpos()         ウィンドウのスクリーン座標を取得
        winlayout()             タブページ内のウィンドウ配置を取得
        winrestcmd()            ウィンドウサイズを復元するコマンドを返す
        winsaveview()           カレントウィンドウのビューを取得
        winrestview()           カレントウィンドウのビューを復元

マッピングとメニュー:                           mapping-functions
        digraph_get()           digraph の取得
        digraph_getlist()       全 digraph の取得
        digraph_set()           digraph の登録
        digraph_setlist()       複数 digraph の登録
        hasmapto()              マップの存在をチェック
        mapcheck()              マッチするマップの存在をチェック
        maparg()                マップのrhs(展開結果)を得る
        mapset()                マップを復元
        menu_info()             メニュー項目の情報を取得
        wildmenumode()          wildmodeが有効かどうかをチェック

テスト用:                                       test-functions
        assert_equal()          2つの式が等しい事をテストする
        assert_equalfile()      2つのファイルの内容が等しい事をテストする
        assert_notequal()       2つの式が等しくない事をテストする
        assert_inrange()        式が範囲内にある事をテストする
        assert_match()          値がパターンにマッチする事をテストする
        assert_notmatch()       値がパターンにマッチしない事をテストする
        assert_false()          式がfalseかどうかテストする
        assert_true()           式がtrueかどうかテストする
        assert_exception()      コマンドが例外を投げる事をテストする
        assert_beeps()          コマンドがビープ音を鳴らすことをテストする
        assert_nobeep()         コマンドがビープ音を鳴らさないことをテストする
        assert_fails()          コマンドが失敗する事をテストする
        assert_report()         テストの失敗をレポートする
        test_alloc_fail()       メモリの確保を失敗させる
        test_autochdir()        起動中に 'autochdir' を有効にする
        test_override()         Vimの内部処理を置き換えてテストする
        test_garbagecollect_now()   直ちにメモリを解放する
        test_garbagecollect_soon()  メモリを解放のフラグを設定する
        test_getvalue()         内部変数の値を取得する
        test_gui_drop_files()   ウィンドウにファイルをドロップする
        test_gui_mouse_event()  インプットバッファにGUIマウスイベントを追加する
        test_ignore_error()     特定のエラーメッセージを無視する
        test_null_blob()        null の Blob を返す
        test_null_channel()     null のチャネルを返す
        test_null_dict()        null の辞書を返す
        test_null_function()    null の Funcref を返す
        test_null_job()         null の Job を返す
        test_null_list()        null のリストを返す
        test_null_partial()     null の部分適用を返す
        test_null_string()      null の文字列を返す
        test_settime()          Vimが内部的に用いる時間を設定する
        test_setmouse()         マウスの位置を設定する
        test_feedinput()        インプットバッファにキーシーケンスを追加する
        test_option_not_set()   オプションが設定されていることを示すフラグをリ
                                セットする
        test_scrollbar()        GUIでスクロールバーの動きをシミュレートする
        test_refcount()         式の参照カウントを返す
        test_srand_seed()       srand() のテスト用の種を設定する
        test_unknown()          unknown 型の値を返す
        test_void()             void 型の値を返す

プロセス間通信:                                 channel-functions
        ch_canread()            何か読むものがあるかチェックする
        ch_open()               チャネルを開く
        ch_close()              チャネルを閉じる
        ch_close_in()           チャネルの入力パートを閉じる
        ch_read()               チャネルからメッセージを読み取る
        ch_readblob()           チャネルから Blob を読み取る
        ch_readraw()            チャネルからrawメッセージを読み取る
        ch_sendexpr()           チャネルにJSONメッセージを送る
        ch_sendraw()            チャネルにrawメッセージを送る
        ch_evalexpr()           チャネル経由で式を評価する
        ch_evalraw()            チャネル経由で raw 文字列を評価する
        ch_status()             チャネルの状態を取得する
        ch_getbufnr()           チャネルのバッファ番号を取得する
        ch_getjob()             チャネルが割り当てられている Job を取得する
        ch_info()               チャネルの情報を取得する
        ch_log()                チャネルのログファイルにメッセージを出力する
        ch_logfile()            チャネルのログファイルを設定する
        ch_setoptions()         チャネルのオプションを設定する
        json_encode()           式をJSONの文字列にエンコードする
        json_decode()           JSONの文字列をVimの型にデコードする
        js_encode()             式をJSONの文字列にエンコードする
        js_decode()             JSONの文字列をVimの型にデコードする

ジョブ:                                         job-functions
        job_start()             Job を開始する
        job_stop()              Job を停止する
        job_status()            Job のステータスを取得する
        job_getchannel()        Job が使用する channel を取得する
        job_info()              Job の情報を取得する
        job_setoptions()        Job のオプションを設定する

目印:                                           sign-functions
        sign_define()           目印を定義または更新する
        sign_getdefined()       定義されている目印のリストを取得する
        sign_getplaced()        設置されている目印のリストを取得する
        sign_jump()             目印へ移動する
        sign_place()            目印を設置する
        sign_placelist()        目印のリストを設置する
        sign_undefine()         定義された目印を削除する
        sign_unplace()          設置された目印を解除する
        sign_unplacelist()      設置された目印のリストを解除する

端末ウィンドウ:                                 terminal-functions
        term_start()            端末ウィンドウを開いてジョブを開始する
        term_list()             端末バッファのリストを取得する
        term_sendkeys()         端末にキーストロークを送る
        term_wait()             スクリーンがアップデートされるのを待つ
        term_getjob()           端末に関連するジョブを取得する
        term_scrape()           端末スクリーンの列を取得する
        term_getline()          端末からテキストの行を取得する
        term_getattr()          {what} の属性値を取得する
        term_getcursor()        端末のカーソル位置を取得する
        term_getscrolled()      端末のスクロール数を取得する
        term_getaltscreen()     代替のスクリーンフラグを取得する
        term_getsize()          端末のサイズを取得する
        term_getstatus()        端末のステータスを取得する
        term_gettitle()         端末のタイトルを取得する
        term_gettty()           端末の tty 名を取得する
        term_setansicolors()    GUI で使用される 16 色の ANSI カラーパレットを
                                設定する
        term_getansicolors()    GUI で使用される 16 色の ANSI カラーパレットを
                                取得する
        term_dumpdiff()         2つの画面ダンプ間の差分を表示する
        term_dumpload()         ウィンドウに端末スクリーンダンプを読み込む
        term_dumpwrite()        端末スクリーンの内容をファイルにダンプする
        term_setkill()          端末内のジョブを停止するシグナルを設定する
        term_setrestore()       端末を復元させるためのコマンドを設定する
        term_setsize()          端末のサイズを設定する
        term_setapi()           端末の JSON API 関数名のプリフィックスを設定す
                                る

ポップアップウィンドウ:                         popup-window-functions
        popup_create()          画面中央にポップアップを作成する
        popup_atcursor()        カーソル位置のすぐ上にポップアップを作成する、
                                カーソルが離れると閉じる
        popup_beval()           v:beval_ 変数によって示される位置、
                                マウスが離れると閉じる
        popup_notification()    3秒間通知を表示する
        popup_dialog()          パディングとボーダー付きで中央にポップアップを
                                作成する
        popup_menu()            リストから項目を選択するためのプロンプト
        popup_hide()            ポップアップを一時的に隠す
        popup_show()            以前に隠されたポップアップを表示する
        popup_move()            ポップアップの位置とサイズを変更する
        popup_setoptions()      ポップアップのオプションを上書きする
        popup_settext()         ポップアップバッファの内容を置き換える
        popup_close()           1つのポップアップを閉じる
        popup_clear()           全てのポップアップを閉じる
        popup_filter_menu()     リストの項目から選択する
        popup_filter_yesno()    'y' か 'n' が押されるまでブロックする
        popup_getoptions()      ポップアップの現在のオプションを取得する
        popup_getpos()          ポップアップの実際の位置とサイズを取得する
        popup_findinfo()        ポップアップ情報ウィンドウのウィンドウIDを取得
                                する
        popup_findpreview()     ポップアッププレビューウィンドウのウィンドウID
                                を取得する
        popup_list()            全ポップアップのウィンドウIDのリストを取得する
        popup_locate()          スクリーン上の指定の位置にあるポップアップの
                                ウィンドウIDを取得する

タイマー:                                       timer-functions
        timer_start()           タイマーを作る
        timer_pause()           タイマーを一時停止もしくは再開する
        timer_stop()            タイマーを止める
        timer_stopall()         全てのタイマーを止める
        timer_info()            タイマーの情報を得る
タグ:                                           tag-functions
        taglist()               マッチするタグのリストを取得する
        tagfiles()              タグファイルのリストを取得する
        gettagstack()           ウィンドウのタグスタックを取得する
        settagstack()           ウィンドウのタグスタックを変更する

プロンプトバッファ:                             promptbuffer-functions
        prompt_getprompt()      バッファで使われているプロンプトテキストを取得
                                する
        prompt_setcallback()    バッファのプロンプトコールバックを設定する
        prompt_setinterrupt()   バッファの割り込みコールバックを設定する
        prompt_setprompt()      バッファのプロンプトテキストを設定する

テキストプロパティ:                             text-property-functions
        prop_add()              指定位置にプロパティを付加する
        prop_add_list()         複数の指定位置にプロパティを付加する
        prop_clear()            指定行からプロパティをすべて削除する
        prop_find()             プロパティを検索する
        prop_list()             指定行のすべてのプロパティのリストを返す
        prop_remove()           指定行からプロパティを削除する
        prop_type_add()         プロパティタイプの追加/定義
        prop_type_change()      プロパティタイプの変更
        prop_type_delete()      テキストのプロパティタイプの削除
        prop_type_get()         プロパティタイプのプロパティを返す
        prop_type_list()        すべてのプロパティタイプをリストで返す

サウンド:                                       sound-functions
        sound_clear()           再生している全サウンドを停止する
        sound_playevent()       イベントサウンドを再生する
        sound_playfile()        サウンドファイルを再生する
        sound_stop()            サウンドの再生を停止する

その他:                                         various-functions
        mode()                  現在の編集モードを得る
        state()                 現在のビジー状態を得る
        visualmode()            最後に使われたビジュアルモードの種類
        exists()                変数、関数の存在をチェック
        exists_compiled()       exists() と同様だが、コンパイル時にチェック
        has()                   機能がサポートされているかをチェック
        changenr()              最近の変更番号を返す
        cscope_connection()     cscope接続をチェック
        did_filetype()          FileType自動コマンドが使用されたかどうか
        eventhandler()          イベントハンドラによって起動されたかどうか
        getpid()                Vim のプロセスIDを得る
        getimstatus()           IME のステータスがアクティブかをチェック
        interrupt()             スクリプトの実行を中断する
        windowsversion()        MS-Windows バージョンの取得
        terminalprops()         端末の属性

        libcall()               外部ライブラリの関数を呼ぶ
        libcallnr()             同上、数値を返す

        undofile()              アンドゥファイルの名前を得る
        undotree()              アンドゥツリーの状態を返す

        getreg()                レジスタの値を得る
        getreginfo()            レジスタの情報を得る
        getregtype()            レジスタのタイプを得る
        setreg()                レジスタの値を設定する
        reg_executing()         実行中のレジスタ名を返す
        reg_recording()         記録中のレジスタ名を返す

        shiftwidth()            'shiftwidth' の実際の値

        wordcount()             バッファ内のバイト数/単語数/文字数などを得る

        luaeval()               Luaの式を評価する
        mzeval()                MzScheme の式を評価する
        perleval()              Perlの式を評価する (+perl)
        py3eval()               Pythonの式を評価する (+python3)
        pyeval()                Pythonの式を評価する (+python)
        pyxeval()               python_x の式を評価する
        rubyeval()              Ruby の式を評価する

        debugbreak()            デバッグ中のプログラムを中断する

==============================================================================
41.7  関数を定義する

自分で関数を定義することができます。基本的な関数定義は次のとおり:

        :function {name}({var1}, {var2}, ...)
        :  {body}
        :endfunction

        Note:
        関数名は大文字で開始する必要があります。

小さな関数を定義してみましょう。二つの数値のうち小さい方を返す関数を作ります。
関数は次のような行で始まります:

        :function Min(num1, num2)

関数の名前が "Min" であり、二つの引数 ("num1" と "num2") を取る、ということを
表しています。
最初にしなければならないのは、どちらの数値が小さいかをチェックすることです:

        :  if a:num1 < a:num2

"a:" は特殊なプリフィックスで、この変数が関数の引数であることを示します。小さ
い方の値を変数 "smaller" に代入しましょう:

        :  if a:num1 < a:num2
        :    let smaller = a:num1
        :  else
        :    let smaller = a:num2
        :  endif

変数 "smaller" はローカル変数です。関数の中で使われた変数はローカル変数になり
ます。ただし、"g:"、"a:"、"s:" などのプリフィックスを付けた場合は別です。

        Note:
        関数の内からグローバル変数にアクセスするには "g:" を付ける必要がありま
        す。つまり、関数内では "g:today" はグローバル変数 "today" を示し、
        "today" ならそれとは別の変数、すなわちローカル変数になります。

":return" ステートメントを使って、小さい方の値を呼び出し元に返しましょう。そし
て、関数を閉じます:

        :  return smaller
        :endfunction

関数定義の全体は次のようになります:

        :function Min(num1, num2)
        :  if a:num1 < a:num2
        :    let smaller = a:num1
        :  else
        :    let smaller = a:num2
        :  endif
        :  return smaller
        :endfunction

関数を短く書きたい場合は、次のようにもできます:

        :function Min(num1, num2)
        :  if a:num1 < a:num2
        :    return a:num1
        :  endif
        :  return a:num2
        :endfunction

ユーザー定義関数は組み込み関数とまったく同じ方法で呼び出すことができます。違う
のは名前だけです。Min 関数は次のように使用できます:

        :echo Min(5, 8)

関数が実行され、関数の中身が Vim によって解釈されます。未定義の変数や関数を使
うなどの間違いがあったときは、エラーメッセージが表示されます。関数定義の時点で
はそれらのエラーは検出されません。

関数が ":endfunction" まで実行されたとき、あるいは引数無しで ":return" を使っ
たときは 0 が返ります。

既存の関数を再定義したい場合は ":function" コマンドに "!" を付けてください:

        :function!  Min(num1, num2, num3)


範囲指定を使う
--------------

":call" コマンドは行範囲を受け取ることができます。範囲指定の使用方法は二つあり
ます。関数を定義するときに "range" キーワードを使った場合は、関数自身が範囲指
定を処理します。
関数には "a:firstline" と "a:lastline" という二つの変数が暗黙的に渡されます。
この二つの変数には範囲指定された行番号が代入されています。例:

        :function Count_words() range
        :  let lnum = a:firstline
        :  let n = 0
        :  while lnum <= a:lastline
        :    let n = n + len(split(getline(lnum)))
        :    let lnum = lnum + 1
        :  endwhile
        :  echo "found " .. n .. " words"
        :endfunction

この関数は次のように呼び出すことができます:

        :10,30call Count_words()

関数が一度だけ実行され、単語の数が表示されます。
関数を定義するときに "range" キーワードを使わなかった場合は、指定された範囲の
それぞれの行に対して関数が呼ばれます (カーソルはその行の上)。例:

        :function  Number()
        :  echo "line " .. line(".") .. " contains: " .. getline(".")
        :endfunction

次のように実行すると:

        :10,15call Number()

関数は 6 回実行されます。


可変長引数
----------

可変個の引数を取る関数を定義できます。例えば、次の関数は、必ず 1 つの引数
(start) を取り、最大で 20 個までの引数を取ることができます:

        :function Show(start, ...)

変数 "a:1" に 1 つ目のオプション引数が代入されます。2 つ目が "a:2" で、3 つ目
が "a:3" です。"a:0" にはオプション引数の数が入ります。
例:

        :function Show(start, ...)
        :  echohl Title
        :  echo "start is " .. a:start
        :  echohl None
        :  let index = 1
        :  while index <= a:0
        :    echo "  Arg " .. index .. " is " .. a:{index}
        :    let index = index + 1
        :  endwhile
        :  echo ""
        :endfunction

この関数は ":echohl" を使って ":echo" の出力に色を付けています。":echohl None"
で色付けをやめます。":echon" コマンドは ":echo" と同じ機能ですが、改行を出力し
ません。

変数 a:000 を使うこともできます。これは "..." 引数がすべて入ったリストです。
a:000を参照。


関数の一覧
----------

":function" コマンドでユーザー定義関数の一覧を表示できます:

        :function
        function Show(start, ...)
        function GetVimIndent()
        function SetSyn(name)

関数の中身を見たいときは関数名を指定してください:

        :function SetSyn
        1     if &syntax == ''
        2       let &syntax = a:name
        3     endif
           endfunction


デバッグ
--------

エラーメッセージが表示されたとき、あるいはデバッグ中に、行番号が表示されると便
利です。デバッグモードについては debug-scripts を参照してください。
'verbose' オプションに 12 以上の値を設定すると、すべての関数呼び出しが表示され
ます。15 以上にすると、実行されたすべての行が表示されます。


関数の削除
----------

例えば Show() 関数を削除するのは次のようにします:

        :delfunction Show

関数が存在しない場合はエラーになります。


関数への参照
------------

変数に関数を代入できると便利なことがあります。それには function() 関数を使いま
す。function() は関数の名前を受け取り、関数への参照を返します:

        :let result = 0         " or 1
        :function! Right()
        :  return 'Right!'
        :endfunc
        :function! Wrong()
        :  return 'Wrong!'
        :endfunc
        :
        :if result == 1
        :  let Afunc = function('Right')
        :else
        :  let Afunc = function('Wrong')
        :endif
        :echo call(Afunc, [])
        Wrong!

Note 関数への参照を保持する変数の名前は大文字で始めなければなりません。そうで
ないと組み込み関数の名前と紛らわしくなります。
変数が参照している関数を呼び出すには call() 関数を使います。call() 関数の最初
の引数は関数への参照で、2 番目の引数は引数のリストです。

関数への参照は、次節で説明される辞書と組み合わせたときもっとも役に立ちます。

あなたが定義した関数についての情報は: user-functions

==============================================================================
41.8  リストと辞書

ここまでは基本型(文字列と数値)を扱ってきました。Vim は二つの複合型、リストと辞
書もサポートしています。

リストとは、要素を順番に並べたものです。要素はどのような型でも構いません。数値
のリスト、リストのリスト、あるいは複数の型が混在したリストでも作れます。例え
ば、3 個の文字列からなるリストを作るには次のようにします:

        :let alist = ['aap', 'mies', 'noot']

リストの要素は角括弧で囲み、コンマで区切ります。空のリストを作るには次のように
します:

        :let alist = []

関数add()を使うとリストに要素を追加することができます:

        :let alist = []
        :call add(alist, 'foo')
        :call add(alist, 'bar')
        :echo alist
        ['foo', 'bar']

リストの連結には + を使います:

        :echo alist + ['foo', 'bar']
        ['foo', 'bar', 'foo', 'bar']

直接リストを拡張するには次のようにします:

        :let alist = ['one']
        :call extend(alist, ['two', 'three'])
        :echo alist
        ['one', 'two', 'three']

add()とは効果が異なることに注意してください:

        :let alist = ['one']
        :call add(alist, ['two', 'three'])
        :echo alist
        ['one', ['two', 'three']]

add()の第二引数は1つの要素として追加されます。


FOR ループ
----------

リストを使ってできる素晴らしいことの1つが、リストに対する繰り返しです:

        :let alist = ['one', 'two', 'three']
        :for n in alist
        :  echo n
        :endfor
        one
        two
        three

上の例は、リスト "alist" の各要素に対して、その値を変数 "n" に代入しながらルー
プを行います。forループの書式は次の通りです:

        :for {varname} in {listexpression}
        :  {commands}
        :endfor

ある回数だけループするには、その長さのリストを使います。関数range()を使うと、
そのようなリストを作成できます:

        :for a in range(3)
        :  echo a
        :endfor
        0
        1
        2

range()が生成するリストの最初の要素は0であることに注意してください。そのため、
最後の要素はリストの長さより1小さい値になります。
最大値、ステップ幅を指定することもでき、逆方向に進むこともできます:

        :for a in range(8, 4, -2)
        :  echo a
        :endfor
        8
        6
        4

より有用な例として、バッファ中の行に対するループ:

        :for line in getline(1, 20)
        :  if line =~ "Date: "
        :    echo matchstr(line, 'Date: \zs.*')
        :  endif
        :endfor

1行目から20行目(両端を含む)を調べ、そこに含まれる日付を全て表示しています。


辞書
-----

辞書はキーと値のペアを保持します。キーを指定することで高速に値を検索できます。
辞書は波括弧で作ります:

        :let uk2nl = {'one': 'een', 'two': 'twee', 'three': 'drie'}

そして角括弧の中にキーを書くことで単語を検索します:

        :echo uk2nl['two']
        twee

辞書の定義の書式は次の通りです:

        {<key> : <value>, ...}

空の辞書とは、どんなキーも持たない辞書のことです:

        {}

辞書にはいろいろな使い道があります。辞書を扱う関数もたくさんあります。例えば、
キーのリストを取得してそれに対してループするには次のようにします:

        :for key in keys(uk2nl)
        :  echo key
        :endfor
        three
        one
        two

キーはソートされていません。特定の順序に並べるにはリストをソートします:

        :for key in sort(keys(uk2nl))
        :  echo key
        :endfor
        one
        three
        two

要素が定義された順序を得ることはできません。そのような目的にはリストを使ってく
ださい。リストは順序を保って要素を保持します。


辞書の関数
----------

辞書の要素は角括弧でインデックスを指定して取得します:

        :echo uk2nl['one']
        een

記号を使わない方法もあります:

        :echo uk2nl.one
        een

この方法はキーがアルファベット、数字、アンダースコアなどの ASCII 文字だけで構
成されている場合に使えます。この方法で値を代入することもできます:

        :let uk2nl.four = 'vier'
        :echo uk2nl
        {'three': 'drie', 'four': 'vier', 'one': 'een', 'two': 'twee'}

関数の定義と辞書への代入を同時に記述することができます:

        :function uk2nl.translate(line) dict
        :  return join(map(split(a:line), 'get(self, v:val, "???")'))
        :endfunction

これを実行してみましょう:

        :echo uk2nl.translate('three two five one')
        drie twee ??? een

":function" の行の末尾に "dict" と書かれています。これは、その関数が辞書から使
われることを示します。ローカル変数 "self" がその辞書を指すようになります。
次に、複雑なreturnコマンドを分解してみましょう:

        split(a:line)

関数split()は文字列を空白文字で区切り、リストにして返します。そのため、この例
での戻り値は次のようになります:

        :echo split('three two five one')
        ['three', 'two', 'five', 'one']

このリストがmap()関数の第一引数になります。map()はリストの各要素を "v:val" に
代入した状態で第二引数を評価します。これによりforループより短いコードが書けま
す。このコードは:

        :let alist = map(split(a:line), 'get(self, v:val, "???")')

次のコードと同じです:

        :let alist = split(a:line)
        :for idx in range(len(alist))
        :  let alist[idx] = get(self, alist[idx], "???")
        :endfor

関数get()はそのキーが辞書に入っているかをチェックします。入っていればその値を
返します。入っていなければデフォルト値(この例では '???')を返します。キーが入っ
ていなくてもエラーを起こしたくないような場合に便利です。

関数join()はsplit()の逆の処理をします。つまり単語のリストをスペースでつなげま
す。
split()、map()、join() を組み合わせると、単語からなる行を簡潔に処理することが
できます。


オブジェクト指向プログラミング
------------------------------

辞書には値と関数を入れることができるので、辞書をオブジェクトとして使うことがで
きます。
上述の例ではオランダ語から英語に翻訳するために辞書を使いました。同じことが他の
言語でもできると面白いかもしれませんね。まず翻訳関数を持ったオブジェクト (つま
り辞書) を作ります。翻訳する単語はまだ定義しません:

        :let transdict = {}
        :function transdict.translate(line) dict
        :  return join(map(split(a:line), 'get(self.words, v:val, "???")'))
        :endfunction

単語を翻訳するのに 'self.words' を使う点が上述の例と少し違います。しかし、
self.words はまだありません。よって、これは抽象クラスと呼ぶことができます。

オランダ語を翻訳するオブジェクトをインスタンス化してみましょう:

        :let uk2nl = copy(transdict)
        :let uk2nl.words = {'one': 'een', 'two': 'twee', 'three': 'drie'}
        :echo uk2nl.translate('three one')
        drie een

さらにドイツ語の翻訳機を作ります:

        :let uk2de = copy(transdict)
        :let uk2de.words = {'one': 'eins', 'two': 'zwei', 'three': 'drei'}
        :echo uk2de.translate('three one')
        drei eins

copy() 関数を使って "transdict" 辞書をコピーし、そのコピーに対して単語を追加し
ています。元の辞書はもちろん変更されません。

さらに一歩進んで、適切な言語を選択できるようにしてみます:

        :if $LANG =~ "de"
        :  let trans = uk2de
        :else
        :  let trans = uk2nl
        :endif
        :echo trans.translate('one two three')
        een twee drie

"trans" は2つのオブジェクト(辞書)のうちどちらか1つを参照します。コピーは作られ
ていません。リストと辞書の同一性についてのより詳しい情報はlist-identity
dict-identityにあります。

未対応の言語を使う場合は、translate() 関数を上書きして何もしないようにするとい
いかもしれません:

        :let uk2uk = copy(transdict)
        :function! uk2uk.translate(line)
        :  return a:line
        :endfunction
        :echo uk2uk.translate('three one wladiwostok')
        three one wladiwostok

! を使って既に存在している関数への参照を上書きしています。続いて、未対応の言語
に対して "uk2uk" を使うように変更します:

        :if $LANG =~ "de"
        :  let trans = uk2de
        :elseif $LANG =~ "nl"
        :  let trans = uk2nl
        :else
        :  let trans = uk2uk
        :endif
        :echo trans.translate('one two three')
        one two three

さらなる情報についてはListDictionariesを参照してください。

==============================================================================
41.9  例外

まずは例題を見てください:

        :try
        :   read ~/templates/pascal.tmpl
        :catch /E484:/
        :   echo "パスカル用のテンプレートファイルは見つかりませんでした。"
        :endtry

":read" コマンドはファイルがなければ失敗します。そのエラーをキャッチして、エ
ラーメッセージの代わりにより親切なメッセージを表示しています。

":try" と ":endtry" の間で起きたエラーは例外に変わります。例外は文字列です。エ
ラーが例外に変わったとき、文字列にはエラーメッセージが含まれます。また、全ての
エラーメッセージは番号を持っています。例題では "E484:" を含んだエラーをキャッ
チしています。この番号は変わらないことが保証されています (テキストは翻訳される
などして変わるかもしれません)。

":read" コマンドが他のエラーを起こした場合、"E484:" というパターンはマッチしな
いでしょう。したがって、その例外はキャッチされず、通常のエラーメッセージが表示
されます。

次のように書くこともできます:

        :try
        :   read ~/templates/pascal.tmpl
        :catch
        :   echo "パスカル用のテンプレートファイルは見つかりませんでした。"
        :endtry

全ての例外がキャッチされます。しかしこれでは "E21: Cannot make changes,
'modifiable' is off" のような有効なエラーに気づくことができません。

":finally" という便利なコマンドもあります:

        :let tmp = tempname()
        :try
        :   exe ".,$write " .. tmp
        :   exe "!filter " .. tmp
        :   .,$delete
        :   exe "$read " .. tmp
        :finally
        :   call delete(tmp)
        :endtry

カーソル行からファイル末尾までを "filter" コマンド (ファイル名を引数に取るコマ
ンド) でフィルタ処理しています。":try" と ":finally" の間で問題が起きても、
ユーザーが CTRL-C を押して操作をキャンセルしても、"call delete(tmp)" は必ず呼
ばれます。一時ファイルが残ってしまう心配はありません。

例外についてさらに詳しい情報はリファレンスマニュアルのexception-handling
参照してください。

==============================================================================
41.10 注意事項

Vim script において注意すべきことの概要を簡単に説明します。他の場所にも同じよ
うな説明はありますが、手頃なチェックリストに使えるでしょう。

改行記号はシステムによって異なります。Unix では <NL> 文字が使われますが、
MS-Windows などでは <CR><NL> が使われます。末尾が <CR> になっているマップを使
うときは注意してください。:source_crnl 参照。


空白
-----

空の行はあっても構いません。無視されます。

行頭の空白 (スペースとTAB) は常に無視されます。引数と引数の間には空白がいくつ
あっても構いません (例えば下記の "set" と "cpoptions" の間)。空白は一つのスペー
スにまとめられ、セパレータの役目をします。最後の文字より後ろにある空白文字は状
況によって無視されたりされなかったりします。下記参照。

":set" コマンドで "=" 記号を使うとき:

        :set cpoptions    =aABceFst

"=" の直前にある空白は無視されます。しかし、"=" の後ろに空白をはさむことはでき
ません。

オプション値に空白を含めるときは、バックスラッシュ ("\") でエスケープする必要
があります:

        :set tags=my\ nice\ file

次のように書くと:

        :set tags=my nice file

これはエラーになります。このコマンドは次のように解釈されてしまいます:

        :set tags=my
        :set nice
        :set file


コメント
--------

コメントは " (ダブルクォート) 記号で開始します。行末までのすべての文字がコメン
トとして解釈され、無視されます。ただし、コメントを書くことができないコマンドも
あります (以下に例を示します)。コメントは行のどこからでも開始できます。

コメントとして簡単な注釈を付けたとします。例:

        :abbrev dev development         " shorthand
        :map <F3> o#include             " insert include
        :execute cmd                    " do it
        :!ls *.c                        " list C files

短縮形 'dev' は 'development     " shorthand' に展開されます。<F3> には
'o#....' から '" insert include' までの全部がマップされます。"execute" コマン
ドはエラーを起こします。"!" コマンドはすべての文字をシェルに渡すので、" 記号が
閉じられていないことでエラーが起こります。
":map"、":abbreviate"、":execute"、"!" などのコマンドはその後ろにコメントを書
くことができません (そのようなコマンドは他にもあります)。ただし、無理やりコメ
ントを書く方法もあります:

        :abbrev dev development|" shorthand
        :map <F3> o#include|" insert include
        :execute cmd                    |" do it

'|' 文字でコマンドを区切り、次のコマンドを書くことができます。この例では二つ目
のコマンドはコメントのみです。"!" の場合は :execute と '|' を使わなければな
りません:
        :exe '!ls *.c'                  |" list C files

":map" と ":abbreviate" の場合は '|' の前に空白を置かないように注意してくださ
い。これらのコマンドは行末か '|' までのすべての文字を使います。そのため、意図
せずに末尾に空白を入れてしまうかもしれません:

        :map <F4> o#include

vimrc を編集するときに 'list' オプションをオンに設定しておくと、この問題が発見
しやすくなります。

Unix では特別なコメント書式を使って Vim script を実行形式にすることができま
す:
        #!/usr/bin/env vim -S
        echo "this is a Vim script"
        quit

"#" コマンドは行を行番号付きで表示しますが、'!' をつけると何もしなくなります。
よってファイルを実行するためのシェルコマンドを記述することができます。
:#! -S


落とし穴
--------

次の例には大きな問題があります:

        :map ,ab o#include
        :unmap ,ab

この unmap コマンドはうまく動きません。なぜなら ",ab " を unmap しようとしてい
るからです。そのようなマップは存在しません。エラーが表示されますが、スペースは
目に見えないので、エラーの原因を見つけるのは困難です。

":unmap" コマンドの後にコメントを書いた場合も同様です:

        :unmap ,ab     " comment

コメントは無視されますが、Vim は ',ab     ' を unmap しようとします。次のよう
に書いてください:

        :unmap ,ab|    " comment


ビューの復元
------------

何らかの変更を加えてから、カーソルのあった場所に戻りたい時があります。そのとき
に、画面に表示されていた行範囲も復元されるとすてきです。
次の例は、現在行をヤンクしてファイルの先頭にプットし、ビューを復元します:

        map ,p ma"aYHmbgg"aP`bzt`a

これは次のことをしています:
        ma"aYHmbgg"aP`bzt`a
        ma                      現在のカーソル位置にマーク a を設定
          "aY                   現在行をレジスタ a にヤンク
             Hmb                ウィンドウの一行目に移動してマーク b を設定
                gg              ファイルの一行目に移動
                  "aP           ヤンクした行をその上にプット
                     `b         ウィンドウの一行目に戻る
                       zt       ウィンドウの表示範囲を以前と同じにする
                         `a     保存しておいたカーソル位置に移動


パッケージング
--------------

関数の名前が他の人の関数とかぶらないように、次の方法を使ってください:
- ユニークな文字列を名前の前に付ける。私はよく略語を使います。例えば、オプショ
  ンウィンドウ (option window) のための関数なら "OW_" などです。
- 関数を一つのファイルにまとめて、関数がロードされているかどうかを示すグローバ
  ル変数を設定する。ファイルが二回目に読み込まれたとき、最初にそれらの関数をア
  ンロードする。
例:

        " This is the XXX package

        if exists("XXX_loaded")
          delfun XXX_one
          delfun XXX_two
        endif

        function XXX_one(a)
                ... body of function ...
        endfun

        function XXX_two(b)
                ... body of function ...
        endfun

        let XXX_loaded = 1

==============================================================================
41.11 プラグインを書く                                write-plugin

Vim script を書いて、それを多くの人に使ってもらうことができます。そのようなス
クリプトはプラグインと呼ばれます。Vim ユーザーはあなたのスクリプトをプラグイン
ディレクトリにコピーするだけで、すぐにその機能を使うことができます。
add-plugin 参照。

プラグインには二種類あります:

      グローバルプラグイン : すべてのファイルで共通
  ファイルタイププラグイン : ファイルの種類別

この節ではグローバルプラグインについて説明します。ほとんどの説明はファイルタイ
ププラグインに対してもあてはまります。ファイルタイププラグイン特有の説明は次節
にあります write-filetype-plugin


名前
-----

最初にプラグインの名前を決めなければなりません。プラグインが提供する機能が名前
から分かるようにしてください。また、他の人が作ったプラグインと名前がかぶらない
ようにしてください。古い MS-Windows システムでの問題を避けるため、名前は 8 文
字以内にしてください。

例えばタイプミス (type mistake) を修正 (correct) するためのスクリプトなら
"typecorr.vim" という名前を付けたりします。ここではこれを例題として使います。

プラグインが誰でも使えるようにするため、いくつかのガイドラインに従ってくださ
い。ガイドラインは段階的に説明していきます。例題プラグインの完全なソースは最後
に示します。


ボディ
------

まずはプラグインの本体部分を見てみましょう。行番号は実際の番号です:

 14     iabbrev teh the
 15     iabbrev otehr other
 16     iabbrev wnat want
 17     iabbrev synchronisation
 18             \ synchronization
 19     let s:count = 4

もちろん、実際のスクリプトはもっと巨大です。

行番号は説明のために追加したものです。プラグインを書くときは行番号を付けないで
ください。


ヘッダー
------

新しい単語を追加していくと、プラグインには複数のバージョンが存在することになり
ます。ファイルを配布したとき、それを使った人は、誰がこの素晴らしいプラグインを
書いたのかを知りたいと思うでしょうし、感想を伝えたいと思うかもしれません。
というわけで、次のようなヘッダーをプラグインに書いてください:

  1     " Vim global plugin for correcting typing mistakes
  2     " Last Change:  2000 Oct 15
  3     " Maintainer:   Bram Moolenaar <Bram@vim.org>

著作権とライセンスについて: プラグインがとても便利で、そして再配布を制限するほ
どのものでない場合は、パブリックドメインか Vim ライセンス (license) の適用を
検討してみてください。次の短い宣言をプラグインの先頭付近に書いておくだけで十分
です:

  4     " License:      This file is placed in the public domain.


行連結、副作用の回避                                    use-cpo-save
--------------------

上の例の 18 行目では行連結 (line-continuation) が使われています。ユーザーの
環境で 'compatible' オプションがオンに設定されていると、この行でエラーが発生し
ます。'compatible' オプションの設定には副作用があるので、勝手に設定をオフにす
ることはできません。問題を避けるには、一時的に 'cpoptions' の値を Vim の初期値
に設定し、後で元に戻します。そうすれば、行連結を使うことができ、スクリプトはほ
とんどの環境で動作するようになります。設定の変更は次のようにします:

 11     let s:save_cpo = &cpo
 12     set cpo&vim
 ..
 42     let &cpo = s:save_cpo
 43     unlet s:save_cpo

最初に 'cpoptions' の値を s:save_cpo 変数に保存します。プラグインの最後でオプ
ションの値を元に戻します。

スクリプトローカル変数 (s:var) を使っていることに注目してください。グローバ
ル変数は他の場所で使われている可能性があります。スクリプトの中だけで使う場合は
スクリプトローカル変数を使ってください。


ロードしない
------------

ユーザーが常にプラグインをロードしたいと思うとは限りません。また、システム管理
者がシステムのプラグインディレクトリにプラグインを入れたが、ユーザーは自分で入
れたプラグインを使いたいということもあります。したがって、指定したプラグインだ
けを無効にできる必要があります。次のようにします:

  6     if exists("g:loaded_typecorr")
  7       finish
  8     endif
  9     let g:loaded_typecorr = 1

これはスクリプトの二重ロードを避ける効果もあります。スクリプトを二重にロードす
ると、関数の再定義エラーが発生したり、自動コマンドが二重に追加されることでトラ
ブルが起きたりします。

変数の名前は "loaded_" で始めてプラグインのファイル名をそのまま付けるようにし
てください。"g:" を付けることで関数の中で変数を使用したときに発生するミスを防
いでいます (関数の中では "g:" を付けない変数はローカル変数になります)。

"finish" を使ってファイルの残りの部分の読み込みを停止しています。この方法は
ファイル全体を if-endif で囲むよりも速いです。


マップ
------

さて、プラグインをもっと魅力あるものに仕上げましょう。マップを追加して、カーソ
ルの下の単語に対する修正を追加できるようにします。単純にキーを選んでマップを設
定することもできますが、そのキーは既にユーザーが使っているかもしれません。マッ
プに使用するキーをユーザーが選択できるようにするには、<Leader> を使います:

 22       map <unique> <Leader>a  <Plug>TypecorrAdd;

"<Plug>TypecorrAdd;" は目的の動作をします。詳しくは後で説明します。

使用したいキーを "mapleader" 変数に設定することで、マップの最初のキーを設定で
きます。例えば、次のように設定すると:

        let mapleader = "_"

マップは "_a" と定義されます。変数が設定されていない場合は初期設定 (バックス
ラッシュ) が使われます。つまり "\a" というマップが定義されます。

Note: 上記のコマンドでは <unique> が使われています。これは、同じマップが既に定
義されていた場合にエラーを表示します。:map-<unique>

マップするキーをユーザーが自分で定義できるようにするには、次のようにします:

 21     if !hasmapto('<Plug>TypecorrAdd;')
 22       map <unique> <Leader>a  <Plug>TypecorrAdd;
 23     endif

"<Plug>TypecorrAdd;" に対するマップが既にあるかどうかを調べ、無い場合のみ
"<Leader>a" にマップを定義します。ユーザーは自分の vimrc ファイルの中でマップ
を定義することができます:

        map ,c  <Plug>TypecorrAdd;

すると、マップのキーとして ",c" が使われます。"_a" や "\a" は使われません。


ピース
------

スクリプトが大きくなると、それを部品ごとに分けたくなります。それには関数やマッ
プを使います。しかし、そうすると関数やマップが他のスクリプトのものと衝突する可
能性があります。例えば、Add() という関数を追加したとき、他のスクリプトでも同じ
名前の関数が定義されているかもしれません。そのような場合は、名前の前に "s:" を
付けて、スクリプトの中だけで使える関数を定義します。

新しい修正を追加するための関数を定義します:

 30     function s:Add(from, correct)
 31       let to = input("type the correction for " .. a:from .. ": ")
 32       exe ":iabbrev " .. a:from .. " " .. to
 ..
 36     endfunction

s:Add() 関数は同じスクリプトの中から呼び出すことができます。他のスクリプトが
s:Add() を定義していた場合、それはそのスクリプトにローカルであり、関数が定義さ
れたスクリプトの中からのみ呼び出すことができます。さらにグローバルの Add() 関
数 ("s:" 無し) を定義することもでき、それはまた別の関数になります。

マップ定義では <SID> が使えます。これは、現在のスクリプトを識別するためのスク
リプト ID を生成します。私たちの入力修正プラグインでは <SID> を次のように使い
ます:

 24     noremap <unique> <script> <Plug>TypecorrAdd;  <SID>Add
 ..
 28     noremap <SID>Add  :call <SID>Add(expand("<cword>"), 1)<CR>

ユーザーが "\a" と入力すると、次の手順でキー入力が呼び出されます:

        \a  ->  <Plug>TypecorrAdd;  ->  <SID>Add  ->  :call <SID>Add()

他のスクリプトで <SID>Add をマップすると、別のスクリプト ID が使われ、別のマッ
プが生成されます。

Note: s:Add() ではなく <SID>Add() と書いていることに注意してください。マップは
スクリプトの外側でユーザーが入力するものだからです。<SID> はスクリプト ID に変
換され、どのスクリプトの Add() 関数を呼べばいいのかわかるようになっています。

これは少し複雑ですが、複数のプラグインを同時に使用するためには必要なことです。
基本的なルールとしては、マップの中では <SID>Add() を使い、他の場所 (スクリプト
の中、自動コマンド、ユーザー定義コマンド) では s:Add() を使います。

マップと同じ方法で、メニューを追加することもできます:

 26     noremenu <script> Plugin.Add\ Correction      <SID>Add

プラグインのメニューを追加する場合は "Plugin" メニューの下に登録することが推奨
されています。この例ではメニューが一つだけですが、複数のメニューを追加する場合
は、サブメニューの使用が推奨されています。例えば、"Plugin.CVS" 以下に
"Plugin.CVS.checkin" や "Plugin.CVS.checkout" などの CVS の操作を登録します。

Note: 28 行目では ":noremap" を使って、他のマップでトラブルが起きないようにし
ています。例えば、誰かが ":call" をマップしているかもしれないからです。24 行目
でも ":noremap" を使っていますが、ここでは "<SID>Add" を再マップして欲しいの
で、"<script>" を使っています。これを使うとスクリプトローカルなマップだけが再
マップされます