VSCode カーソル移動を向上させる自作 Extension の紹介

# はじめに

Atom から VSCode に乗り換えました。
それに伴って Atom 用に細々と作成していたパッケージを、この度 VSCode の Extension として公開しました。
皆さんに使ってもらえるように紹介したいと思います。
(ほとんど怪しい英語で書いた ReadMe の日本語版です。)

# 作成したもの

`Boundary Move`
https://marketplace.visualstudio.com/items?itemName=BlueSilverCat.boundary-move

![capture](https://raw.githubusercontent.com/BlueSilverCat/boundary-move/image/image/capture.gif)

カーソルを `Unicode property`の境界単位で移動させるものです。
built-in コマンドに `cursorWordPartRight/cursorWordPartLeft` などがありますがそれのような挙動をします。
また、`jumpy` extension のようにジャンプ機能もあります。
built-in のコマンドとはカーソルが止まる場所が異なります。
こちらの方がより細かい位置に停止するようになります。
built-in のコマンドと比べると、特に日本語の文章の場合は、使い勝手が大幅に向上するかと思います。
(自然言語処理のような手法を取っていないので機械的な位置で止まってしまいますが)
ただ、プログラムや英語を書く場合にこそ真価を発揮すると思います。

## なぜこんなものを作ったのか

プログラムを書いていると、カーソル移動を頻繁にしなければいけないこともあります。
その時、1 文字ずつ Arrow key を押すのは面倒なだけです。
特に、Arrow key を押しっぱなしで移動できないような環境で作成していた時は、何とか減らせないかと思ったものです。
また、最近は入力補完が充実しているので長い変数名を修正する時などは、入力補完の候補を選択すれば良いだけです。
つまり、語(word)の中にカーソルを移動させ、1 文字ずつ修正するような場面は減っています。
言い換えれば、word 単位でカーソルを移動させれば快適という事です。
Atom や VSCode には、word 単位で移動できるコマンドが標準で用意されているのですが、これを通常のカーソル移動と置き換えてしまうと止まって欲しいところに止まらないことも多く逆に面倒な場面も多かったです。
そこで、この Extension を作成しました。

もしかしたら Vim などを使うと楽なのかもしれませんが、筆者は Vim に拒絶反応を起こし使えなかったのでこのようなものを作りました。

## 機能

- move: カーソルを文字境界単位で移動させる
- select: 文字列を境界単位で選択する
- jump: カーソルを指定した位置に移動させる
  - jump: 直接指定モード。文字境界にラベルが表示されるのでそれを入力してジャンプする
  - jump line: 行指定モード。行番号を指定してから、その行の文字境界を指定してジャンプする

### 停止位置詳細

例えば、以下のような文字列が有ったとします。

```javascript
function func1() {}
```

built-in コマンドの `cursorWordPartRight/cursorWordPartLeft` を使うと停止位置は、以下になります。
"‾"は、停止位置を表す。

```javascript
‾function‾ ‾func1‾(){}‾
```

何も支障はないと思われるかもしれませんが、個人的には、"()"や"{}"の内部にも止まって欲しいです。
そこで自作 Extension の出番です。
`Boundary Move`では停止位置は、以下になります。

```javascript
‾function‾ ‾func‾1‾(‾){‾}‾
```

これで引数を追加したい場合や、関数を実装するときにカーソルを合わせやすくなりました。

少し内部的な話をすると停止位置は、Unicode Property の General Category が切り替わった位置で停止するようになります。
上記の文字列を Unicode Property で表すと以下のようになります。
(こんな表記はありませんが意味は通じるかと思います。)

```
Ll{8} Zs{1} Ll{4} Nd{1} Ps{1} Pe{1} Ps{1} Pe{1}
```

Ll(Lowercase_Letter、英小文字など)が 8 個続いた後、Zs(Space_Separator、空白など)が 1 つ有り...という意味です。
英小文字と空白の間が最初の停止位置になり、次は空白と英小文字の間が停止位置になるという具合です。

#### Capital letter の検出

以下のような文字列が有ったとします。

```
CatLikeTuna
```

デフォルトの設定で停止位置は、以下になります。

```
‾Cat‾Like‾Tuna‾
```

場合によっては、大文字と小文字の境界で停止したいと思うかもしれません。
その場合は、設定で`boundary-move.capitalLetter`を`false`に設定すると以下の位置で停止するようになります。

```
‾C‾at‾L‾ike‾T‾una‾
```

#### Special characters

上で説明しましたが、この Extension は Unicode Property が切り替わった位置を停止位置とします。
そのため、以下のような文字列が有ると、

```
"Cat", "", "Dog",
```

停止位置は、以下のようになってしまいます。

```
‾"‾Cat‾",‾ ‾"",‾ ‾"‾Dog‾",‾
```

これでは、`""`の内部に文字を入力したい時には不便です。
このような時には、`boundary-move.specialCharacters` に `"` を設定します。
そうすると、停止位置は、以下になります。

```
‾"‾Cat‾"‾,‾ ‾"‾"‾,‾ ‾"‾Dog‾"‾,‾
```

`boundary-move.specialCharacters`に設定した文字は、いかなる時も停止位置として働きます。
もっとも、`"`は、デフォルト設定に含まれているので改めて設定する必要はありません。

#### Japanese support

以下のような日本語の文章があった場合、

```
猫は、マグロが大好きです。
```

デフォルト設定での停止位置は、以下になります。

```
‾猫は‾、‾マグロが大好きです‾。‾
```

このくらいの短い文章ならばなんとかなるかもしれませんが、大雑把すぎます。
日本語を頻繁に入力しなければならない場合は、`boundary-move.japanese`を`true`に設定してください。
そうすると停止位置は、以下になります。

```
‾猫‾は‾、‾マグロ‾が‾大好‾きです‾。‾
```

この停止位置も大分不備がありますが、これより向上させるのは荷が重いです。

### Jump

もともとカーソルを左右に動かすことのみ考えていたのですが、内部の実装的に容易にジャンプ機能が実現できそうだったのでジャンプ機能も付けました。
筆者は、Atom を使っていた時から`Jumpy`が好きだったのですが、痒いところに手が届かない事も多く作成することにしました。

Jump には、2 つの入力方法があります。

- 画面内の境界にラベルが表示され、それを入力することによりジャンプする `jump` コマンド
- はじめに行番号を入力し、その行の境界位置を指定することによりジャンプする `jumpLine`コマンド

となります。

# 最後に

多くの方に使ってもらえたら筆者が喜びます。
この記事だけだと、ただの宣伝なのでもっとソースコードに焦点を当てた記事も書きたいと思います。