vim-jp / vimdoc-ja / usr_51

usr_51 - Vim日本語ドキュメント

メインヘルプファイルに戻る English | 日本語 | 編集
usr_51.txt    For Vim バージョン 8.2.  Last change: 2022 May 14

                     VIM USER MANUAL - by Bram Moolenaar

                              プラグインを作る


プラグインを使用することで、特定のファイルの種別の設定、構文ハイライトやその他
多くの設定を定義できます。
この章ではVimプラグインでのもっとも共通な部分の書き方について説明します。

51.1  一般的なプラグインを書く
51.2  ファイルタイププラグインを書く
51.3  コンパイラプラグインを書く
51.4  プラグインを書く (高速ロード版)
51.5  ライブラリスクリプトを書く
51.6  Vim script を配布する

次章: usr_52.txt  Vim9 script でプラグインを作る
前章: usr_50.txt  高度な Vim script の書き方
目次: usr_toc.txt

==============================================================================
51.1  一般的なプラグインを書く                        write-plugin

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

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

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

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


名前
-----

最初にプラグインの名前を決めなければなりません。プラグインが提供する機能が名前
から分かるようにしてください。また、他の人が作ったプラグインと名前がかぶらない
ようにしてください。

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

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


ボディ
------

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

 14     iabbrev teh the
 15     iabbrev otehr other
 16     iabbrev wnat want
 17     iabbrev synchronisation
 18             \ synchronization

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

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


最初の行

  1     vim9script noclear

vimi9script を一番最初のコマンドとして使用する必要があります。一番最初の行に
記述するのがベストです。

作成しているスクリプトは、2回目にロードされたときに終了するための finish コ
マンドがあります。スクリプトで定義された項目が失われるのを防ぐために、
"noclear" 引数を使用します。詳しくは vim9-reload をご覧ください。


ヘッダー
------

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

  2     # Vim global plugin for correcting typing mistakes
  3     # Last Change:  2021 Dec 30
  4     # Maintainer:   Bram Moolenaar <Bram@vim.org>

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

  5     # License:      This file is placed in the public domain.


行継続と副作用の回避                                    use-cpo-save
--------------------

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

 11     var save_cpo = &cpo
 12     set cpo&vim
 ..
 42     &cpo = save_cpo

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

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


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

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

  7     if exists("g:loaded_typecorrect")
  8       finish
  9     endif
 10     g:loaded_typecorrect = 1

これはスクリプトの2重ロードで関数が無意味に再定義されることと自動コマンドが2重
に追加されるのを避ける効果もあります。

変数の名前は "g:loaded_" で始めてプラグインのファイル名をそのまま付けるように
してください。"g:" を付けることで変数をグローバルにし、他の箇所で機能があるか
チェックできるようにします。"g:" を付けないとスクリプトローカルになります。

finish を使ってファイルの残りの部分の読み込みを停止しています。Vimはコマンド
を解析して endif を見つける必要があるため、この方法はファイル全体を if-endif
で囲むよりもはるかに高速です。


マップ
------

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

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

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

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

        g: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() という関数を追加したとき、他のスクリプトでも同じ
名前の関数が定義されているかもしれません。そのような場合は、スクリプトの中だけ
で使える関数を定義します。
幸いにも、Vim9 script では、これがデフォルトです。旧来のスクリプトでは、名前
の前に "s:" を付ける必要があります。

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

 30     def Add(from: string, correct: bool)
 31       var to = input($"type the correction for {from}: ")
 32       exe $":iabbrev {from} {to}"
 ..
 36     enddef

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

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

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

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

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

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

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

これは少し複雑ですが、複数のプラグインを同時に使用するためには必要なことです。
基本的なルールとしては、マップの中では <SID>Add() を使い、他の場所 (スクリプト
の中、自動コマンド、ユーザー定義コマンド) では 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>" を使っています。これを使うとスクリプトローカルなマップだけが再
マップされます :map-<script>。26 行目でも ":noremenu" で同様のことをしていま
す :menu-<script>


<SID> と <Plug>                                         using-<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 Add(<q-args>, false)
 40     endif

ユーザー定義コマンドは、同じ名前のコマンドがまだない場合のみ定義できます。既に
定義されている場合はエラーになります。":command!" を使ってユーザー定義関数を上
書きするのは良いアイデアとは言えません。ユーザーは、自分が定義したコマンドがな
ぜ動かないのか不思議に思うでしょう。:command
だれの責任でそうなってしまったのか見付けるには:

        verbose command Correct


スクリプト変数
--------------

先頭に "s:" が付いた変数はスクリプト変数です。これはスクリプトの中だけで使えま
す。スクリプトの外からは見えません。同じ名前の変数を複数のスクリプトで使ってし
まうようなトラブルを避けることができます。Vim が実行されている間、変数は保持さ
れます。そして、同じスクリプトが再読み込みされると、再び同じ変数が使われます。
s:var

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

Vim9 script の良いところは、変数がデフォルトでスクリプトローカルであるという
ことです。必要に応じて "s:" を前に付けることができますが、そうする必要はありま
せん。また、スクリプト内の関数も、プリフィックスなしでスクリプト変数を使用する
ことができます。

スクリプトローカル変数は、スクリプト内で定義した関数、自動コマンド、ユーザーコ
マンド内でも使用できます。したがって、プラグイン内の部品間で情報を漏らさずに共
有するための最適な方法です。この例では、修正回数を数えるための行をいくつか追加
することができます:

 19     var count = 4
 ..
 30     def Add(from: string, correct: bool)
 ..
 34       count += 1
 35       echo "you now have " .. count .. " corrections"
 36     enddef

"count" はスクリプト内の 4 で宣言と初期化がされます。その後、Add() 関数が呼び
出されると、"count" がインクリメントされます。関数がどこから呼ばれたかにかかわ
らず、関数が定義されたスクリプトのローカル変数を使用します。


まとめ
------

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

  1     vim9script noclear
  2     # Vim global plugin for correcting typing mistakes
  3     # Last Change:  2021 Dec 30
  4     # Maintainer:   Bram Moolenaar <Bram@vim.org>
  5     # License:      This file is placed in the public domain.
  6
  7     if exists("g:loaded_typecorrect")
  8       finish
  9     endif
 10     g:loaded_typecorrect = 1
 11     var 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     var 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>"), true)<CR>
 29
 30     def Add(from: string, correct: bool)
 31       var to = input("type the correction for " .. from .. ": ")
 32       exe ":iabbrev " .. from .. " " .. to
 33       if correct | exe "normal viws\<C-R>\" \b\e" | endif
 34       count += 1
 35       echo "you now have " .. count .. " corrections"
 36     enddef
 37
 38     if !exists(":Correct")
 39       command -nargs=1  Correct  call Add(<q-args>, false)
 40     endif
 41
 42     &cpo = save_cpo

33 行目は説明がまだでした。これは、新しい修正をカーソルの下の単語に適用しま
す。:normal コマンドを使って新しい略語を適用しています。Note: マップと略語は
その場で展開されます。":noremap" で定義されたマップから関数が呼び出されたとし
ても動作は同じです。


ドキュメント                                            write-local-help
------------

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

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

  1     *typecorrect.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                                                     *typecorrect-settings*
 17     This plugin doesn't have any settings.

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

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

ヘルプの他の部分を参照するときは || で囲みます。そうすれば、ユーザーは簡単にヘ
ルプの関連した部分を参照することができます。


ファイルタイプの認識                                    plugin-filetype
--------------------

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

        au BufNewFile,BufRead *.foo             setlocal filetype=foofoo

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

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


要約                                                    plugin-special
-----

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

var name                スクリプトローカル変数。

<SID>                   スクリプトID。マップや関数をスクリプトローカルにする
                        のに使う。

hasmapto()              スクリプトが提供している機能に対して、ユーザーが既に
                        マップを定義したかどうかをチェックする関数。

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

map <unique>            マップが既に定義されているなら警告を発する。

noremap <script>        スクリプトローカルマップだけを使う。グローバルマップは
                        使わない。

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

==============================================================================
51.2  ファイルタイププラグインを書く  write-filetype-plugin ftplugin

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

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


