【vimめも】 15. Vim scriptの基本

## 変数

### 宣言とスコープ

```vim
" 変数の定義
let foo = 4

" 変数の削除
unlet foo
```

変数にはスコープがあり、変数名の前に`l:`などを付けて指定する  
省略した場合は、関数内であれば`l:`、それ以外であれば`g:`となる

- b  
現在のバッファにローカル
- w  
現在のウィンドウにローカル
- t  
現在のタブページにローカル
- g  
グローバル
- l  
関数にローカル
- s  
`:source`されたVim scriptにローカル
- a  
関数の引数(関数内のみ)  
`let`時には指定できない
- v  
グローバル、Vimがあらかじめ定義

変数を作成の際だけでなく代入の際も`let`をつける

```vim
let l:foo = 1

" 代入
let l:foo = 3
```

コンソール出力

```vim
let foo = 1
echo foo
"=> 1
```

### 型

#### 数値

```vim
" 数値
let foo = 1
"=> 1

" 加算
let foo += 2
"=> 3

" 減算
let foo -= 1
"=> 2
```

#### 文字列

```vim
" 文字列
let foo = 'a'
let foo = "a"

" 文字列の連結
let bar = foo . 'bc'
```

#### リスト

```vim
" リスト
let foo = ['a', 'b']
let bar = ['c', 'd']
"=> ['a', 'b']

" 連結( + )
foo + bar
"=> ['a', 'b', 'c', 'd']
let foo += bar
"=> ['a', 'b', 'c', 'd']

" 取り出し
foo[2]
"=> 'c'

" 最後の要素を取り出し
foo[-1]
"=> 'd'

" 部分リスト
" 2番目から最後まで
let endlist = foo[2:]
"=> ['c', 'd', 'e']

" 1個の要素からなるリスト: [3]
let shortlist = foo[2:2]
"=> ['c']

" リストのコピーを作る
let otherlist = foo[:]
"=> ['a', 'b', 'c', 'd', 'e']

" 変更
let foo[4] = 'f'
"=> ['a', 'b', 'c', 'd', 'f']
```

#### 辞書

改行する際は、次行の行頭に `\` をつける

```vim
" 辞書
let dict = {'foo': 23, 'bar': 4}

" 辞書
let person = {
\ 'name': 'ryo',
\ 'height': 176,
\ 'weight': 64,
\ 'like': {
\   'drink': 'japan-sake'
\ },
\ 'birthday': [1993, 12, 29]
}

person["name"]
"=> 'ryo'
person.name
"=> 'ryo'
```

## 条件

trueやfalse型はない[1]  
真理値には数値が使われる。0は偽を意味し、非0は真を表す

```vim
if 1
  " 通る
else
  " 通らない
endif

if 0
  " 通らない
else
  " 通る
endif

if 0
  " 通らない
elseif 1
  " 通る
endif
```

[1]: JSON解析の互換として`v:true``v:false`はあるが、基本的には1/0

## ループ

リストを使用

```vim
let list = [3, 4, 6, 1]
for item in list
  echo item
endfor
"=> 3
"=> 4
"=> 6
"=> 1

let index = 0
while index < len(list)
  echo list[index]
  let index += 1
endwhile

for item in list
  if item == 4
    " 次に進む"
    continue
  endif

  if item == 6
    " ループを抜ける
    break
  endif

  echo item
endfor
```

## エラー制御

```vim
try
  sleep 10
  " 例外を投げる
  throw "error"
catch /^Vim:Interrupt$/
  echo 'Ctrl + c でキャンセルされました'
catch /^error$/
  echo "errorを検知"
catch
  " 例外すべて補足
  echo '例外発生'
finally
  " 必ず実行
  echo is_wait ? '成功' : '失敗'
endtry
```

## 式

- 三項演算子

```vim
empty(list) ? 'a' : 'b'
```
- OR

```vim
exist('list') || empty?(list)
```
- AND

```vim
exist('list') && empty?(list)
```
- 比較演算

```vim
" 等しい
a == b
" 等しくない
a != b
" より大きい
a > b
" 大きいか等しい
a >= b
" より小さい
a < b
" 小さいか等しい
a <= b
" 正規表現にマッチする
a =~ b
" 正規表現にマッチしない
a !~ b
```

- 演算

```vim
" 足し算
a + b
" 引き算
a - b
" 文字列連結
a . b
" 掛け算
a * b
" 割り算
a / b
" 割った余り
a % b
```

- その他

```vim
" 論理否定
!a
```

## 関数

関数を実行のみの場合は`call`を前につける  
それ以外の場合はcallは付けない

```vim
let list = [1, 2, 3]
call add(list, 4)
echo list
"=> [1, 2, 3, 4]

```

### 全般で使用する関数

```vim
" コピー（浅い）
let l:bar = copy(list)

" コピー（深い）
let l:bar = deepcopy(list)

" 変数が定義されているか
if exists('foo')
endif

" 機能がサポートされているか
if has('mac')
endif
```

### 文字列でよく使用する関数

```vim
" 文字列が空か
if empty(str)
endif

" 文字列を評価
if eval("a == " . prefix . "_value")
endif
```

### リストでよく使用する関数

```vim
" 先頭に追加
call insert(list, 'a')

" 末尾に追加
call add(list, 'z')

" 削除(3番目の要素を削除)
call remove(list, 2)

" 削除(3番目から最後までを削除)
call remove(list, 2, -1)

" 並び替え
let sorted_list = sort(list)

" 反転
let reversed_list = reverse(list)

" 重複削除
let uniq_list = uniq(list)

" 数
let length = len(list)

" 最大値
let max_value = max(list)

" 最小値
let min_value = min(list)

let str = join(list, ',')

if empty(list)
endif
```

### 辞書でよく使用する関数

```vim
" 要素の追加（変更）
let dict['age'] = 24
let dict.age = 24

" 要素の削除
call remove(dict, 'name')
unlet dict['name']
unlet dict.name

echo keys(dict)
echo values(dict)
```
前回: [【vimめも】 14. grep]
(https://qiita.com/r12tkmt/items/bd740d6cad232dd1a294)