Next: , Previous: , Up: 目次   [Index]


Vim script 書法

*usr_41.txt*	For Vim バージョン 8.1.  Last change: 2019 Nov 17

		     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 を配布する

はじめに

誰もが最初に觸れる Vim script は vimrc ファイルです。Vim が起動するときに讀み込まれ、書かれてゐるコマンドが實行されます。それにより好きなやうに設定を變更できます。vimrc の中ではすべてのコロンコマンドが使へます (":" で始まるコマンドのこと。Ex コマンドやコマンドラインコマンドと呼ばれることもある)。

シンタックスファイルも Vim script です。シンタックスファイルは、ファイルタイプ別にオプションを設定するファイルの一種です。複雜なマクロ定義を別ファイルに分けて保存しておくこともできます。このやうに、いろいろな使用方法が考へられます。

簡單な例から始めませう:

: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

1 行目では ":let" コマンドで變數に値を代入してゐます。書式は次のとほりです:

:let {variable} = {expression}

例では、變數名が "i"、式が 1 です。

":while" コマンドでループを開始します。書式は次のとほりです:

:while {condition}
:  {statements}
: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 を加算し、新しい値を同じ變數に代入します。

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

: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 進數は "0" で開始します。例へば "017" は 10 進數の 15 です。2 進數は "0b" か "0B" で開始します。例へば "0b101" は 10 進數の 5 です。

注意:
10 進數で書くときは先頭に "0" を付けないでください。8 進數として扱はれてしまひます。

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

:echo 0x7f 036
127 30

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

:echo 0x7f -036
97

式の途中にある空白は無視されますが、可讀性を高めるために、適切に空白で區切ることをお勸めします。例へば上記の數値が負數であると勘違ひしてしまはないやうに、マイナス記號と數値の閒に空白をいれませう:

:echo 0x7f - 036

變數

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

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:nameVim が定義する變數

變數の削除

變數はメモリを消費します。":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| を參照してください。

變數に文字列を代入するには文字列定數を使ふ必要があります。文字列定數には 2 つの種類があります。1 つはダブルクォート文字列です:

:let name = "peter"
:echo name
peter

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

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

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

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

シングルクォート文字列の中ではすべての文字がそのまま使はれます。ただし、シングルクォートだけは特別で、1 つのシングルクォートを表すためには 2 つのシングルクォートを書く必要があります。バックスラッシュはそのまま使はれるので、特殊文字は使へません。

ダブルクォート文字列の中では特殊文字が使へます。次のやうなものがあります:

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

最後の 2 つはただの 1 例です。"\<name>" 形式で "name" といふ特殊キーを使ふことができます。

文字列で使へる特殊表記については |expr-quote| を參照してください。

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

文字列は "." で連結できます:

:echo "foo" . "bar"
foobar

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

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)

條件式

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

:if {condition}
   {statements}
:endif

{condition} を評價した結果が眞 (0以外) であれば、{statements} の內容が實行されます。{statements} は正しく記述されてゐる必要があります。不正な記述があると ":endif" までたどり着けません。

":else" を使ふこともできます。書式は次のとほり:

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