無効化
------

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

        # このバッファに対してまだ実行されていない場合のみ処理を実行する
        if exists("b:did_ftplugin")
          finish
        endif
        b:did_ftplugin = 1

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

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

        vim9script
        b:did_ftplugin = 1

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

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

        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("g:no_plugin_maps") && !exists("g: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

ここでは二つのグローバル変数が使われています:
g:no_plugin_maps      すべてのファイルタイププラグインのマップを無効化
g:no_mail_maps        "mail" ファイルタイプのマップを無効化


ユーザー定義コマンド
--------------------

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

        command -buffer  Make  make %:r.s


変数
-----

ファイルタイププラグインは対応するすべてのバッファに対して実行されます。スクリ
プトローカル変数はすべての実行で共有されます。バッファごとの変数を使いたい場合
はバッファローカル変数 b:var を使ってください。


関数
-----

関数は一度だけ定義すれば十分です。しかし、ファイルタイププラグインは対応する
ファイルが開かれるたびに読み込まれます。次のようにすると関数が一度だけ定義され
るようになります:

        if !exists("*Func")
          def Func(arg)
            ...
          enddef
        endif


アンドゥ                                        undo_indent undo_ftplugin
--------

ユーザーが ":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 変
数を設定すべきです。

これら両方の変数は旧来のスクリプトの文法で使われ、Vim9 の文法では使いません。


ファイル名
----------

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

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

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


要約                                                    ftplugin-special
-----

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

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

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

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

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

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

exists("*s:Func")       関数が定義済かどうかをチェックする。

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

==============================================================================
51.3  コンパイラプラグインを書く              write-compiler-plugin

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

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

        next $VIMRUNTIME/compiler/*.vim

:next と打って次のプラグインファイルに移動してください。

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

        vim9script
        if exists("g:current_compiler")
          finish
        endif
        g:current_compiler = "mine"

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

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

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

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

==============================================================================
51.4  プラグインを書く (高速ロード版)         write-plugin-quickload

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

基本的なアイデアはプラグインを二回に分けて読み込むということです。一回目はユー
ザー定義コマンドやマップを定義して機能を提供します。二回目は機能を実装する関数
を定義します。

スクリプトを二回読み込むことがクイックロードだというと驚かれるかもしれません。
この手法の意味は、一回目は高速に読み込み、スクリプトの重い部分は二回目に後回し
にするということです。二回目の読み込みは、ユーザーが実際にその機能を使用したと
きに発生します。あなたがその機能を常に使うなら、これは逆に遅くなってしまいま
す。

ここでは FuncUndefined 自動コマンドを使います。Vim 7 以降では代わりの方法があ
ります。51.5 で説明されている autoload 機能を使う方法です。ここで使用した
旧来のスクリプトの代わりに Vim9 script も使えます。

次に例を示します:

        " クイックロードのデモ用のグローバルプラグイン
        " 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 コマンドによって終了
し、スクリプトの残りの部分は実行されません。

二回目に読み込まれたときは "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 自動コマンドのパターンにマッチし
ていることに注意してください。他のプラグインがこのパターンにマッチする関数を定
義しているとうまく動きません。

==============================================================================
51.5  ライブラリスクリプトを書く              write-library-script

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

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

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

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

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

        mylib#myfunction(arg)

この方がずっと簡単でしょう? Vim は # が含まれる関数の名前を見て、それが未定義
なら、'runtimepath' の中から "autoload/mylib.vim" を探します。そのスクリプトは
関数 "mylib#myfunction()" を定義していなければなりません。

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

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

        netlib#ftp#read('somefile')

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

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

関数は次のように定義します:

        def netlib#ftp#read(fname: string)
                #  ftp を使ってファイルを読み込む
        enddef

関数定義と関数呼び出しではまったく同じ名前が使われます。最後の '#' より前の部
分がサブディレクトリとスクリプトの名前に対応しています。

同じ方法で変数を扱うこともできます:

        var weekdays = dutch#weekdays

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

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

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

==============================================================================
51.6  Vim script を配布する                   distribute-script

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

別の場所として github があります。しかし、そこが探される場所であるとあなたは知
る必要があります!。多くのプラグインマネージャーがプラグインを github から取得
するというアドバンテージがあります。あなたが使うであろうお気に入りのサーチエン
ジンが見付けるのもそこになります。

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

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

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

==============================================================================

次章: usr_52.txt  Vim9 script でプラグインを作る

Copyright: see manual-copyright  vim:tw=78:ts=8:noet:ft=help:norl: