Helix Editorのモードと基本操作

より網羅的な説明は:point_right:[DocumentのKeymap](https://docs.helix-editor.com/master/keymap.html)を参照すること

前半は説明と感想が主でキー操作は後半に行う

## Summary

| Mode | default key | 個人的な感想 |
| --- | --- | --- |
| Normal | Esc | 移動操作はvim/neovimとそこまで変わらないが，選択や編集が加わるとややこしさがアップ |
| Insert | i, a, A, I, etc... | selectに慣れるまではここもおぼつかないが，基本操作はvim/neovimと同じ |
| Select | v, w, e, b, %, etc... | vim/neovimと一番違う操作及びモード．慣れれば逆に使いやすいはず |
| Space | space | メタ的な操作が豊富で非常に便利．とりあえずspace+fでfzfを覚えれば良い |
| Match | m | テキスオブジェクトを使った操作全般はこれを使えば良く他のモードと組み合わせたり応用が利く |
| Goto | g | カーソル行移動，列移動などでよく使う．このモードからの移動に慣れると速い操作ができる |
| View | z | 画面位置を軽く調整する場合に利用できるがCtrl-fなどのデフォルトのキーマップの方が楽 |
| Sticky View | Z | コードを眺めるときにとりあえず起動すれば画面移動が楽 |
| Window | Ctrl-w <br> space+w | そこまで多用しないが，ウィンドウ操作がまとまっていてわかりやすい |
| Command | : | vimと同様に保存からレジスタからスクリプトの実行など便利な機能が豊富．私はまだ使いこなせていない |

`select mode/select`に慣れれば操作はvim/neovimと変わらない感じ

`select`に加えてマイナーモードと機能を合わせることでより編集が拡張される

逆に言えばこれらモードと機能の使い勝手が自分に合わなければvim/neovimで良いと思う

実際にディスカッションなどでvimのキーマッピングの仕方を尋ねている人がいたが，コントリビュータの方が「それだとhelixの思想と合っていないならおすすめしない(意訳)」ときちんと説明している

[vim/neovimのキーバインドバージョン](https://github.com/LGUG2Z/helix-vim)もあるので参考までに

## Basic Mode

- ノーマルモード(Normal mode)
- 挿入モード(Insert mode)
- 選択モード(Select/Extend mode)

大きく違うのがこの`Select/Extend mode`(以下選択モードまたは選択)になる

この`選択`がHelixではとても重要であるため[Manipulation](https://qiita.com/drafts/8a2c58e39ab345660722/edit#manipulation)の箇所で詳しく説明する

### ノーマルモード(Noraml Mode)

hjklで移動やCtrl+f, Ctrl+bで画面移動など移動系の操作は同じな気がする

デフォルトでノーマルモードのカーソル位置が一つの選択状態になっている

移動系全般は基本的には似た動作になる

違う移動系操作で分かりやすいのは`w`，`f`，`t`になる

`w`は単語の先頭に移動だが，vim/neovimとは違い単語の一文字目ではなくその単語の直前にカーソルが移動する(`e`は同じ)

また，昔のvimよろしく日本語文における`w`，`e`などの移動はスペース以外が全て一単語として扱われる

一応個人的に関数を作って対応したが，あまり使わない(動かないかも: [記事](https://qiita.com/GreasySlug/items/1875748b8ae782a4238a))

![japanese_w_e_move.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/e8dd969f-6d01-30ba-4753-8c8fb3beac4f.gif)

`f`，`t`はその行だけに限らず一文字を発見するまでとなり，繰り返し検索は`Alt+.`で押しにくかったりする

![f_t_find.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/da9e9c69-91e0-883a-61a5-f0175d30bb37.gif)

その他にもヤンク`y/Y`とペースト`p/P`はレジスタを利用し，システムクリップボードを利用する場合は `space+y/Y`，`space+p/P`になっていたりする

### 挿入モード(Insert Mode)

ノーマルモード・選択モードから挿入モードへの操作がvim/neovimと違う

一行目が`w`を押した後に`i`*3，`a`*3を押した場合，二行目が`e`を押した後に`i`*3，`a`*3を押した場合となる

![select_i_a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/9ad7be88-56c9-ea2b-1200-18c0a06601bc.gif)

この操作に同意できるかどうかが，helixを使っていくかvim/neovimに戻るかの違いだと思う

~~個人的にはここの行末にある単語で`w`を押した後に`a`で単語の後ろに追加で，次の行の冒頭に来るのが一番helixで嫌なところになる~~ 案外慣れます

こうなる理由は`改行(\n)`も一文字扱いだからである

そのため，`w`による「次の単語の前に移動」により`\n`まで移動して`a`で「後ろに挿入」だと，どうしても改行後の行頭に挿入することになってしまう

```text
// []が選択箇所を示す
iii[一行目\n]aaa二行目\n // w: 次の単語の前は"\n"
一行目\niii[二行目]aaa\n // e: 現在の文字の最後は"目"
```

補完はLSPが無いと補完はされない

インサート内でのペーストはCtrl+rだが，この時にレジスタが表示されるのでこれも初心者的には良いと思う

vim/neovimとは異なり，helixではデフォルトでレジスタには`"`しか保存されない

順次レジスタに保持されていかないので明示的に任意のレジスタに保存する必要がある

![スクリーンショット 2025-01-08 090256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/25edaca1-7006-7981-b19a-80b5b0890cf2.png)



## Minor Mode

vim/neovimでまとまっていないキーバインドや，プラグインの機能を入れてそれぞれのユーザーが独自に設定していたようなキーバインドをわかりやすくモードとして統合したもの

これらがキーコンボですぐに実行できる状態になっているが個人的にはHelixの中で非常に気に入っている

初心者にはありがたいポップアップや、エディタ自体のエンハンス系が初めから存在するのが良い

- `space`: スペースモード(space mode)
- `v` : 選択モード(select mode)
- `m`: マッチモード(match mode)
- `g`: 移動モード(goto mode)
- `z`: 視点モード(view mode)
- `Z`: 固定視点モード(sticky view mode)
- `:`: コマンドモード(command mode)
- `C-w`: 画面モード(window mode)

### スペースモード(Space Mode): space

![picker.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/025c2f63-9042-696b-266d-ffbf0b2013b5.gif)

様々な機能がとりあえず放り込まれたメタ的なモードになる

主な用途としてはピッカー(Picker)操作となる

いわゆるfuzzy finderにあたる機能になる

この中にある`f`, `F`の`file pikcer`と`s`の`symbole picker`をよく利用する

ディレクトリ内のファイルの検索やバッファー検索などtelescopeのような機能がある

他にもDebug機能やglobal searchも存在する

`?`でVSCodeなどにもあるようなコマンドパレットも開くともできる

### マッチモード(Match Mode): m

編集するときに非常に役立つモード

`'`が`"`に地味に変わっている

![match.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/155da2bc-a15b-edae-15f5-dea50ad33c45.gif)

単語の選択から関数の選択まで一気にできる

tree-sitterがある言語なら他にもクラスやコメント，パラメータなどにも対応できる

vim surroundやtext objectsなどをここで上手く扱うことができる

操作中は右下にポップアップが表示されるでそれを見ながら編集ができる

キー入力自体はvim/neovimよりも多くなってしまう

例えば，text objectsを使った操作は全般的にvim/neovimよりキー操作が増える

| キー | 前半 | 後半 |
| --- | --- | --- |
| miwms” | miw <br> 単語を選択 | ms” <br> 選択箇所の周りに”を追加 |
| maWms{ | maW <br> 記号と周りの空白を含めた単語を選択 | ms{ <br> 選択箇所の周りに{を追加 |
| mr({ | mr”’ <br> 選択箇所の周りにある(を{に置換 |  |
| md[ | md[ <br> 選択箇所の周りにある(を削除 |  |

前半のtext objectsを利用したvim surround系の操作がどうしても二回マッチモードを行い処理を行う必要がある

周りにある記号系を削除・変更する場合は選択されていなければ一番近い箇所が自動で選ばれる

そのため明示的に記号を選んで編集したいときは先述のmiやmaを使ったテキストオブジェクトの操作が必須になる

とりあえずはこのモードを経由して選択・変更に慣れれば編集がはかどるようになる

### 固定視点モード(Sticky View Mode): Z(z)

選択状態などを維持しつつコードを眺められるモード

視点モード(view mode)は視点移動するとポップアップが消えてノーマルモードへ変わる

このモードを使えば右下にポップアップを固定表示したまま連続で視点移動をすることができる

このモードを経由しなくてもノーマルモードでCtrl-fやCtrl-dなどの視点移動系は全て扱える

そこまで重要な気がしなくもないが，初心者にとってポップアップが表示されて忘れやすい画面移動系のキー操作を見れるのは嬉しいと思う

---

他にもコマンドモードや移動モードなどよく使うモードがあるが長くなるので省略する

これらマイナーモードはマッピングを追加したり，違うマッピングすることができる

他にもポップアップ表示される独自のマッピングも作れる

例えば

```toml
[keys.normal]
# {}でマッピングを追加すると，これがポップアップとして表示される
"space" = { w = ":write", q = ":quit" } # "wで保存"，”qで終了”がスペースモードに追加される
# 複数のコマンドを一気に実行したい場合は[]で囲む
"C-h" = ["select_all", "regex"] # "Ctrl+h"でファイル内を全て選択し置換できるようになる
```

## 再マッピングに関して

キーマップを変えたければキーではなく，コマンドをマッピングする

再帰マッピングができないのでそこは注意する

また，同時押しのキーマッピングはmodifierキーAlt，Ctrl，Shiftだけ

```vim:vim/neovim
inoremap jj <Esc> " キーを再マップしており
nnoremap j gj     " helixではこのようなマッピングはできない
```

```toml:helix
[keys.insert]
j = { j = "Normal" } # `コマンド`をキーにマッピングする
C-c = "esc" # このようなマッピングはできない
n-z-z = ["search_next", "align_view_middle"] # これもできないので{}で入子にする
n = { z = { z = ["search_next", "align_view_middle"] } } # 適当マッピング
[keys.normal]
space = { w = [":write", ":format"] } # 組み込みコマンドはコロンが必要
```
## Manipulation

helixを扱う上で大事なのは`選択操作`

これを使えないとまともに操作して編集ができない

vimmerが初見で絶対に慣れない操作は以下の通り

+ ビジュアルモードとノーマルモードがセットになった操作感
+ 常に選択箇所がハイライト表示(選択箇所の縮小は`;`)
+ xが行選択(S+vじゃない)
    + ddではなくxd
    + yyではなくxy
+ sが正規表現のマッチング
    + いきなり置換になる感じ
+ 矩形選択(Ctrl+v)がなくマルチカーソル(Shift+c)
+ dが選択箇所を削除
+ 選択状態からインサートモードへの移行
+ 改行が一文字扱い

初見でこれらが非常に煩わしく感じるが慣れれば案外使いやすい

### 操作基礎

[kakouneのサイトに違いが書かれてあるのでそれも参考になる](https://github.com/mawww/kakoune/wiki/Migrating-from-Vim)

c，d，yの御三家はよく使うオペレータだと思うのでこれを例にする

| vim/neovim    | helix             |
| ------------- | ------------------|
| ciw, diW, yiw | miwc, miWd, miwy  |
| caw, daW, yaw | mawc, maWd, mawy  |
| ci", di{, yi’ | mi"c, mi{d, mi’y  |
| ca", da{, ya’ | ma"c, ,ma{d, ma{y |
| cs"', ds(     | miwmr"', miWmd(   |
| C, D, y$      | vglc, vgld, vgly  |
| dd, yy        | xd, xy            |
| Vjd, Vjc, Vjy | xxd, xxc, xxy     |
| ggVGd         | %d                |

特徴として挙げられるのはこれら

+ マッチモード`m`を用いたテキストオブジェクトの選択
+ 日本語っぽい文法(目的語 述語)
+ 移動モード`g`を用いた列の選択
+ `x`による行選択
+ `%`による全体選択

一番特徴的なのは日本語っぽい文法だと個人的には思う

日本語の「関数内を選択(mif)してヤンク(y)」，「行を選択(x)してして削除(d)」がそのままキーストロークとして実現できる

ただ，vim/neovimよりもストロークが多くよく議論として出される

個人的に`C`と`D`が`vglc`と`vgld`なのはいただけない

`g`は今回説明していいない`移動モード`となっており，`gl`で行末まで移動となっている

また，全体を選択するときには`%`となっており全体を選択がやりすいが，覚えにくいとは思う

それ以外は`m`から始まっており，一貫したキーストロークで覚えやすい

ちなみに単語だけを選択したければ`miw`，`miW`よりも`eb`や`EB`の方が楽に選択できる

単語の頭にいれば`e`だけで単語全体が選択状態になるのでそのまま`d`で削除できる

このようにテキストオブジェクト内にいる時と，外にいる時で操作が微妙に異なる

関数やクラス内にいてこれらを選択する場合は`mif/c`で関数内から関数全体を選択できる

関数やクラスの外側近くにおりこれらを選択する場合は，今回説明していない`unipairedモード`を使ったパラグラフ移動や関数移動(`v]p`)などで選択できる

### 移動操作

| キー | 説明 | コマンド |
| --- | --- | --- |
| h, Left | 左へ | move_char_left |
| j, Down | 下へ | move_line_down |
| k, Up | 上へ | move_line_up |
| l, Right | 右へ | move_char_right |
| w, W | 次の単語の先頭へ | move_next(_long)_word_start |
| e, E | 次の単語の最後へ | move_next(_long)_word_end |
| b, B | 前の単語の先頭へ | move_prev(_long)_word_start |

これらはvim/neovimと同じようなカーソル移動の操作

しかし，これらを操作したときのエディタの挙動が異なる

見た目の違いとしても現れるのが`選択`である

vim/neovimのビジュアルモードにあたるが，より拡張的に扱える

ちなみにデフォルトでカーソル位置が一つの`選択`状態になっている

これら移動操作に`選択(select)`が組み込まれている

そのためw，Wなどは「次の単語の先頭へ移動」+「次の単語の先頭まで選択」の2つの意味を持つようになる

同様にfも「一文字を検索」+「一文字目までを選択」の2つの意味を持つようになる

| キー | 説明 | コマンド |
| --- | --- | --- |
| f | カーソル以降で一文字を検索 | find_next_char |
| t | カーソル以降で一文字をまで検索 | find_till_char |
| F | カーソル以前で一文字検索 | find_prev_char |
| T | カーソル以前で一文字見までを検索 | till_prev_char |
| Alt-. | 検索actionの繰り返し | repeat_last_motion |

先ほど説明した通り今いる箇所から見つけた箇所までを選択する

そのため`i`で選択箇所の前，`a`で選択箇所の後ろに挿入なので注意して使わないと検索したときにいたカーソル位置に誤って挿入してしまったりする

![f_t_find.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/78152a6e-51f4-5bfc-3e15-8eded15dd215.gif)


ただ，Rustなどで`collect();`する前に何かしらメソッドチェーンを書きたいときは`f;`でセミコロンまで移動すればすぐに追加できる

![f_search.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/ffae5439-067e-5da6-8ee7-dddfdf9d96b6.gif)

### 変更操作

| キー       | 説明 | コマンド |
| --------- | --- | --- |
| a         | **選択箇所**の後ろに挿入 | append_mode |
| i         | **選択箇所**の前に挿入 | insert_mode |
| A, end    | 行末に挿入 | append_to_line |
| I, home   | 行頭に挿入 | prepend_to_line |
| ~         | 大文字小文字切り替え | switch_case |
| u         | アンドゥ | undo |
| U         | リドゥ | redo |
| r         | 一文字で置換 | replace |
| R         | ヤンクした文章で置換 | replace_with_yanked |
| d         | **選択箇所**を削除 | delete_selection |
| .         | 最後の変更を繰り返す | N/A |
| “\<reg\>Q | 選んだレジスタにマクロの記録を開始/停止(デフォルトで") | record_macro |
| “\<reg\>q | 選んだレジスタから記録されたマクロを実行(デフォルトで") | replay_macro |

上記の選択モードからの変更操作が一番慣れが必要な個所になる

`w`, `e`, `b`なども`移動`+`選択`が組み合わせられている

選択箇所の`i`（始め）か`a`（後ろ）かを明確にキー操作で選択する必要性が出てくる

選択箇所

また，ドットとマクロは注意が必要になる

ただ，マクロが`q`ではなく`Q`なのは初心者的には嬉しい

`q`を誤って押して勝手に記録が開始されて焦るみたいなのが減る

`q`で実行するのも`@`よりもわかりやすいと思う

~~[Issue](https://github.com/helix-editor/helix/issues/2249)として挙がっているが，`Q:記録`で`q:再生`を記録できるせいでマクロが無限にスタックされるバグがあるので注意する~~ → [修正されました](https://github.com/helix-editor/helix/pull/2902)

また，挿入モードで説明した通り`”`でレジスタが表示されるのは良いなあと思う

vimでレジスタを上手に扱うのは初心者にはなかなかに難しい

だが，とりあえず`”`を押してレジスタを確認し，ペーストしたりヤンクする場所を決めたりできるので重宝する

### 選択

選択するだけではなく，選択後にもできる操作が複数ある

| キー   | 説明                                          | コマンド |
| ------ | -------------------------------------------- | --- |
| v      | 選択モードへ移行                               | select_mode |
| s      | 選択箇所内で正規表現に一致する箇所を全て選択     | select_regex |
| x      | 行を選択                                      | extend_line |
| ;      | 選択範囲を一つに縮小                           | collapse_selections |
| Alt-;  | 選択箇所のカーソル位置とアンカー(初期位置)を反転 | flip_selections |
| ,      | プライマリーキーだけ残す                       | keep_primary_selection |
| %      | ファイル全体を選択                             | select_all |
| Ctrl-c | 選択箇所をコメント化・コメント解除              | toggle_comments |

とりあえずはここに書いているのは覚えておいた方が良い

移動系の操作で広く選択してしまったときはとりあえず`;`を押すことでカーソル位置だけが選択された状態に戻る

`f`などを使ったときにはこれをよく使う

選択操作は非常に強力で，よくこれが矩形選択と比較に出される

矩形選択では複数個所を`I`を利用しコメントアウトしたり，`e`，`W`などで上手く移動して複数個所を編集するなどをする

もう一つ`:%s///g`で検索した箇所を置換するという操作も良くすると思う

それらをhelixではマルチカーソルと正規表現などで丸ごと処理するようにしている

え，正規表現が難しい?なら[ハンター](https://www.regex-hunting.com/)になるんだ

![select.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2630694/484cb8e7-7fb5-e051-ba82-55ee48b12595.gif)

## Conclusion

モードによる機能が豊富で面白く，使いやすい

選択が肝になる操作

移動と選択が一緒なので注意が必要

選択は他のモードと組み合わせることで更に強力