1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

vim9script入門

Last updated at Posted at 2023-04-15

とほほのwww入門にあるプログラミング言語入門風の情報が欲しかったので、vimのヘルプからコピペ。
旧来の記載が残っているかも。

参考文献というかコピペ元

vimdoc-ja

ライセンス

コピペ元のライセンスに従います。

CC-BY-4.0 license

vim script 実行方法 

カレントバッファのスクリプトを実行

  1. vim で対象スクリプトのファイルを開く

    $ vim test.vim
    
  2. カレントバッファのスクリプトを以下のコマンドで実行

    :source %
    

コマンドラインから実行

$ vim -s test.vim

オートロードスクリプトを実行

  1. autoload ディレクトリにスクリプトを置く

    $ cp test.vim ~/.vim/autoload/
    
  2. vim から以下のコマンドで実行

    :call filename#function()
    

    これらの関数は常にグローバルで、Vim9 script なら "g:" が必要:

    :call g:filename#function()
    

コメント

# コメント

ヒアドキュメント

内部変数 {var-name} を文字列 {endmarker} で囲まれたテキスト行を含むリスト List に設定する。

var {var-name} =<< [trim] [eval] {endmarker}
text...
text...
{endmarker}
  • {endmarker} は空白を含んではならない

  • {endmarker} は小文字で始めることはできない

  • {endmarker} の行は他の文字を含めることができない

  • trim がない場合、テキスト行内のすべての空白文字は保持される。

  • trim が指定されている場合、最初の行のインデントがすべての行から取り除かれる

    let text =<< trim END
      if ok
        echo 'done'
      endif
    END
    
    結果: ["if ok", "  echo 'done'", "endif"]
    
  • eval が指定されない場合、リテラル文字列として扱われるが、
    シングルクォートは除外され2重にする必要はない。

  • eval が指定されている場合、{expr} 形式の任意の Vim の式が評価され、
    結果が文字列補間のように式を置き換える。

サンプル

var lines =<< trim END
  1行目
  2行目
  3行目
END
echo join(lines, "\n")

データタイプ

bool
number
float
string
blob
list<{type}>
dict<{type}>
job
channel
func
func: {type}
func({type}, ...)
func({type}, ...): {type}
void
tuple<a: {type}, b: {type}, ...>  # まだサポートされてない

true, false                     # 真偽値
-123, 0x10, 0177 0o177 0b1011   # 数値
123.456, 1.15e-6, -1.1e3        # 浮動小数点
"hello, world", 'hello!'        # 文字列
[1, 2, ['a', 'b']]              # リスト
{'blue': "#00f", 'red': "#f00"} # 辞書
function("strlen")              # 関数への参照
v:false, v:true, v:null         # 特殊値
job_start()を参照               # ジョブ
ch_open() を参照                # チャンネル
0zFF00ED015DAF                  # Blog (バイナリラージオブジェクト)

変数、定数 (var, const, final)

var lnum = 1

変数とその値、両方を定数とするには、:const を使用。

const myList = [1, 2]
myList = [3, 4]		# エラー!
myList[0] = 9		# エラー!
myList->add(3)		# エラー!

変数の変更のみを禁止するには、:final を使用

final myList = [1, 2]
myList = [3, 4]		# エラー!
myList[0] = 9		# OK
myList->add(3)		# OK

演算子

式文法一覧、優先順位の低いものから高い順に:

expr2 ? expr1 : expr1       # if-then-else
expr2 ?? expr1              # Falsy演算子
expr3 || expr3 ...          # 論理和
expr4 || expr4 ...          # 論理積
expr5 == expr5              # 等しい
expr5 != expr5              # とくしくない
expt5 >  expt5              # より大きい
expr5 >= expr5              # より大きいか等しい
expr5 <  expr5              # より小さい
expr5 <= expr5              # 小さいか等しい
expr5 =~ expr5              # 正規表現にマッチする
expr5 !~ expr5              # 正規表現にマッチしない
expr5 ==? expr5             # 文字列として等しい(大文字/小文字区別無し)
expr5 ==# expr5             # 文字列として等しい(大文字/小文字区別有り)
expr5 is expr5              # 同一のリスト List、辞書 Dictionary またはBlob のインスタンス
expr5 isnot expr5           # 異なるリスト List、辞書 Dictionary またはBlob のインスタンス
expr6 << expr6              # ビット単位の左シフト
expr6 >> expr6              # ビット単位の右シフト
expr7 +  expr7 ...          # 足し算、リストまたはBlobの連結
expr7 -  expr7 ...          # 引き算
expr7 .  expr7 ...          # 文字列の連結
expr7 .. expr7 ...          # 文字列の連結
expr8 *  expr8 ...          # 掛け算
expr8 /  expr8 ...          # 割り算
expr8 %  expr8 ...          # 剰余(割った余り)
<type>expr9                 # 型のチェックと変換 (Vim9 のみ)
! expr9                     # 論理否定
- expr9                     # 単項のマイナス
+ expr9                     # 単項のプラス
expr10[expr1]               # 文字列のバイト、またはリストの要素
expr10[expr1 : expr1]       # 文字列の部分文字列、またはリストの部分リスト
expr10.name                 # 辞書 Dictionary の要素
expr10(expr1, ...)          # Funcref 変数による関数呼び出し
expr10->name(expr1, ...)    # method 呼び出し
number                      # 数定数
"string"                    # 文字列定数。バックスラッシュは特別な意味を持つ
$"Hello, {name}!"           # 文字列補間
'string'                    # リテラル文字列定数。'を含めるには2重にする
[expr1, ...]                # リスト List
{expr1: expr1, ...}         # 辞書 Dictionary
&option                     # オプション変数
(expr1)                     # 式の入れ子
variable                    # 内部変数
$VAR                        # 環境変数
@r                          # レジスタ 'r' の値
function(expr1, ...)        # 関数呼出し
(args) => expr1             # Vim9 のラムダ式

代入

{var-name} = {expr1}            # 内部変数{var-name}に式{expr1}の結果をセット
{var-name}[{idx}] = {expr1}     # リストの要素に式{expr1}の結果をセット
{var-name}[{idx1}:{idx2}] = {expr1}
                                # リストListの一部を式{expr}の値で置き換え
{var} += {expr1}                # {var} = {var} + {expr1}
{var} -= {expr1}                # {var} = {var} - {expr1}
{var} *= {expr1}                # {var} = {var} * {expr1}
{var} /= {expr1}                # {var} = {var} / {expr1}
{var} %= {expr1}                # {var} = {var} % {expr1}
{var} .= {expr1}                # {var} = {var} . {expr1}
{var} ..= {expr1}               # {var} = {var} .. {expr1}
${env-name} = {expr1}           # 環境変数{env-name}に式{expr1}の結果をセット
@{reg-name} = {expr1}           # 式{expr1}の結果をレジスタ{reg-name}に書きこむ
&{option-name} = {expr1}        # オプション{option-name}に式{expr}の値をセット

リスト

var mylist = [1, two, 3, "four"]
var emptylist = []
var item = mylist[2]                    # 3番目の要素(3)を取得
var nestlist = [[11, 12], [21, 22], [31, 32]]
var longlist = [1, 2, 3] + [4, 5, 6]    # リストの連結
var otherlist = longlist[:]             # リストのコピー
var endlist = longlist[2:]              # 2番目から最後まで
var shortlist = longlist[2:2]           # 1個の要素からなるリスト

リストのアンパック

var [var1, var2] = mylist

変数の個数とリストの要素数が一致しないときはエラーになる。リストにある余分な要
素をまとめて受け取るには、";" と受け取る変数名を書いておく:

# 要素が 2 つしかないときでもエラーにはならない。"rest" は空リストになる。
var [var1, var2; rest] = mylist

リスト操作

var r = call(funcname, list)      # 引数リストをつけて関数を呼び出す
if empty(list)                    # リストが空かどうか判定する
var l = len(list)                 # リストの要素数
var big = max(list)               # リスト中の最大値
var small = min(list)             # リスト中の最小値
var xs = count(list, 'x')         # 'x' の出現回数を数える
var i = index(list, 'x')          # 最初に 'x' が現れる位置のインデックス
var lines = getline(1, 10)        # バッファから10行を取得
call append('$', lines)           # バッファに行を追加する
var list = split("a b c")         # 文字列を分割してリストにする
var string = join(list, ', ')     # リストの要素を連結して文字列にする
var s = string(list)              # リストの文字列表現
call map(list, '">> " .. v:val')  # 各要素の前に ">> " をつける

