sci

最果て風呂

Vim のウインドウ変数等について調べたのだが...

これは下記の記事から続いているお話。

Vim の変数のスコープについて調べたら「わかってない」ということがわかった

先日の続きで変数のスコープについて調べる実験。問題と出会った時は、なるべく単純な例で実験するのが良い。そのような訳で、材料は下記のものとする。本当は変数ひとつひとつでファイルを分けたいのだけど、作業が繁雜すぎると面倒になって放り投げる可能性があるので、今回はこれでいく。はたしておいしく料理することができるだろうか?

目的

Vim editor は複数の編集モードを持つ、一風変わったエディタである。カスタマイズ性にすぐれ、プラグインと呼ばれるパーツを組み合わせることによって、さまざまな形態に変身させることができる。このプラグインはどれだけ利用しても課金されることはなく、小さなお子様を持つ親御さんのパソコンに安心して入れておける。

さて、カスタマイズするための方法はプラグインの利用によるものだけではなく、Vim script と呼ばれる自己増殖型拡張言語を用いて自分で記述することによっても実現できる。筆者もいくばくかのスクリプトを記述し、多数ある Vim script の変数のスコープについて理解しているつもりでいた。しかし先日の実験によりそれが誤りであることが明らかとなり、初歩に戻って理解する必要があることを悟った。

本実験の目的は、単純な構造のスクリプトを用いて「なんとなくこんなもんか」と自己満足することにある。厳密な論理なんてシラネ。なお、t: 変数もあるが、筆者はタブを使わないので除外する。

材料

  1. 本体: test.vim
let g:g_list = ["あ", "い", "う", "え", "お"]
let w:w_list = ["あ", "い", "う", "え", "お"]
let b:b_list = ["あ", "い", "う", "え", "お"]
let s:s_list = ["あ", "い", "う", "え", "お"]
  1. 補助: co-test.vim
echo len(g:g_list)
echo len(w:w_list)
echo len(b:b_list)
echo len(s:s_list)

方法

  1. 同じスクリプト 対照実験ではないが、1 と 2 を同じスクリプトファイルに書いた場合、エラーは出ない

  2. 同じウインドウ、別のバッファ、別のスクリプトファイル

:e test.vim
:source %
:e co-test.vim
:source %
  1. 別のウインドウ、別のバッファ、別のスクリプトファイル
:e test.vim
:source %
:C-w s
:e co-test.vim
:source %

予想

  1. 同じウインドウであるため g:, w: はエラーとならないが、別のバッファおよび別のスクリプトであるため、b:, s: はエラーとなる
  2. g: はエラーとならないが、別のウインドウおよび別のバッファおよび別のスクリプトであるため、w:, b:, s: はエラーとなる

結果

  1. 同じウインドウ、別のバッファ
5
5
Error detected while processing co-test.vim:
line    3:
E121: Undefined variable: b:b_list
E116: Invalid arguments for function len(b:b_list)
E15: Invalid expression: len(b:b_list)
line    4:
E121: Undefined variable: s:s_list
E116: Invalid arguments for function len(s:s_list)
E15: Invalid expression: len(s:s_list)
  1. 別のウインドウ、別のバッファ
5
Error detected while processing co-test.vim:
line    2:
E121: Undefined variable: w:w_list
E116: Invalid arguments for function len(w:w_list)
E15: Invalid expression: len(w:w_list)
line    3:
E121: Undefined variable: b:b_list
E116: Invalid arguments for function len(b:b_list)
E15: Invalid expression: len(b:b_list)
line    4:
E121: Undefined variable: s:s_list
E116: Invalid arguments for function len(s:s_list)
E15: Invalid expression: len(s:s_list)

考察

すべて予想通りの結果となった。g: はいついかなる状況下でもエラーとならずにアクセスすることができるようである。

次に w: であるが、同じウインドウ内であればバッファおよびスクリプトファイルが異っていてもアクセスすることが出来るが、別のウインドウでアクセスすることが出来ない。

最後に s: であるが、これはスクリプトファイルが異っているため、ウインドウ等が同じであってもアクセスすることが出来ない。

補助実験

手順は同じであるが、bufferswinnr() の結果をメモしておいた。

  1. 同じウインドウ、別のバッファ
:echo winnr() (test.vim )
test.vim 1
        
:echo winnr() (co-test.vim )
co-test.vim 1
        
:buffers (test.vim で)
  1 %a   "test.vim"                     line 1
  2 #    "co-test.vim"                  line 1
        
:buffers (co-test.vim で)
  1 #    "test.vim"                     line 1
  2 %a   "co-test.vim"                  line 1
  1. 別のウインドウ、別のバッファ
:echo winnr() (test.vim )
test.vim 2
        
:echo winnr() (co-test.vim )
co-test.vim 1
        
:buffers (test.vim で)
  1 %a   "test.vim"                     line 1
  2  a   "co-test.vim"                  line 0
        
:buffers (co-test.vim で)
  1 #a   "test.vim"                     line 1
  2 %a   "co-test.vim"                  line 1
        
:echo winnr() (test.vim で二分割を解除して一画面にした時)
test.vim 1

実験をしている過程で気が付き、最後の「二分割を解除して一画面にした状態」で調べてみた。すると、同じ test.vimwinnr() の値が 2 から 1 に変わっている。

この結果にかなり戸惑っている。自分は下記のようにウインドウとバッファに強い結び付きがあるものだと思っていたからだ。

window:buffer(test.vim)
window:buffer(co-test.vim)

例えば「window1 の buffer test.vim さん」のように、変更のないものだと思っていた。だから同じ test.vim だけれども、「window2 の buffer test.vim さん」の状態も可能であると。

あ〜、でもそうすると、二分割して同じファイルを編集している時に Vim が困るか。あくまでもバッファはバッファであり、ウインドウ番号は適宜変動するもだと理解しておけば良いのか?

追加実験

  1. 別のバッファ、別のスクリプトファイル、ただしウインドウの分割を解除する
:e test.vim
:source %
:C-w s
:e co-test.vim
:C-w o
:source %
  1. 別のバッファ、別のスクリプトファイル、いろいろやる
:e test.vim
:source %
:C-w s
:e co-test.vim
:C-w o
:bnext (test.vim になっている)
:source %
:bnext (co-test.vim になっている)
:source %

追加実験の結果

  1. 別のバッファ、別のスクリプトファイル、ただしウインドウの分割を解除する
5
Error detected while processing co-test.vim:
line    2:
E121: Undefined variable: w:w_list
E116: Invalid arguments for function len(w:w_list)
E15: Invalid expression: len(w:w_list)
line    3:
E121: Undefined variable: b:b_list
E116: Invalid arguments for function len(b:b_list)
E15: Invalid expression: len(b:b_list)
line    4:
E121: Undefined variable: s:s_list
E116: Invalid arguments for function len(s:s_list)
E15: Invalid expression: len(s:s_list)
  1. 別のバッファ、別のスクリプトファイル、いろいろやる
5
5
Error detected while processing co-test.vim:
line    3:
E121: Undefined variable: b:b_list
E116: Invalid arguments for function len(b:b_list)
E15: Invalid expression: len(b:b_list)
line    4:
E121: Undefined variable: s:s_list
E116: Invalid arguments for function len(s:s_list)
E15: Invalid expression: len(s:s_list)

追加実験の考察

追加実験 3. は本実験 2. と同じ結果となったので良いが、追加実験 4. は w: が成功してしまっている。こ・れ・は...もう一度 4. について追ってみよう。

:bnext で移動すると、co-test.vim と同じウインドウに居ることになり、そこで :source % をすれば、当然同じウインドウの変数になるってことになるのかな?

降参だぁ〜。とりあえず疑問点がわかったので :help windwos.jax を読む。OS の Windows のことじゃないからね。bufwinnr() というのもあるのね。