vim-jp / vimdoc-ja / usr_46

usr_46 - Vimドキュメント

メインヘルプファイルに戻る
usr_46.txt    For Vim バージョン 8.2.  Last change: 2020 Jun 14

                     VIM USER MANUAL - by Bram Moolenaar

                        Vim9 script でプラグインを作る


Vim9 script 言語はプラグイン、とりわけ複数のファイルからなる大きなものを書くの
に使えます。この章ではプラグインをモジュールとして分割し、アイテムをインポート
やエクスポートして局所性を維持する方法を解説します。

46.1  導入
46.2  変数の宣言
46.3  関数と型
46.?  旧来のスクリプトから Vim9 script を使う

次章: usr_90.txt  Vim のインストール
前章: usr_45.txt  言語を選択する (ロケール)
目次: usr_toc.txt

==============================================================================
46.1  導入                                            vim9-script-intro

Vim9 script は大きな Vim script を容易に書けるようにデザインされています。他の
スクリプト言語、特に TypeScript のようになっています。また、処理内の関数はコン
パイルされ素早く実行できます。これにより Vim9 script はとても速く、最大100倍に
なります。

基本的な考え方はスクリプトファイルにあるアイテムをプライベートとし、そのスクリ
プトファイル内からのみ利用し、そしてアイテムをエクスポートし、スクリプトファイ
ルの外から使うというものです。エクスポートされたアイテムはインポートしたスクリ
プトから使うことができます。これは定義された位置を非常に明確にできます。

さあサンプルから始めてみましょう、このスクリプトが1つの関数をエクスポートし、
もう1つのプライベートな関数があります:

        vim9script  " Vim9 script ファイルであることを示します。

        export def GetMessage(): string
           let result = ''
           ...
           result = GetPart(count)
           ...
           return result
        enddef

        def GetPart(nr: number): string
          if nr == 4
             return 'yes'
          else
             return 'no'
          endif
        enddef

vim9script コマンドはファイルのごく最初のコマンドとして置かれなくてはいけま
せん。これがないと Vim は旧来のスクリプトの文法であると見なします。

export def GetMessage(): string の行は export から始まっており、この関数は
インポート可能で他のスクリプトから呼び出せることを意味します。
def GetPart(... の行は export から始まっておらず、これがスクリプトローカル
の関数で、このスクリプトファイル内からしか使えません。

export def GetMessage(): string の行のコロンと戻り値の型に気付くでしょう。
def で定義された Vim9 関数は引数および戻り値の型を指定する必要があります。こ
れは Vim が効率的にコードをコンパイルできるようにするためです。GetPart 関数は
引数 "nr" の型が "number" であると定義されています。

注意すべきは result = GetPart(count) の代入は let コマンドを使っていないこ
とです。これについては次の節で説明します。

==============================================================================
46.2  変数の宣言                                      vim9-declarations

Vim9 script の変数は一度だけ :let もしくは :const コマンドによって宣言され
ます。値は :let 無しで代入され変数を :unlet することはできません。

よくあるケースとして、変数の宣言と初期化を同時にしたい時:
        let myText = 'some text'
        ...
        myText = 'other text'

変数の型は式から推論されます。この場合は文字列となり、数値で初期化した場合は型
は数値となります:
        let myNumber = 1234
        ...
        myNumber = 0

もし、この変数に文字列を代入したなら、エラーが検出されます:
        let myNumber = 'this fails!'

稀なケースとして任意の型の値を取る変数が欲しい場合、"any" 型を指定しなければな
りません:
        let myVar: any = 1234
        myVar = 'text also works'

値の代入なしで変数を宣言することもできます。このケースでは Vim は0もしくは空文
字列として初期化します:
        let word: string
        if condition
          word = 'yes'
        else
          word = 'no'
        endif

とはいえ、これは短くできます:
        let word = condition ? 'yes' : 'no'

==============================================================================
46.3  関数と型

旧来の Vim script は型のチェックがありましたが、ランタイムつまりコード実行時に
実施していました。そしてそれは寛容で、ときどきエラー報告ではなく処理によって不
明な値となっていました。結果として関数が定義できかつ正常であると思えても、問題
が発覚するのは常に呼び出した後でした:
        let s:collected = ''
        func ExtendAndReturn(add)
           let s:collected += a:add
           return s:collected
        endfunc

どの箇所に問題があると思いますか? 次を試してください:
        echo ExtendAndReturn('text')
すると0が見えるでしょう。なぜか? それは旧来の Vim script は "+=" が引数を数値
に変換し、そして数値のない任意の文字列では結果が0となるのです!

:def だと型チェックが関数のコンパイル時に行われます。それによってあなたは引
数の型と戻り値の型の指定が必要になります。また引数は "a:" のプリフィックス無し
で使われることに注意してください:
        let s:collected = ''
        def ExtendAndReturn(add: string): string
           s:collected += add
           return s:collected
        enddef
        defcompile

ここでは直ちにコンパイルを実行するために :defcompile を使っており、それがな
いなら関数が呼ばれるときにコンパイルされるでしょう。Vim はあなたが間違っている
と警告します:
        E1013: type mismatch, expected number but got string

Vim9 script は厳密で、"+" 演算子は数値か浮動小数点数でしか使えません。文字の結
合であれば ".." を使わなくてはなりません。これが間違いを防ぎ、上にあるような驚
きの結果をもたらす自動型変換を回避します。そして関数の最初の行をこう変化させれ
ば:
           s:collected ..= add
動くようになります。

もし関数が何も返さないなら、戻り値の型は無くてよいです:
        def ReportResult(result: string)
           echo 'The result is: ' .. result
        enddef

これもまたチェックされ、もし値を返そうとすると、エラーとなるでしょう。

あなたが型をケアしない場合や関数が多型で動くなら、"any" 型を使うことができます:

        def Store(key: string, value: any)
          resultDict[key] = value
        enddef

==============================================================================
46.?  旧来のスクリプトから Vim9 script を使う         source-vim9-script

いくつかの場合として持っている旧来の Vim script にて Vim9 script のアイテムを
使いたいことがあります。たとえばあなたの .vimrc がプラグインの初期化をする場合
などです。最良の方法は :import を使うことです。例:

        import Init as NiceInit from 'myNicePlugin.vim'
        call NiceInit('today')

これは Vim9 script からエクスポートされた "Init" 関数を見付けそれをスクリプト
ローカルなアイテム "NiceInit" として利用可能にします。"s:" を指定しなくても
:import は常にスクリプトの名前空間を使います。もし "myNicePlugin.vim" がすで
に読み込み済みであれば再度読み込まれることはありません。

その上アイテムがグローバルの名前空間に置かれるのを防ぎ (名前の衝突が不測の問題
になり得ます)、そしてたとえ何度もアイテムをインポートしても、スクリプトの読み
込みがただ一度であることを意味します。

いくつかの場合、例えばテストなどで、ただ Vim9 script を読み込みたいだけのこと
があります。大丈夫ですが、グローバルのアイテムだけが利用可能となります。Vim9
script ではこうしたグローバルのアイテムで確実にユニークな名前を使うようにしな
くてはなりません。 例:
        source ~/.vim/extra/myNicePlugin.vim
        call g:NicePluginTest()

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

次章: usr_90.txt  Vim のインストール

Copyright: see manual-copyright  vim:tw=78:ts=8:noet:ft=help:norl:
関連キーワード:  usr, Vim, 関数, let, スクリプト, string, アイテム, 変数, collected, result