2 つ目の {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 に變換されるのです。

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

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

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

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

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

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

他のループコマンド

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

: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| を參照。

式を實行する

今まではコマンドを直接書いてきました。":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

函數を使ふ

たくさんの函數があらかじめ定義され、豐富な機能が提供されてゐます。このセクションの說明にもいくつか登場します。函數の一覽は |functions| を參照してください。

函數は ":call" コマンドで呼び出します。引數はカッコで圍み、それぞれをコンマで區切ります。例:

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

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

函數は式の中で使ふこともできます。例:

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

getline() 函數はカレントバッファから行を取得する函數です。引數には行番號を指定します。この例では "." ですが、これはカーソルのある行を示します。

substitute() 函數は ":substitute" コマンドとほぼ同じです。最初の引數は置換對象の文字列、2 つ目の引數はパターン、3 つ目は置き換へ文字列、最後はフラグです。

setline() 函數は行の內容を置き換へます。最初の引數は行番號、2 つ目の引數は置き換へる文字列です。この例では、substitute() の結果で現在行を置き換へてゐます。上記の 3 行のコマンドは次のコマンドと同じことをしてゐます:

:substitute/\a/*/g

substitute() コマンドの前後にいろいろな處理を入れたりすると、もつと面白いことができるやうになります。

函數一覽

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

文字列繰作:

nr2char()數値から文字を得る
list2str()數値のリストから文字列を得る
char2nr()文字の數値を得る
str2list()文字列から數値のリストを得る
str2nr()文字列を數値に變換する
str2float()文字列を浮動小數點數に變換する
printf()書式付き文字列を整形する
escape()文字列の特定の文字を ’\’ でエスケープ
shellescape()シェルコマンドで使へるやうに文字列をエスケープ
fnameescape()Vim コマンド用にファイル名をエスケープ
tr()ある文字の集合から別の文字の集合へ置換する
strtrans()文字列を印刷可能な狀態とする
tolower()文字列を小文字にする
toupper()文字列を大文字にする
match()文字列の中でパターンにマッチした位置
matchend()文字列の中でパターンにマッチした末尾の位置
matchstr()文字列の中でパターンにマッチした文字列
matchstrpos()文字列の中でパターンにマッチした文字列と位置
matchlist()matchstr()と同樣だが、部分マッチも返す
stridx()文字列の中で部分文字列が見つかつた最初の位置
strridx()文字列の中で部分文字列が見つかつた最後の位置
strlen()文字列のバイト單位での長さ
strchars()文字列の文字單位での長さ
strwidth()表示された文字列のサイズ
strdisplaywidth()表示された文字列のサイズ、タブに關係する
substitute()パターンにマッチする文字列を置換
submatch()":s" と substitute() の中で部分マッチを得る
strpart()文字列の一部分を得る(バイト數指定)
strcharpart()文字のインデックスで指定された部分文字列を得る
strgetchar()文字のインデックスで指定された文字コードを得る
expand()特殊キーワードを展開する
expandcmd():edit‘ のやうにコマンドを展開する
iconv()テキストのエンコーディングを變換する
byteidx()文字列中の文字のバイトインデックス
byteidxcomp()byteidx() と同樣だが合成文字を數に入れる
repeat()文字列を複數回繰り返す
eval()文字列を式として評價する
execute()Ex コマンドを實行し出力を得る
win_execute()execute() に似てゐるが指定ウィンドウで實行する
trim()文字列から文字をトリムする

リスト操作:

get()要素を取得。存在しないインデックスでもエラーを出さない
len()リスト中の要素の個數
empty()リストが空であるか判定する
insert()リストの任意の位置に要素を插入する
add()リストに要素を追加する
extend()リストにリストを連結する
remove()リストから1個以上の要素を取り除く
copy()リストの淺いコピーを作成する
deepcopy()リストの完全なコピーを作成する
filter()リストから選擇された要素を取り除く
map()リストの各要素を變換する
sort()リストをソートする
reverse()リストの竝び順を反轉させる
uniq()隣接して繰り返される要素のコピーを削除する
split()文字列を分割し、リストにする
join()リストの要素を連結し、文字列にする
range()數列リストを返す
string()リストの文字列表現
call()リストを引數として函數を呼ぶ
index()リスト中の要素のインデックス
max()リスト中の最大値
min()リスト中の最小値
count()ある要素がリスト中に出現する回數を返す
repeat()リストを複數回繰り返す

辭書操作:

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

浮動小數點數の計算:

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()雙曲線正接 (ハイパボリックタンジェント)
isnan()數値でないかどうかのチェック

その他の計算:

and()ビットごとの論理積
invert()ビットごとの否定
or()ビットごとの論理和
xor()ビットごとの排他的論理和
sha256()SHA-256 ハッシュ

變數:

type()變數の型
islocked()變數がロックされてゐるか判定する
funcref()函數參照へのFuncrefを取得する
function()函數名から Funcref を取得する
getbufvar()指定バッファの變數値を得る
setbufvar()指定バッファに變數を設定する
getwinvar()指定ウィンドウの變數値を得る
gettabvar()指定タブページから變數値を得る
gettabwinvar()指定ウィンドウ・タブページから變數値を取得する
setwinvar()指定ウィンドウに變數を設定する
settabvar()指定タブページに變數を設定する
settabwinvar()指定ウィンドウ・タブページに變數を設定する
garbagecollect()開放可能なメモリを解放する

カーソルとマークの位置:

col()カーソルやマークの列番號を取得する
virtcol()カーソルやマークの畫面上の列番號を得る
line()カーソルやマークの行番號を取得する
wincol()カーソルのウィンドウでの列番號
winline()カーソルのウィンドウでの行番號
cursor()カーソルを指定した位置に移動させる
screencol()カーソルのスクリーン列を取得する
screenrow()カーソルのスクリーン行を取得する
screenpos()テキスト文字のスクリーン位置 (行と列)
getcurpos()カーソルの位置を取得する
getpos()カーソルやマークなどの位置を取得する
setpos()カーソルやマークなどの位置を設定する
byte2line()指定のバイト位置の行番號を取得する
line2byte()指定の行のバイト位置を取得する
diff_filler()ある行より上の詰め行の數を取得する
screenattr()スクリーン列/行の屬性を取得する
screenchar()スクリーン列/行の文字コードを取得する
screenchars()スクリーン列/行の文字コードのリストを取得する
screenstring()スクリーン列/行の文字列を取得する

カレントバッファで動作するもの:

getline()バッファから行を得る
setline()バッファの行を置き換へる
append()行または行のリストをバッファに追加する
indent()行のインデントを得る
cindent()C 言語におけるインデントを得る
lispindent()Lisp 言語におけるインデントを得る
nextnonblank()次の非空行を探す
prevnonblank()前の非空行を探す
search()パターンにマッチする場所を探す
searchpos()パターンにマッチする場所を探す
searchpair()start/skip/end の對を探す
searchpairpos()start/skip/end の對を探す
searchdecl()名前が宣言されてゐる場所を探す
getcharsearch()文字檢索情報を返す
setcharsearch()文字檢索情報を設定する

他のバッファで動作するもの:

getbufline()バッファの行のリストを得る
setbufline()指定されたバッファ內で 1 行を置換する
appendbufline()指定されたバッファ內で行のリストを追加する
deletebufline()指定されたバッファから行を削除する

システム函數とファイル繰作:

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()ファイルを讀み込み、行のリストを得る
writefile()行のリストをファイルに書き込む
readdir()ディレクトリ內のファイル名のリストを得る
writefile()行のリストまたは Blob をファイルに書き込む

日附と時刻:

getftime()ファイルの最終更新日時を得る
localtime()現在時刻を秒單位で得る
strftime()時刻を文字列に變換する
reltime()現在時刻または經過時閒を正確に取得する
reltimestr()reltime() の結果を文字列に變換する
reltimefloat()reltime() の結果を浮動小數點に變換する

バッファ、ウィンドウ、引數リスト:

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_gotoid()IDで指定されたウィンドウへ移動する
win_id2tabwin()ID で指定されたタブとウィンドウの番號を得る
win_id2win()IDで指定されたウィンドウの番號を得る
getbufinfo()バッファの情報一覽を得る
gettabinfo()タブページの情報一覽を得る
getwininfo()ウィンドウの情報一覽を得る
getchangelist()變更リストのエントリ一覽を得る
getjumplist()ジャンプリストのエントリ一覽を得る
swapinfo()スワップファイルに關する情報
swapname()バッファのスワップファイルパスを取得する

コマンドライン:

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

QuickFix とロケーションリスト:

getqflist()QuickFix エラーのリスト
setqflist()QuickFix を變更する
getloclist()ロケーションリストの項目のリスト
setloclist()ロケーションリストを變更する

插入モード補完:

complete()補完候補を設定する
complete_add()補完候補を追加する
complete_check()補完處理を終へるべきかどうかをチェックする
complete_info()現在の補完情報を得る
pumvisible()ポップアップメニューが表示されてゐるかチェック
pum_getpos()表示されてゐるポップアップメニューの位置とサイズを得る

折り疊み:

foldclosed()行が折り疊まれてゐるかどうかをチェックする
foldclosedend()foldclosed() と同樣。折り疊み末尾の行番號を返す
foldlevel()行の折り疊みレベルを得る
foldtext()閉ぢた折り疊みを代替表示するテキストを生成
foldtextresult()閉ぢた折り疊みを代替表示するテキストを得る

シンタックスハイライト:

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

スペリング:

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

履歷:

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

對話インターフェイス:

browse()ファイル選擇ダイアログを開く
browsedir()ディレクトリ選擇ダイアログを開く
confirm()ユーザーに選擇をさせる
getchar()ユーザーが入力した文字を得る
getcharmod()最後に入力した文字の修飾子 (modifier) を得る
getmousepos()最後に取得したマウスの位置を得る
feedkeys()先行入力キューに文字を入れる
input()ユーザーが入力した行を得る
inputlist()ユーザーにリストから項目を選擇させる
inputsecret()ユーザーが入力した行を得る。ただし表示はしない
inputdialog()ダイアログを使つてユーザーが入力した行を得る
inputsave()先行入力キューを保存して空にする
inputrestore()inputsave() で保存した狀態に戾す

GUI:

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

Vim サーバー:

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

ウィンドウサイズと位置:

winheight()ウィンドウの高さを取得
winwidth()ウィンドウの幅を取得
win_screenpos()ウィンドウのスクリーン座標を取得
winlayout()タブページ內のウィンドウレイアウトを取得
winrestcmd()ウィンドウサイズを復元するコマンドを返す
winsaveview()カレントウィンドウのビューを取得
winrestview()カレントウィンドウのビューを復元

マッピング:

hasmapto()マップの存在をチェック
mapcheck()マッチするマップの存在をチェック
maparg()マップの rhs (展開結果)を得る
wildmenumode()wildmode が有效かどうかをチェック

テスト用:

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_fails()コマンドが失敗する事をテストする
assert_report()テストの失敗をレポートする
test_alloc_fail()メモリの確保を失敗させる
test_autochdir()起動中に ’autochdir’ を有效にする
test_override()Vimの 內部處理を置き換へてテストする
test_garbagecollect_now()直ちにメモリを解放する
test_getvalue()內部變數の値を取得する
test_ignore_error()特定のエラーメッセージを無視する
test_null_blob()null の Blob を返す
test_null_channel()null のチャネルを返す
test_null_dict()null の辭書を返す
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 でスクロールバーの移動をシミュレートする

プロセス閒通信:

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_start()Job を開始する
job_stop()Job を停止する
job_status()Job のステータスを取得する
job_getchannel()Job が使用する channel を取得する
job_info()Job の情報を取得する
job_setoptions()Job のオプションを設定する

目印:

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

Terminal window:

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()端末のサイズを設定する

ポップアップウィンドウ:

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()ポップアップを閉ぢる
popup_clear()すべてのポップアップを閉ぢる
popup_filter_menu()項目のリストから選擇する
popup_filter_yesno()’y’ か ’n’ が押されるまでブロックする
popup_getoptions()ポップアップの現在のオプションを取得する
popup_getpos()ポップアップの實際の位置とサイズを取得する

タイマー:

timer_start()タイマーを作る
timer_pause()タイマーを一時停止もしくは再開する
timer_stop()タイマーを止める
timer_stopall()全てのタイマーを止める
timer_info()タイマーの情報を得る

タグ:

taglist()マッチしてゐるタグのリストを取得する
tagfiles()タグファイルのリストを取得する
gettagstack()ウィンドウのタグスタックを取得する
settagstack()ウィンドウのタグスタックを變更する

プロンプトバッファ:

prompt_setcallback()バッファにプロンプトコールバックを設定する
prompt_setinterrupt()バッファに割り込みコールバックを設定する
prompt_setprompt()バッファにプロンプトテキストを設定する

その他:

mode()現在の編輯モードを得る
visualmode()最後に使はれたビジュアルモードの種類
exists()變數、函數の存在をチェック
has()機能がサポートされてゐるかをチェック
changenr()最近の變更番號を返す
cscope_connection()cscope 接續をチェック
did_filetype()FileType 自動コマンドが使用されたかどうか
eventhandler()イベントハンドラによつて起動されたかどうか
getpid()Vim のプロセスIDを得る
libcall()外部ライブラリの函數を呼ぶ
libcallnr()同上、數値を返す
undofile()アンドゥファイルの名前を得る
undotree()アンドゥツリーの狀態を返す
getreg()レジスタの値を得る
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| の式を評價する
debugbreak()デバッグされてゐるプログラムを中斷する

函數を定義する

自分で函數を定義することができます。基本的な函數定義は次のとほり:

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

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

小さな函數を定義してみませう。2 つの數値のうち小さい方を返す函數を作ります。函數は次のやうな行で始まります:

:function Min(num1, num2)

函數の名前が "Min" であり、2 つの引數 ("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" コマンドは行範圍を受け取ることができます。範圍指定の使用方法は 2 つあります。函數を定義するときに "range" キーワードを使つた場合は、函數自身が範圍指定を處理します。

函數には "a:firstline" と "a:lastline" といふ 2 つの變數が暗默的に渡されます。この 2 つの變數には範圍指定された行番號が代入されてゐます。例:

: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 番目の引數は引數のリストです。

函數への參照は、次節で說明される辭書と組み合はせたときもつとも役に立ちます。

リストと辭書

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

リストとは、要素を順番に竝べたものです。要素はどのやうな型でも構ひません。數値のリスト、リストのリスト、あるいは複數の型が混在したリストでも作れます。例へば、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" に代入した狀態で第 2 引數を評價します。これにより 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

さらなる情報については |List| と |Dictionaries| を參照してください。

例外

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

: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| を參照してください。

注意事項

Vim script において注意すべきことの槪要を簡單に說明します。他の場所にも同じやうな說明はありますが、手頃なチェックリストに使へるでせう。

改行記號はシステムによつて異なります。Unix では <NL> 文字が使はれますが、MS-DOS, Windows, OS/2 などでは <CR><LF> が使はれます。末尾が <CR> になつてゐるマップを使ふときは注意してください。|:source_crnl| 參照。

空白

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

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

":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

’|’ 文字でコマンドを區切り、次のコマンドを書くことができます。この例では 2 つ目のコマンドはコメントのみです。"!" の場合は |: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                ウィンドウの 1 行目に移動してマーク b を設定
        gg              ファイルの 1 行目に移動
          "aP           ヤンクした行をその上にプット
             `b         ウィンドウの 1 行目に戾る
               zt       ウィンドウの表示範圍を以前と同じにする
                 `a     保存しておいたカーソル位置に移動

パッケージング

函數の名前が他の人の函數とかぶらないやうに、次の方法を使つてください:

例:

" 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

プラグインを書く

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

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

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

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

名前

最初にプラグインの名前を決めなければなりません。プラグインが提供する機能が名前から分かるやうにしてください。また、他の人が作つたプラグインと名前がかぶらないやうにしてください。古い 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.

行連結、副作用の囘避

上の例の 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" メニューの下に登錄することが推奬されてゐます。この例ではメニューが 1 つだけですが、複數のメニューを追加する場合は、サブメニューの使用が推奬されてゐます。例へば、"Plugin.CVS" 以下に "Plugin.CVS.checkin" や "Plugin.CVS.checkout" などの CVS の操作を登錄します。

Note:
28 行目では ":noremap" を使つて、他のマップでトラブルが起きないやうにしてゐます。例へば、誰かが ":call" をマップしてゐるかもしれないからです。24 行目でも ":noremap" を使つてゐますが、ここでは "<SID>Add" を再マップして欲しいので、"<script>" を使つてゐます。これを使ふとスクリプトローカルなマップだけが再マップされます |:map-<script>|。26 行目でも ":noremenu" で同樣のことをしてゐます |:menu-<script>|。

<SID> と <Plug>

<SID> と <Plug> は、入力したキーに對するマップと、他のマップの中だけで使はれるマップが干涉しないやうにするために使はれます。<SID> と <Plug> の違ひに注意してください:

<Plug>

これはスクリプトの外側からも見えます。ユーザーが自分でプラグインの機能をマップできるやうにするやうな場合に使ひます。<Plug> は特殊なコードで、キーボードから入力されることはありません。 キー列が他のプラグインとかぶらないやうに、<Plug> スクリプト名 マップ名、といふ形式で使つてください。 我々の例では、スクリプト名が "Typecorr"、マップ名が "Add" なので、"<Plug>TypecorrAdd" といふキー列になります。スクリプト名とマップ名の最初の文字だけを大文字にして、どこがマップ名なのかわかるやうにします。

<SID>

これはスクリプト ID (スクリプト固有の識別子) です。 Vim は內部で <SID> を "<SNR>123_" に變換します ("123" の部分はいろいろな數字が入ります)。つまり、函數 "<SID>Add()" は、あるスクリプトでは "<SNR>11_Add()" といふ名前になり、別のスクリプトでは "<SNR>22_Add()" になります。これは ":function" コマンドで函數一覽を表示すると確認することができます。<SID> の變換はマップの中でも同樣におこなはれるので、マップの中からスクリプトローカル函數を呼び出すことができます。

ユーザー定義コマンド

修正を追加するためのユーザー定義コマンドを追加します:

38    if !exists(":Correct")
39      command -nargs=1  Correct  :call s:Add(<q-args>, 0)
40    endif

ユーザー定義コマンドは、同じ名前のコマンドがまだない場合のみ定義できます。既に定義されてゐる場合はエラーになります。":command!" を使つてユーザー定義函數を上書きするのは良いアイデアとは言へません。ユーザーは、自分が定義したコマンドがなぜ動かないのか不思議に思ふでせう。|:command|

スクリプト變數

先頭に "s:" が付いた變數はスクリプト變數です。これはスクリプトの中だけで使へます。スクリプトの外からは見えません。同じ名前の變數を複數のスクリプトで使つてしまふやうなトラブルを避けることができます。Vim が實行されてゐる閒、變數は保持されます。そして、同じスクリプトが再讀み込みされると、再び同じ變數が使はれます。|s:var|

スクリプト變數は、同じスクリプトの中で定義された函數、自動コマンド、ユーザー定義コマンドでも使へます。我々の例に、修正の數を數へるための數行のコードを追加します:

19  let s:count = 4
..
30  function s:Add(from, correct)
..
34    let s:count = s:count + 1
35    echo s:count . " corrections now"
36  endfunction

最初に s:count はスクリプトの中で 4 で初期化されます。その後、s:Add() 函數が呼び出されると、s:count が增加します。函數がどこから呼ばれたかにかかはらず、函數が定義されたスクリプトのローカル變數が使はれます。

まとめ

例題の完成形は以下のやうになります:

1 " Vim global plugin for correcting typing mistakes
2 " Last Change:  2000 Oct 15
3 " Maintainer:   Bram Moolenaar <Bram@@vim.org>
4 " License:  This file is placed in the public domain.
5
6 if exists("g:loaded_typecorr")
7   finish
8 endif
9 let g:loaded_typecorr = 1
10
11 let s:save_cpo = &cpo
12 set cpo&vim
13
14 iabbrev teh the
15 iabbrev otehr other
16 iabbrev wnat want
17 iabbrev synchronisation
18     \ synchronization
19 let s:count = 4
20
21 if !hasmapto('<Plug>TypecorrAdd')
22   map <unique> <Leader>a  <Plug>TypecorrAdd
23 endif
24 noremap <unique> <script> <Plug>TypecorrAdd  <SID>Add
25
26 noremenu <script> Plugin.Add\ Correction      <SID>Add
27
28 noremap <SID>Add  :call <SID>Add(expand("<cword>"), 1)<CR>
29
30 function s:Add(from, correct)
31   let to = input("type the correction for " . a:from . ": ")
32   exe ":iabbrev " . a:from . " " . to
33   if a:correct | exe "normal viws\<C-R>\" \b\e" | endif
34   let s:count = s:count + 1
35   echo s:count . " corrections now"
36 endfunction
37
38 if !exists(":Correct")
39   command -nargs=1  Correct  :call s:Add(<q-args>, 0)
40 endif
41
42 let &cpo = s:save_cpo
43 unlet s:save_cpo

33 行目は說明がまだでした。これは、新しい修正をカーソルの下の單語に適用します。|:normal| コマンドを使つて新しい略語を適用してゐます。

Note: マップと略語はその場で展開されます。":noremap" で定義されたマップから函數が呼び出されたとしても動作は同じです。

fileformat’ オプションを "unix" に設定することが推奬されてゐます。さうすれば、Vim script はどこでも動作します。’fileformat’ が "dos" に設定されたスクリプトは Unix では動作しません。|:source_crnl| も參照。設定が正しいことを確實にするため、ファイルを保存する前に次のコマンドを實行してください:

:set fileformat=unix

ドキュメント

プラグインのドキュメントを書くのは良いアイデアです。ユーザーが動作を變更できるやうな場合には特に重要です。|add-local-help| ではどのやうにしてドキュメントがインストールされるか說明されてゐます。

プラグインヘルプファイルの例を示します ("typecorr.txt"):

1 *typecorr.txt*  Plugin for correcting typing mistakes
2
3 If you make typing mistakes, this plugin will have them corrected
4 automatically.
5
6 There are currently only a few corrections.  Add your own if you like.
7
8 Mappings:
9 <Leader>a   or   <Plug>TypecorrAdd
10     Add a correction for the word under the cursor.
11
12 Commands:
13 :Correct {word}
14     Add a correction for {word}.
15
16                         *typecorr-settings*
17 This plugin doesn't have any settings.

書式に氣をつけなければならないのは一行目だけです。1 行目はコピーされ、help.txt の "LOCAL ADDITIONS:" の項に埋め込まれます |local-additions|。最初の "*" は 1 行目の 1 桁目に書いてください。ヘルプを追加したら ":help" を實行して項目が追加されたことを確認してください。

ヘルプの中で ** で文字を圍むとタグを追加することができます。ただし、既存のヘルプタグと同じものを使はないでください。"typecorr-settings" のやうに、プラグインの名前を使つてタグを作るといいかもしれません。

ヘルプの他の部分を參照するときは || で圍みます。さうすれば、ユーザーは簡單にヘルプの關聯した部分を參照することができます。

ファイルタイプの認識

ファイルタイプが Vim によつて認識されない場合は、別ファイルにファイルタイプを認識するためにコードを作成する必要があります。通常は、自動コマンドを使つて、ファイル名がパターンにマッチしたときにファイルタイプを設定します。例:

au BufNewFile,BufRead *.foo         set filetype=foofoo

この 1 行を ’runtimepath’ の最初のディレクトリの "ftdetect/foofoo.vim" に書き込みます。例へば、Unix なら "~/.vim/ftdetect/foofoo.vim" などです。ファイルタイプとスクリプトファイルの名前を同じにする決まりになつてゐます。

必要ならより複雜な處理をすることもできます。例へば、ファイルの中身を見て言語を判定したりできます。|new-filetype| も參照。

要約

プラグインで使用する特有事項の要約を示します:

s:name

スクリプトローカル變數。

<SID>

スクリプトID。マップや函數をスクリプトローカルにするのに使ふ。

hasmapto()

スクリプトが提供してゐる機能に對して、ユーザーが既にマップを定義したかどうかをチェックする函數。

<Leader>

"mapleader" の値。ユーザーがその變數にキーを設定することで、プラグインのマップの開始キーを指定できる。

:map <unique>

マップが既に定義されてゐるなら警告を發する。

:noremap <script>

スクリプトローカルマップだけを使ふ。グローバルマップは使はない。

exists(":Cmd")

ユーザー定義コマンドが既にあるかどうかをチェックする。

ファイルタイププラグインを書く

ファイルタイププラグインはグローバルプラグインと似てゐますが、カレントバッファのマップやオプションだけを設定します。ファイルタイププラグインの使用方法については |add-filetype-plugin| を參照してください。

先に |41.11| 節のグローバルプラグインの項を讀んでください。そこで說明されてゐることはすべてファイルタイププラグインにもあてはまります。この節ではファイルタイププラグイン特有の事項だけを說明します。ファイルタイププラグインはカレントバッファに對してのみ機能するといふことが最も大切です。

無效化

ファイルタイププラグインを書いて多くの人に使つてもらはうとするなら、プラグインを無效化できるやうにしておく必要があります。プラグインの先頭に次のやうな記述を追加してください:

" このバッファに對してまだ實行されてゐない場合のみ處理を實行する
if exists("b:did_ftplugin")
finish
endif
let b:did_ftplugin = 1

これは同じプラグインが同じバッファで二重にロードされるのを防ぐためにも必要です (":edit" コマンドを引數なしで實行したときに發生します)。

ユーザーは、次の一行だけを書いたファイルタイププラグインを作成することで、標準プラグインのロードを無效化できます:

let b:did_ftplugin = 1

ただし、そのファイルを保存したファイルタイププラグインディレクトリが、’runtimepath’ の中で $VIMRUNTIME よりも前にある必要があります。

標準プラグインを使ひつつ、その設定を 1 つだけ變更したいといふ場合は、スクリプトの中で設定を變更することができます:

setlocal textwidth=70

このファイルを "after" ディレクトリに保存すると、(例へば filetype=vim なら) 標準配布の "vim.vim" が讀み込まれた後に、保存したファイルが讀み込まれるやうになります |after-directory|。Unix ならファイルのパスは "~/.vim/after/ftplugin/vim.vim" です。

Note:
標準プラグインは "b:did_ftplugin" を設定しますが、ここではそれを無視してゐます。

オプション

ファイルタイププラグインでは、カレントバッファの設定だけを變更するため、次のコマンドを使つてオプションを設定してください:

:setlocal

そして、バッファローカルなオプションだけを設定してください (どのオプションがさうなのかはヘルプで確認してください)。|:setlocal| コマンドでグローバルオプションやウィンドウローカルオプションを設定すると、たくさんのバッファの設定が變更されます。ファイルタイププラグインはそのやうな動作をすべきではありません。

オプションの値がフラグや設定項目のリストなら、"+=" や "-=" を使ふことで既存の設定を維持することができます。ユーザーがそのオプションの設定を變更してゐる可能性もあるので注意してください。最初に初期設定に戾してから設定を變更するといいかもしれません。例:

:setlocal formatoptions& formatoptions+=ro

マップ

カレントバッファの中だけで機能するマップを作るには次のコマンドを使ひます:

:map <buffer>

上述したやうに、マップは二段階に分けて作る必要があります。ファイルタイププラグインで機能を定義する例を示します:

if !hasmapto('<Plug>JavaImport')
map <buffer> <unique> <LocalLeader>i <Plug>JavaImport
endif
noremap <buffer> <unique> <Plug>JavaImport oimport ""<Left><Esc>

|hasmapto()| を使つて、ユーザーが既に <Plug>JavaImport に對してマップを定義してゐるかどうかを調べます。未定義ならファイルタイププラグインの標準のマップを定義します。マップは <LocalLeader> で開始します。さうすることで、ファイルタイププラグインのマップを開始するキーをユーザーが選擇できます。初期設定はバックスラッシュです。

"<unique>" を使つて、マップが既に存在したとき、あるいは既存のマップと重複したときにエラーメッセージが表示されるやうにします。

|:noremap| を使つて、ユーザーが定義した他のマップの影響を受けないやうにします。":noremap <script>" を使ふと、スクリプトの中で定義した <SID> で始まるマップだけが再マップされます。

ユーザーがファイルタイププラグインのマップを無效化できる仕組みを提供しなければなりません。例へば、"mail" ファイルタイプのプラグインなら次のやうにします:

" マップを追加する。ユーザーが望まない場合は追加しない。
if !exists("no_plugin_maps") && !exists("no_mail_maps")
" "> " を插入して引用する
if !hasmapto('<Plug>MailQuote')
vmap <buffer> <LocalLeader>q <Plug>MailQuote
nmap <buffer> <LocalLeader>q <Plug>MailQuote
endif
vnoremap <buffer> <Plug>MailQuote :s/^/> /<CR>
nnoremap <buffer> <Plug>MailQuote :.,$s/^/> /<CR>
endif

ここでは 2 つのグローバル變數が使はれてゐます:

|no_plugin_maps|すべてのファイルタイププラグインのマップを無效化
|no_mail_maps|"mail" ファイルタイプのマップを無效化

ユーザー定義コマンド

ファイルタイプ用のユーザー定義コマンドを追加して、それを 1 つのバッファの中だけで使へるやうにするには、|:command| の引數に "-buffer" を指定します。例:

:command -buffer  Make  make %:r.s

變數

ファイルタイププラグインは對應するすべてのバッファに對して實行されます。スクリプトローカル變數 |s:var| はすべての實行で共有されます。バッファごとの變數を使ひたい場合はバッファローカル變數 |b:var| を使つてください。

函數

函數は一度だけ定義すれば十分です。しかし、ファイルタイププラグインは對應するファイルが開かれるたびに讀み込まれます。次のやうにすると函數が一度だけ定義されるやうになります:

:if !exists("*s:Func")
:  function s:Func(arg)
:    ...
:  endfunction
:endif

アンドゥ

ユーザーが ":setfiletype xyz" としたとき、それ以前のファイルタイプの效果は無效になるべきです。b:undo_ftplugin 變數にコマンドを設定し、ファイルタイププラグインの設定をアンドゥするやうにしてください。例:

let b:undo_ftplugin = "setlocal fo< com< tw< commentstring<"
    \ . "| unlet b:match_ignorecase b:match_words b:match_skip"

":setlocal" でオプション名の後に "<" を付けると、そのオプションをグローバルな値でリセットします。オプションをリセットするにはこの方法が一番です。

このやうに行繼續を使ふには ’cpoptions’ から "C" フラグを取り除く必要があります。上述の |use-cpo-save| を參照してください。

インデントスクリプトの效果をアンドゥする爲には、それに應じた b:undo_indent 變數を設定すべきです。

ファイル名

ファイルタイププラグインのファイル名にはファイルタイプ名が含まれてゐなければなりません |ftplugin-name|。次の 3 つのうちのどれかにしてください:

.../ftplugin/stuff.vim
.../ftplugin/stuff_foo.vim
.../ftplugin/stuff/bar.vim

"stuff" はファイルタイプ名、"foo" と "bar" は任意の名前です。

要約

ファイルタイププラグインの特有事項を要約します:

<LocalLeader>

"maplocalleader" の値。ユーザーがその變數にキーを設定することで、ファイルタイププラグインのマップの開始キーを指定できる。

:map <buffer>

バッファローカルなマップを定義する。

:noremap <script>

同スクリプトで定義してゐる <SID> で始まるマップだけを再マップする。

:setlocal

カレントバッファのオプションのみ設定する。

:command -buffer

バッファローカルなユーザー定義コマンドを定義する。

exists("*s:Func")

函數が定義濟かどうかをチェックする。

プラグイン全般に關する事項は |plugin-special| を參照してください。

コンパイラプラグインを書く

コンパイラプラグインは特定のコンパイラを使ふためのオプションを設定します。ユーザーは |:compiler| コマンドでその設定を讀み込むことができます。設定されるオプションは主に ’errorformat’ と ’makeprg’ です。

百聞は一見に如かず。次のコマンドですべての標準コンパイラプラグインを開くことができます:

:next $VIMRUNTIME/compiler/*.vim

|:next| を使つて次のプラグインファイルに移動してください。

これらのファイルには 2 つの特有事項があります。1 つは、標準ファイルに對して設定を追加したり上書きしたりできる仕組みです。標準ファイルの先頭は次のやうになつてゐます:

:if exists("current_compiler")
:  finish
:endif
:let current_compiler = "mine"

コンパイラファイルを書いて、それを個人用のランタイムディレクトリ (例へば Unixなら ~/.vim/compiler) に置いたとき、"current_compiler" 變數を設定することで標準ファイルの設定をスキップすることができます。 2 つ目は、":compiler!" が使はれたときは ":set" を使ひ、":compiler" が使はれたときは ":setlocal" を使ふ仕組みです。Vim はそのために ":CompilerSet" といふユーザーコマンドを定義します。古い Vim はそれを定義しないので、プラグインの中で定義してください。例:

if exists(":CompilerSet") != 2
command -nargs=* CompilerSet setlocal <args>
endif
CompilerSet errorformat&                " use the default 'errorformat'
CompilerSet makeprg=nmake

コンパイラプラグインを書いて、それを Vim の配布物に含めたり、システムのランタイムディレクトリに入れたりする場合は、上記の方法を使つてください。 "current_compiler" がユーザープラグインで設定された場合は何も實行しないやうにします。

コンパイラプラグインを書いて標準プラグインの設定を上書きする場合は "current_compiler" をチェックしないやうにします。そのプラグインは最後に讀み込まれないといけないので、’runtimepath’ の最後にあるディレクトリに置きます。例へば、Unix なら ~/.vim/after/compiler などです。

プラグインを書く (高速ロード版)

プラグインが成長し、とても大きくなることがあります。すると、起動速度は遲くなつてきます。例へそのプラグインをたまにしか使はないとしても遲くなります。さういふときはクイックロードプラグインの出番です。

基本的なアイデアはプラグインを 2 回に分けて讀み込むといふことです。1 囘目はユーザー定義コマンドやマップを定義して機能を提供します。2 囘目は機能を實裝する函數を定義します。

スクリプトを 2囘讀み込むことがクイックロードだといふと驚かれるかもしれません。この手法の意味は、1 囘目は高速に讀み込み、スクリプトの重い部分は 2 囘目に後回しにするといふことです。2 囘目の讀み込みは、ユーザーが實際にその機能を使用したときに發生します。あなたがその機能を常に使ふなら、これは逆に遲くなつてしまひます。

Note: Vim 7 以降では代はりの方法があります。|41.15| で說明されてゐる |autoload| 機能を使ふ方法です。

次に例を示します:

" クイックロードのデモ用のグローバルプラグイン
" Last Change:  2005 Feb 25
" Maintainer:   Bram Moolenaar <Bram@vim.org>
" License:  This file is placed in the public domain.

if !exists("s:did_load")
command -nargs=* BNRead  call BufNetRead(<f-args>)
map <F19> :call BufNetWrite('something')<CR>

let s:did_load = 1
exe 'au FuncUndefined BufNet* source ' . expand('<sfile>')
finish
endif

function BufNetRead(...)
echo 'BufNetRead(' . string(a:000) . ')'
" read 機能をここに書く
endfunction

function BufNetWrite(...)
echo 'BufNetWrite(' . string(a:000) . ')'
" write 機能をここに書く
endfunction

このスクリプトが最初に讀み込まれたとき、"s:did_load" は設定されてゐません。"if" と "endif" の閒のコマンドが實行されます。|:finish| コマンドによつて終了し、スクリプトの殘りの部分は實行されません。

2 囘目に讀み込まれたときは "s:did_load" が存在するので、"endif" 以降のコマンドが實行されます。この部分では (長くなる可能性のある) BufNetRead() 函數と BufNetWrite() 函數を定義します。

このスクリプトをプラグインディレクトリに置くと、Vim の起動時に實行されます。處理の流れは次のやうになります:

  1. 起動時にスクリプトが讀み込まれる。"BNRead" コマンドが定義され、<F19> キーにマップが設定される。自動コマンドの |FuncUndefined| が定義される。":finish" コマンドによつてスクリプトが終了する。
  2. ユーザーが BNRead コマンド實行する、または <F19> キーを押す。BufNetRead() 函數か BufNetWrite() 函數が呼び出される。
  3. Vim はその函數を見つけることができず、自動コマンドの |FuncUndefined| イベントを發行する。函數名が "BufNet*" といふパターンにマッチするので、"source fname" コマンドが實行される。"fname" はスクリプトの名前になります。スクリプトがどこに保存されてゐても、"<sfile>" が展開されてファイル名になります (|expand()|參照)。
  4. スクリプトが再び讀み込まれる。"s:did_load" 變數が存在するので函數が定義される。

遲延ロードされる函數の名前が |FuncUndefined| 自動コマンドのパターンにマッチしてゐることに注意してください。他のプラグインがこのパターンにマッチする函數を定義してゐるとうまく動きません。

ライブラリスクリプトを書く

いろいろな場所で同じ機能が必要になることがあります。コードが 2、3 行以上になる場合は、それを 1 つのスクリプトに入れて、他のスクリプトから使へるやうにしたくなると思ひます。そのやうなスクリプトをライブラリスクリプトと呼びます。

自分でライブラリスクリプトを讀み込むことは可能ですが、同じスクリプトを二重に讀み込まないやうにする必要があります。それには |exists()| 函數を使ひます。例:

if !exists('*MyLibFunction')
    runtime library/mylibscript.vim
endif
call MyLibFunction(arg)

runtimepath’ に設定されたディレクトリの中の "library/mylibscript.vim" の中で MyLibFunction() が定義されてゐる必要があります。

これをより簡單にするために、Vim には autoload といふ仕組みがあります。同じことを次のやうに書くことができます:

call mylib#myfunction(arg)

この方がずつと簡單でせう? Vim は函數の名前を見て、それが未定義なら、’runtimepath’ の中から "autoload/mylib.vim" を探します。そのスクリプトは函數 "mylib#myfunction()" を定義してゐなければなりません。

mylib.vim には他の函數も入れられます。ライブラリスクリプトの中では自由に函數を作ることができます。ただし、函數名の ’#’ より前の部分はスクリプトの名前と同じにする必要があります。さうしないと Vim はどのスクリプトを讀み込めばいいのかわかりません。

ライブラリスクリプトをたくさん書く場合は、サブディレクトリを使ふといいかもしれません。例:

call netlib#ftp#read('somefile')

Unix では、このライブラリスクリプトは次のやうな場所に置かれます:

~/.vim/autoload/netlib/ftp.vim

函數は次のやうに定義します:

function netlib#ftp#read(fname)
    "  ftp を使つてファイルを讀み込む
endfunction

函數定義と函數呼び出しではまつたく同じ名前が使はれます。最後の ’#’ より前の部分がサブディレクトリとスクリプトの名前に對應してゐます。

同じ方法で變數を扱ふこともできます:

let weekdays = dutch#weekdays

これによつて "autoload/dutch.vim" が讀み込まれます。そのスクリプトには例へば次のやうなコードが書かれてゐます:

let dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
    \ 'donderdag', 'vrijdag', 'zaterdag']

より詳しくは |autoload| を參照してください。

Vim script を配布する

Vim ユーザーは Vim のウェブサイト http://www.vim.org でスクリプトを探します。便利なスクリプトを作つたら、ぜひ共有しませう!

Vim script はどのシステムでも使へます。tar や gzip コマンドは存在しないことがあります。ファイルをまとめたり壓縮したりするには "zip" ユーティリティが推奬されてゐます。

可搬性を最大限に高めるには、Vim 自身を使つてスクリプトをパッケージ化します。それには Vimball ユーティリティを使ひます。|vimball| を參照。

自動更新するための行を書いておくと便利です。|glvs-plugins| を參照。


Next: , Previous: , Up: 目次   [Index]