まずモード名だが、vim のように visual モードではなく、bound モードと呼ぶことにしたい。もしかしたら region モードにするかもしれない。
これを実装するにあたって、内部的には、本質的には単に選択領域の 2 つの端点だけを管理するだけの話だ。bound モードではカーソルが行末の改行にも乗れるようにする、とかカーソル(選択の終了点)が選択の開始点の前へ行った時のつじつま合わせとか、細々としたものはあるけれど、内部的には結局は 2 つの端点だ。
一方で、vim で visual モードというだけあって、見た目の部分が重要だ。つまり選択中の領域を反転表示させないといけない。DOM でこれをどう実現するか?
まずブラウザが持つ標準の範囲選択の仕組みをブラウザから制御するために selection がある。これだとまさに選択領域の両端点を指定するだけでいい。
var r = window.getSelection().getRangeAt(0);
r.setStart(text_node_of_lower_side, column_of_its_index);
r.setEnd(text_node_of_higher_side, column_of_its_index);
ただ、それがどう表示されるかは全くブラウザ任せになる。これは実際楽なのだけど、wasavi 側のテーマによっては判別しづらいものになるかもしれない。
次に DOM レベルで選択範囲を span でくくりだす方法もある。こちらは選択領域の更新を自前でやらないければいけないのがネックになる。一番簡単なのは、更新前に一旦すべての選択領域をクリアし(つまり span でくくりだされた部分を脱皮させる)、再度選択範囲をくくりだすのである。これだと特に選択範囲が何十行にも及ぶ場合に明らかに遅くなりそうではあるので、実際はそのへんは差分で管理しないといけないはずだ。
そういうわけでこんなかんじになる。いたってふつー。