[VimとEmacsの共存] VimでEmacsキーバインドを使えるようにしてみた

# なぜEmacsキーバインドが良いのか？
どのキーボードもだいたい`方向キー`や`Delキー`はホームポジションを崩さないと押せない位置にあります
これは少しの差ではありますが塵も積もれば多大なロス
いち早く改善すべき習慣であると思ってます

:::note
その点、Emacsのキーバインドは`Ctrl`キーとの組み合わせで操作するので
**ホームポジションを崩さずに**カーソルの移動や削除が出来ます
:::

マスターするととっても楽ちん
手の動きも少なくなり疲労軽減、作業効率増大、これなしではテキスト入力出来なくなるレベルです
（前の職場のWindowsPCでもキーマッピング登録して使ってたほど中毒性があります）

しかも幸いなことに**Macのほとんどのアプリケーションではデフォルトでこのキーバインドが使えます**
なのでSlackの返信やGoogleでの検索、報告書の作成など、Emacsキーバインドをめちゃくちゃ多用してます

使わない手はないのです！！

# Vimとの共存
話は変わりまして、よく宗教論争として争っているVimももちろんホームポジションを崩さず様々な操作が出来ます
私自身も今ではすっかりVimメインの生活になりVim無しでは生きていけなくなりつつあります
しかし唯一不満なのがInsertモードでの操作
今のVimは方向キーでの操作も出来るのですが方向キーまで手を伸ばす気にはなれません
独自のキーマッピングを定義するのも考えましたが普段使ってるEmacsキーバインドとの脳の切り替えコストがしんどい

そこでVim + Emacsを実現出来ないかと考えました

Emacsキーバインドは`Ctrlキー`を組み合わせるのでVimのInsertモードとの相性も良さそう

さっそく取り掛かろう！と考えたものの
検索ワードが抽象的過ぎて同じような事をしようとしてる人をググっても見つけられず、、、

結局自力で考えて導入しました
なんとか問題なく動くようになったと思います

# 今回移植するEmacsキーバインド
```bash
Ctrl + p   # カーソルを上へ（↑矢印）
Ctrl + n   # カーソルを下へ（↓矢印）
Ctrl + f   # カーソルを右へ（→矢印）
Ctrl + b   # カーソルを左へ（←矢印）
Ctrl + a   # カーソル行の行頭へ移動
Ctrl + e   # カーソル行の行末へ移動
Ctrl + h   # 左の文字を削除（BackSpece)
Ctrl + d   # 右の文字を削除（Del）
Ctrl + k   # カーソルから右を全て削除
```
なるべくVimの機能で完結させたいのでよく使うキーバインドだけに絞りました

:::note warn
当然**もともとあるキーマッピングを上書き**してます
コピーする際は再マッピングする等しっかり検討してください
私の場合は衝突する既存のVimキーマッピングは使わないものなのでOKです
:::


# 導入
実際にVimの設定ファイル（vimrcかinit.vim）に書き込んでいきます
下記をコピペでOKです

```vim:vimrc
" Emacsキーバインド
inoremap <silent> <C-p> <Up>
inoremap <silent> <C-n> <Down>
inoremap <silent> <C-f> <Right>
inoremap <silent> <C-b> <Left>
inoremap <silent> <C-a> <Home>
inoremap <silent> <C-e> <End>
inoremap <silent> <C-h> <BS>
inoremap <silent> <C-d> <Del>
inoremap <silent> <C-k> <ESC>:EmacsKillCommand<CR>a

" <C-k>自作コマンド
command! -nargs=0 EmacsKillCommand call EmacsKillCommand()
function! EmacsKillCommand()
  let s:currentLine = getline('.')
  let s:nextLine = getline(line('.')+1)
  let s:currentCol = col('.')
  let s:endCol = col('$')-1

  if s:currentLine == ""        " 現在の行が空白か判定
    :normal dd
  else
    if s:currentCol == s:endCol " カーソルが最終位置かどうか判定
      if s:nextLine == ""       " 次の行が空行か判定
        :normal J
      else
        :normal Jh
      endif
    elseif s:currentCol == 1    " 行の頭か判定
      normal D
    else
      :normal lD
    endif
  endif
endfunction
```

これでInseertモードの際にEmacsキーバインドを駆使して操作出来るようになります
ちなみに`<C-k>`だけ本来の動作にするにはちょっと複雑だったのでスクリプト書きました（初Vimスクリプト）
力不足で完全なる`<C-k>`の動きにはなってませんがほぼほぼコピー出来ているので実用上はとりあえずいいことにしてます^^;

とりあえず快適〜！

### 改善の余地がある部分
- 2文字目で`<C-k>`を実行すると1文字目判定されてしまう
```bash:example
t|est　 # tとeの間（2文字目）で実行

期待してる動作： t   #　estが削除される
実際の動作：　　     # すべて削除されてしまう

原因：　InsertからESCでNormalモードに戻った際に1文字目と同じ位置になるため
```

- 現在行が空白且つ次行が1文字目から存在する場合、`<C-k>`を実行するとカーソル位置が2文字目になってしまう
```bash:example
|    # 空き行
test

期待してる動作：
|test 　# testの前にカーソル
実際の動作：
t|est # tとeの間にカーソル
原因：　最後にaでInsertモードに戻っているため
（これをやらないと他の箇所で実行の際に1文字前にカーソルが行ってしまうためしかたなく…）
```
良い改善案ある方、助言頂けると嬉しいです🙇‍♂️



# 番外編1　CommandモードでもEmacsキーバインドを使う
Commandモード（EXモード、コマンドラインモード）でも使いたいと思って作成しました

下記をコピペでOKです

```vim
cnoremap <C-p> <Up>
cnoremap <C-n> <Down>
cnoremap <C-f> <Right>
cnoremap <C-b> <Left>
cnoremap <C-a> <Home>
cnoremap <C-e> <End>
cnoremap <C-h> <BS>
cnoremap <C-d> <Del>
cnoremap <C-k> <Right><C-\>egetcmdline()[:getcmdpos()-2]<CR><BS>
```

個人的には革命レベルで使いやすくなりました
特に`<C-a>からの<C-k>での全削除`と`<C-p><C-n>での履歴遡れる`が最高！

InsertモードではVim本来のNormalモードで移動で問題ないよ！っていう生粋のVimmerの方でも
これはあった方が便利なんじゃないかな、と思います😄

そしてまたしても`<C-k>`の記述が難関
[コチラのStackOverFlow](https://stackoverflow.com/questions/62521307/delete-from-cursor-to-end-of-line-in-vim-command-mode)を参考に改良してみました
（そのままでは行頭では期待動作にならなかったので右移動→`<C-k>`→BackSpeceさせてます。力技ｗ）


# 番外編2 さらにEmacs化！？
ここからは更に意見が分かれると思いますが
VisualモードとNormalモードでもEmacsキーバインド使えるようにした設定も置いておきます

```vim
" VisualモードとNormalモードはお好みで
vnoremap <silent> <C-a> <Home>
vnoremap <silent> <C-e> <End>
nnoremap <silent> <C-f> <Right>
nnoremap <silent> <C-b> <Left>
nnoremap <silent> <C-a> <Home>
nnoremap <silent> <C-e> <End>
nnoremap <silent> <C-k> :EmacsKillCommand<CR>
nnoremap <silent> <C-y> p
```

個人的にはNormalモードやVisualモードでは
Vim本来のキーバインドやモーションが使いやすいのでそれを使うようにしています
利用頻度が高いとか好みに合わせてどうぞ！



# 参考URL
https://knowledge.sakura.ad.jp/23436/

https://tomoprog.hatenablog.com/entry/2016/03/12/153229

https://sy-base.com/myrobotics/vim/vim-cursor-position/

https://eagletmt.hatenadiary.org/entry/20100623/1277289728

https://stackoverflow.com/questions/62521307/delete-from-cursor-to-end-of-line-in-vim-command-mode