*usr_52.txt*	For Vim バージョン 9.0.  Last change: 2022 May 21

		     VIM USER MANUAL - by Bram Moolenaar

			Vim9 script でプラグインを作る


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

|52.1|	導入
|52.2|	変数の宣言
|52.3|	関数と型
|52.4|	旧来のスクリプトから Vim9 script を使う

次章: |usr_90.txt|  Vim のインストール
前章: |usr_51.txt|  プラグインを作る
目次: |usr_toc.txt|

==============================================================================
*52.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` コマンドを使っていないこ
とです。これについては次の節で説明します。

==============================================================================
*52.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'

==============================================================================
*52.3*	関数と型

旧来の Vim script はコード実行時にのみ型のチェックがありました。そしてそれは寛
容で、ときどきエラー報告ではなく処理によって不明な値となっていました。結果とし
て関数が定義できかつ正常であると思えても、問題が通知されるのは常に関数の呼び出
し後でした: >
	func Concatenate(base, add)
	   return a:base + a:add
	endfunc

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

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

ここでは直ちにコンパイルを実行するために `:defcompile` を使っており、それがな
いなら関数が最初に呼ばれるときにコンパイルされるでしょう。Vim はあなたが間違っ
ていると警告します: >
	E1051: Wrong argument type for +

補足: ここでは旧来のスクリプトでの話です。Vim9 script を使う場合はスクリプトの
最後に `:defcompile` を置くことで、定義されるすべての関数の定義によるエラーが
チェックされます。

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

==============================================================================
*52.4*	旧来のスクリプトから 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:
