不器用な人のための digraph + f モーション

# はじめに

この記事は [Vim2 Advent Calendar](https://qiita.com/advent-calendar/2019/vim2) 22 日目の記事です． 21 日目の記事は [uyo](https://qiita.com/uyo) さんによる [vim helpから学ぶvim](https://qiita.com/uyo/items/2da52398e1408e956b21) でした． 23 日目は [hnishi](https://qiita.com/hnishi) さんの記事が入る予定です．

一年前，初参加の Advent Calendar で [Vim で縦方向 f 移動を実現した](https://qiita.com/monaqa/items/9764e957523ad0b56aec) という記事を書きました．
さらに先日， [gorilla.vim](https://gorillavim.connpass.com/) というイベントで [f モーションで縦横無尽に移動しよう](https://speakerdeck.com/monaqa/f-mosiyondezong-heng-wu-jin-niyi-dong-siyou) という発表をさせていただきました．

f モーション．大好きです．
しかし，実はまだ弱点が一つあります．それは **全角文字**． f モーションは「移動したい文字を直後に指定する」という性質上，日本語の文章を相手するのがそこそこ苦手です． Microsoft IME や Google 日本語入力などのメジャーな IME を使用する場合，普通にやろうとすれば， `f` の後に「かな」キーを押して目的の文字を打ってエンターを押してさらに「英数」キーを押して... なんてステップを踏むことになります．瞬時に移動するのが f モーションの醍醐味なのに，これでは魅力が半減どころか八割減という感じですね．悲しいことですが，そもそも日本語と Vim の相性はあまり良くないのかもしれません．

しかし，母語が日本語であるという事実も，愛用エディタが Vim であるという事実も，もはや本人の意思で変えることはできません．日本人 Vimmer にはもはや，「Vim をカスタマイズして少しでも日本語を使いやすくする」以外の選択肢は残されていないのです．ありがたいことに，Vim というエディタのポテンシャルとカスタマイズ性は計り知れません．少しでも日本語にやさしい Vim にして，メールに，ブログの下書きに，Slack [^1]に Vim を使いましょう．

[^1]: ちょうど今年の Vim Advent Calendar 2019 には higashi000 さんの [VimでSlackをしよう](https://qiita.com/higashi000/items/8a862f62f33e070f1622) という記事があります．

# 標準でできること

実は， Vim の **digraph** という機能を使えば，いくつかの全角文字なら入力モード（英数/かな）を切り替えずに f で移動することができます． digraph をシンプルに述べれば，こういう機能です．

> Digraphs are used to enter characters that normally cannot be entered by
> an ordinary keyboard.  These are mostly printable non-ASCII characters.  The
> digraphs are easier to remember than the decimal number that can be entered
> with CTRL-V (see |i_CTRL-V|).

...はい． `:help digraph` からの引用です．要は

* *通常の*キーボードからだと普通のやり方では打てないような文字を入力するときに使う
* もっぱら非 ASCII 文字を出力する
* 挿入モードの `CTRL_V` よりも覚えやすい[^2]

[^2]: 挿入モードの `CTRL-V` とは，Unicode を数字で指定して文字を打つ機能です．詳しくは `:help i^v` と打ってみましょう．さらに余談ですが，挿入モードで `<C-v><Tab>` とおせば，たとえ `'expandtab'` が恩になっていても`<Tab>` を補完のトリガなどに設定していてもタブ文字を打つことができます．

といったことが書かれています．そう，例えばこんな文書があったとしましょう．

> ほげほげ！ふがふが！ぴよぴよ！

「ほ」にカーソルがある状態から「ぴ」の部分に移動したくなったとします．そんなときは `f<C-k>pi` と打ってみてください．「かな入力」に切り替えなくても，ひらがなの「ぴ」の部分に移動できるはずです．

具体的に説明します． `<C-k>` とは digraph を入力するためのキーマップであり，このキーの後に特定の2文字を入力すれば，対応する文字が出力されます．実は f の直後だけなく， Insert モードや Command-line モードでも使うことができます．

## digraph 一覧の確認方法

`:digraphs` またはその短縮形 `:dig` で登録されている digraph の一覧を確認できます．ただし digraph はデフォルトで登録されているものだけでも 1000 以上あり，とても一目で追えるような数ではありません．デフォルトの digraph を検索したい場合は `:help digraph-table` を参照するのがおすすめです．以下のような見やすいテーブル形式で閲覧できます．コピペすれば TSV 形式のデータにもなります．

```
                                                        *digraph-table*
char  digraph   hex     dec     official name ~
^@      NU      0x00      0     NULL (NUL)
^A      SH      0x01      1     START OF HEADING (SOH)
^B      SX      0x02      2     START OF TEXT (STX)
^C      EX      0x03      3     END OF TEXT (ETX)
^D      ET      0x04      4     END OF TRANSMISSION (EOT)
^E      EQ      0x05      5     ENQUIRY (ENQ)
^F      AK      0x06      6     ACKNOWLEDGE (ACK)
^G      BL      0x07      7     BELL (BEL)
^H      BS      0x08      8     BACKSPACE (BS)
```

## 代表的な digraph

日本語の digraph をいくつか紹介します．

| digraph | 文字 |
| :-----  | :--- |
| `ka` | か |
| `sa` | さ |
| `ta` | た |
| `na` | な |
| `Ka` | カ |
| `Sa` | サ |


規則性が分かりやすいですね．基本的にローマ字入力通りに打てばひらがなが入力されます．また，1文字目を大文字にすればカタカナになります．ちょっと特殊なひらがな・カタカナも，以下のように打てます．

| digraph | 文字 |
| :-----  | :--- |
| `yA` | ゃ |
| `YA` | ャ |
| `a5` | あ |
| `A6` | ア |

小さい「ゃ」は2文字目を大文字にすればよいです．子音のない「あ行」は2文字目を「5」に，カタカナの「ア行」は「6」にします．

ひらがな・カタカナに飛べるのも便利といえば便利ですが， [スライド](https://speakerdeck.com/monaqa/f-mosiyondezong-heng-wu-jin-niyi-dong-siyou) で紹介したとおり， f モーションは記号を狙って移動すると非常に便利です．それは日本語の文章といえど例外ではありません．日本語では句読点を文の区切り目としますから，句読点に飛べたり，句読点を基準に文字のカットやヤンクができたりしたら便利ですよね．句読点以外にも全角疑問符，感嘆符，括弧，鍵括弧など，日本語で頻用される記号はたくさんあります．よく用いられる記号の digraph として，標準では以下のようなものが用意されています．

| digraph | 文字 |
| :-----  | :--- |
| `,_` | 、 |
| `._` | 。 |
| `<'` | 「 |
| `>'` | 」 |
| `<"` | 『 |
| `>"` | 』 |
| `("` | 【 |
| `)"` | 】 |
| `-?` | 〜 |
| `.6` | ・ |

うん，まあ，覚えれば良いんですが...なかなか大変そうですね...  少なくとも私は3日で忘れると思います．また，「全角疑問符」「全角感嘆符」「全角括弧 `（`」などは標準で用意されていませんでした．今のままだと，覚えにくいし抜けはあるしで，ちょっと使いにくいですね．

# カスタマイズしてもっと便利に飛ぶ

ちょっと使いにくい？ならカスタマイズすれば良いのです．

## digraph のカスタマイズ

実は， digraph はカスタマイズできます．つまり，好きな2文字のペアに対して好きな ASCII 文字を割り当てることができます[^3]．たとえば `<C-k>j.` と打って`。` が出てくるようにしたければ， `.vimrc` で以下のように設定します．

[^3]: ただし， 1文字目が `_` となるような digraph は登録しないほうがいいようです．

```vimscript
digraph j. 12290
```

このように， `digraph (登録したい2文字ペア) (出力したい文字の Unicode の十進表現)` という形で好きな digraph を登録できるのです．簡単ですね！

...え？追加したい文字の Unicode がわからない？心配無用です．なんと，Vim には標準で Unicode を調べるためのキーマップ `ga` があります．バッファ上の文字「。」にカーソルを置いてから `ga` と打てば，コマンドラインの行に

```
<。> 12290, 16進数 3002, 8進数 30002, ダイグラフ ._
```
と出てくるはずです．一番最初の数字が十進表現なので，それをそのまま使えば OK という訳です．また，既にその文字を入力するための digraph が登録されている場合は上の例のように digraph の2文字も併せて表示してくれる，そんな親切設計になっています．


これを使って自分だけの好きな digraph をつくってみましょう！ 2019年現在，私は以下のように設定しています（分かりやすいよう， digraph の設定の右にコメントで何の文字を登録しているか書いています）．

```vimscript
" カッコ
digraphs j( 65288  " （
digraphs j) 65289  " ）
digraphs j[ 12300  " 「
digraphs j] 12301  " 」
digraphs j{ 12302  " 『
digraphs j} 12303  " 』
digraphs j< 12304  " 【
digraphs j> 12305  " 】

" 句読点
digraphs j, 65292  " ，
digraphs j. 65294  " ．
digraphs j! 65281  " ！
digraphs j? 65311  " ？
digraphs j: 65306  " ：

" 数字
digraphs j0 65296  " ０
digraphs j1 65297  " １
digraphs j2 65298  " ２
digraphs j3 65299  " ３
digraphs j4 65300  " ４
digraphs j5 65301  " ５
digraphs j6 65302  " ６
digraphs j7 65303  " ７
digraphs j8 65304  " ８
digraphs j9 65305  " ９

" その他の記号
digraphs j~ 12316  " 〜
digraphs j/ 12539  " ・
digraphs js 12288  " 　
```

`j` + 半角記号 の組み合わせに統一することで，より覚えやすくしています．また，カッコについては自分がよく用いるものを優先的に登録しています．ちなみに，私は普段全角のカンマとピリオドを用いているため，digraph もカンマとピリオドを登録しています．句読点「、。」に飛ぶよう設定したい場合は，代わりに

```vimscript
digraphs j, 12289  " 、
digraphs j. 12290  " 。
```

とすればよいでしょう．

## f モーションのカスタマイズ

上の工夫で digraph は覚えやすくなりました．しかし，今のままでは全角閉括弧 `）` に飛ぶためだけに `f<C-k>j)` と 4 ストローク必要です（キーの数で言えば5つ）．自分，不器用ですから，4ストロークをちゃちゃっと打つというのはなかなかどうにも難しい...  半角閉括弧だったら `f)` の2ストロークで済むことを考えると，全角カンマだって，2ストロークとは言わずとも3ストロークぐらいには済ませたいものですよね．そこで，こんなふうにキーマップを定義してしまいます．

```vimscript
noremap fj f<C-k>j
noremap Fj F<C-k>j
noremap tj t<C-k>j
noremap Tj T<C-k>j
```

こうすると， `fj.` が `f<C-k>j.` と等価になり，上の digraph の設定と合わせれば `fj.` の3ストロークで全角ピリオドに飛べるようになります． `fj!` で「！」まで飛べますし， `ctj)` で全角閉括弧「）」の直前までカットすることもできます．まとめると，

- 半角記号に飛びたい→`f` / `t` / `F` / `T` + 飛びたい文字
- 全角記号に飛びたい→`f` / `t` / `F` / `T` +  `j` + 飛びたい文字の半角版

というふうに使い分ければ良いことになります．随分と分かりやすく，簡潔になりました．

なお，お気づきの方もいたかと思いますが，今のままでは `fj` というキーマップを潰してしまうため，半角の `j` に f モーションで飛びたいときに不便です．ついでに以下の digraph も登録するのがおすすめです．

```vimscript
digraphs jj 106  " j
```
これで， `fjj` と打てば半角の j に飛べるようになります． `j` に飛ぶときには余分な1ストロークが追加で必要となるものの，その分様々な全角文字にジャンプするときのストロークを節約できるようになる，というわけです．

# 終わりに

digraph + f モーションを使って快適に日本語移動する方法でした．この記事を作成しているときも，「あーこの表現まずいな，カンマ手前まで一気に消すか」などというときに大活躍しています．手前味噌ですが，かなり便利です．ぜひ設定してみてください！

ここまで読んでくださりありがとうございました．来年も Vimmer にとって良い年になりますように．