辞書

var mydict = {1: 'one', 2: 'two', 3: 'three'}
var emptydict = {}
var nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}

キーに対してループ

for key in keys(mydict)
   echo key .. ': ' .. mydict[key]
endfor

キーでソートした順にループ

for key in sort(keys(mydict))
   echo key .. ': ' .. mydict[key]
endfor

値に対してループ

for v in values(mydict)
   echo "value: " .. v
endfor

キーと値の両方でループ

for [key, value] in items(mydict)
   echo key .. ': ' .. value
endfor

辞書から要素を取り除く

var i = remove(dict, 'aaa')
unlet dict.aaa
unlet dict['aaa']

辞書操作関数

if has_key(dict, 'foo')           # 辞書がキー "foo" の要素を持つなら真
if empty(dict)                    # 辞書が空なら真
var l = len(dict)                 # 辞書の要素数
var big = max(dict)               # 辞書中の最大値
var small = min(dict)             # 辞書中の最小値
var xs = count(dict, 'x')         # 'x' の出現回数を数える
var s = string(dict)              # 辞書の文字列表現
call map(dict, '">> " .. v:val')  # 各要素の前に ">> " をつける

Blob

var b = 0zFF00ED015DAF
var b = 0zFF00.ED01.5DAF        # 読みやすくするために、ドットをバイト間(16進文字のペア)に挿入
var b = readfile('image.png', 'B')

Blobのインデックス

var myblob = 0z00112233
var byte = myblob[0]           # 1番目のバイトを取得: 0x00
var byte = myblob[2]           # 3番目のバイトを取得: 0x22
var last = myblob[-1]          # 最後のバイトを取得: 0x33
var byte = get(myblob, idx)    # 無効なインデックスに対するエラーを回避

Blobの繰り返し

for byte in 0z112233
   call Doit(byte)
endfor

Blobの連結

var longblob = myblob + 0z4455
var myblob += 0z6677

関数

def[!] {name}([arguments])[: {return-type}]

  • {name} : 100バイト未満
  • {reeturn-type} : 省略、あるいは void である場合は、何も返さないと想定される
  • {arguments} : 書式は以下の3つ
    • {name}: {type}
    • {name} = {value}
    • {name}: {type} = {value}
  • def : 最大 50 階層のネストが可能
  • [!] : ! を付けると既存の関数を上書きする

enddef

  • 関数の終了

関数定義

def Add(x: number, y: number): number
  return x + y
enddef

メソッド呼び出し

expr10->name([args]) 

これは次と同じである:

name(expr10 [, args])

あるメソッドが返す値を次のメソッドに渡して連鎖させることができる

mylist->filter(filterexpr)->map(mapexpr)->sort()->join()

ラムダの使用例:

GetPercentage()->{x -> x * 100}()->printf('%d%%')

ラムダ式 (クロージャ)

def Foo(arg: number): func
  var i = 3
  return (x) => x + i - arg
enddef

var Bar = Foo(4)
echo Bar(6)       # 5

ラムダ式には {} に複数のステートメントを含むことができる:

var Lambda = (arg) => {
  g:was_called = 'yes'
  return expression
}
  • いかなるコマンドも { の後ろに続けることはできない
  • 閉じの } は行の先頭

ラムダとクロージャのサポートは以下のように判定できる:

if has('lambda')

if - elseif - else - endif

var a = 5
if a == 5
  echo "5"
elseif a == 4
  echo "4"
else
  echo "others"
endif

while - endwhile

let lnum = 1
while lnum <= line("$")
  let lnum = lnum + 1
  echo lnum
endwhile

for - endfor

for item in [1, 2, 3, 4, 5]
  echo item
endfor

ループ制御(break, continue)

var n = 0
while (true)
  n += 1
  if n == 2
    continue
  endif
  if n == 8
    break
  endif
  echo n
endwhile

try - catch - finally - endtry

def Foo(value: any)
  try
    throw value
  catch /^\d\+$/
    echo "Number thrown"
  catch /.*/
    echo "String thrown"
  finally
    echo "finally"
  endtry
enddef

call Foo(0x1267)       # Number thrown
                       # finally
call Foo('string')     # String thrown
                       # finally
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?