IdeaVIMのキーバインドを考える

IDEA系エディタでVimのキーバインドを使うために、 [IdeaVIM](https://plugins.jetbrains.com/plugin/164-ideavim) というプラグインがある。
流石にVim純正プラグインがそのまま動くわけではないので、足りない機能はIDEA純正の機能にVimプラグイン風のキーを割り当てて補うことを考える。

以下はGitHubから他人の `.ideavimrc` を見漁って自分なりにまとめた `.ideavimrc` の設定である。

# コード折り畳みを無効化

自分にとってIDEのコード折り畳み機能は不要な機能であるが、IDEの設定から無効化するだけでは不完全であった。

```vim:.ideavimrc
nnoremap zM <Nop>
nnoremap zc <Nop>
nnoremap zC <Nop>
nnoremap zR <Nop>
nnoremap zo <Nop>
nnoremap zO <Nop>
```

# surround を有効化

[tpope/vim-surround](https://github.com/tpope/vim-surround) と同じ機能とキーバインドを実現。

```vim:.ideavimrc
set surround
```

# AceJump にキーバインドを割り当てる

[AceJump](https://plugins.jetbrains.com/plugin/7086-acejump) は [vim-easymotion](https://github.com/easymotion/vim-easymotion) と似た挙動をするIDEA用のプラグイン。
私の場合は Space 2回押下で呼び出すように設定する。

```vim:.ideavimrc
nnoremap <Space><Space> :<C-u>action AceAction<CR>
```

Vimモードでは少し挙動がおかしいのであまり使っていない。

# 検索機能をIDEA純正に

テキストハイライトがついて見やすく、凝った検索をしなければVim純正と似たような操作性で検索ができる。

```vim:.ideavimrc
nnoremap / :<C-u>action Find<CR>
```

# ジャンプ機能をIDEA純正に

コードジャンプ機能はIDEAの方が完成度が高いので、こちらを標準で使います。

```vim:.ideavimrc
nnoremap <C-o> :<C-u>action Back<CR>
nnoremap <C-i> :<C-u>action Forward<CR>
nnoremap <C-S-o> <C-o>
nnoremap <C-S-i> <C-i>
```

# コードジャンプ

## 前/次のメソッド定義へジャンプ

```vim:.ideavimrc
nnoremap [m :<C-u>action MethodUp<CR>
nnoremap ]m :<C-u>action MethodDown<CR>
```

## 前/次の変更箇所へジャンプ

```vim:.ideavimrc
nnoremap [c :<C-u>action VcsShowPrevChangeMarker<CR>
nnoremap ]c :<C-u>action VcsShowNextChangeMarker<CR>
```

## 前/次のエラー箇所へジャンプ

```vim:.ideavimrc
nnoremap [e :<C-u>action GotoPreviousError<CR>
nnoremap ]e :<C-u>action GotoNextError<CR>
```

[ + アルファベットで前方検索、] + アルファベットで後方検索。ついでに現在の行の前/後に空行を挿入するキーバインドも紹介する。

```vim:.ideavimrc
nnoremap [<Space> O<Esc>j
nnoremap ]<Space> o<Esc>k
```

## タグジャンプ

|キーセット|動作|
|:---|:---|
|K|JavaDocを表示|
|gjK|インターフェイスへジャンプ|
|gjk|宣言へジャンプ|
|gji|実装クラスへジャンプ|
|gjs|スーパークラスへジャンプ|
|gjt|テストクラスへジャンプ|
|Ctrl + k|出現箇所の検索|

基本的に **gj + アルファベット** をタグジャンプに割り当てている。

```vim:.ideavimrc
nnoremap K :<C-u>action QuickJavaDoc<CR>
nnoremap gjK :<C-u>action GotoDeclaration<CR>
nnoremap gjk :<C-u>action GotoTypeDeclaration<CR>
nnoremap gji :<C-u>action GotoImplementation<CR>
nnoremap gjs :<C-u>action GotoSuperMethod<CR>
nnoremap gjt :<C-u>action GotoTest<CR>
nnoremap <C-k> :<C-u>action ShowUsages<CR>
```

# コードリファクタリング機能

あまりしっくりくるキーバインドが浮かばなかったのでパクったものをそのまま使ってる。

```vim:.ideavimrc
nnoremap cre :<C-u>action RenameElement<CR>
nnoremap cS :<C-u>action ChangeSignature<CR>
nnoremap cts :<C-u>action ChangeTypeSignature<CR>
```

# IDEのリッチな機能にキーバインドを割り当てる

キーバインドを覚えるコストを少しでも削減するために、以下のルールを設けてみた。

* **スペースキー + 小文字アルファベット** でIDEの機能で何かする。
* **スペースキー + 大文字アルファベット** でIDEの機能で何か大げさなことをする。

ものすごく漠然としているが、例を見て頂ければ理解できると思う。

|キーセット|動作|
|:---|:---|
|Space + a|IDEアクションを検索|
|Space + G|コード生成メニューを表示|
|Space + gn|新規クラスを生成|
|Space + go|メソッドをオーバーライド|
|Space + gc|コンストラクタを生成|
|Space + gg|Getter を生成|
|Space + gs|Setter を生成|
|Space + ga|Getter/Setter を生成|
|Space + ge|equals を生成|
|Space + gt|テストメソッドを生成|
|Space + =|現在のバッファをフォーマット|
|Space + o|アウトラインを表示|
|Space + q|現在のバッファを閉じる|
|Space + Q|最後の閉じたバッファを開く|
|Space + f|ファイルを検索|
|Space + F|ファイルを全文検索|
|Space + s|クラスを検索|
|Space + S|シンボルを検索|
|Space + t|端末を表示|
|Space + r|実行|
|Space + R|現在のクラスを実行|
|Space + d|デバッグ|
|Space + D|現在のクラスをデバッグ|
|Space + b|現在の行をブレークポイントに指定/指定解除|

以上を反映したものがこちらである。

```vim:.ideavimrc
nnoremap <Space>a :<C-u>action GotoAction<CR>
nnoremap <Space>G :<C-u>action Generate<CR>
nnoremap <Space>gn :<C-u>action NewClass<CR>
nnoremap <Space>go :<C-u>action OverrideMethods<CR>
nnoremap <Space>gc :<C-u>action GenerateConstructor<CR>
nnoremap <Space>gg :<C-u>action GenerateGetter<CR>
nnoremap <Space>gs :<C-u>action GenerateSetter<CR>
nnoremap <Space>ga :<C-u>action GenerateGetterAndSetter<CR>
nnoremap <Space>ge :<C-u>action GenerateEquals<CR>
nnoremap <Space>gt :<C-u>action GenerateTestMethod<CR>
nnoremap <Space>= :<C-u>action ReformatCode<CR>
nnoremap <Space>o :<C-u>action FileStructurePopup<CR>
nnoremap <Space>q :<C-u>action CloseContent<CR>
nnoremap <Space>Q :<C-u>action ReopenClosedTab<CR>
nnoremap <Space>e :<C-u>action SearchEverywhere<CR>
nnoremap <Space>f :<C-u>action GotoFile<CR>
nnoremap <Space>F :<C-u>action FindInPath<CR>
nnoremap <Space>s :<C-u>action GotoClass<CR>
nnoremap <Space>S :<C-u>action GotoSymbol<CR>
nnoremap <Space>t :<C-u>action ActivateTerminalToolWindow<CR>
nnoremap <Space>P :<C-u>action ManageRecentProjects<CR>
nnoremap <Space>b :<C-u>action ToggleLineBreakpoint<CR>
```

バッファがない状態、あるいはコードエリアからフォーカスが外れてしまうとキーバインドが使えなくなるのが残念。

# (追記) 前回の変更箇所へジャンプ

**追記**: またいい感じのアクションを見つけてしまった。

```vim:.ideavimrc
nnoremap g; :<C-u>action JumpToLastChange<CR>
nnoremap g, :<C-u>action JumpToNextChange<CR>
```

Vimと同じように `g;` で前回の変更箇所へジャンプし、 `g,` で戻ります。

# (追記) 現在のタブ以外を閉じる

```vim:.ideavimrc
nnoremap <C-w>o :<C-u>action CloseAllEditorsButActive<CR>
```

**Ctrl-W + o** で現在開いているタブ以外を閉じる。

# IDEのアクションを呼び出す

```
:actionlist [フィルタ]
```

でIdeaVIMから呼び出せる機能を参照できる。

```
:action [アクション名]
```

でアクションの呼び出しが行えるので、どのような挙動をするのかを試すことが出来る。

# これからやる

* 何も含んでいない最終行にキャレットが移動しないバグがあるので、修正したものを近々PRを送る。
* `SelectWord` , `UnSelectWord` は actionlist に含まれていたが、Vimの範囲選択とは連携できないので修正する。
* `RenameElement` が不自然なので、Vimのモード、範囲選択と自然に連携するように修正する