Vimmer が Spacemacs に完全に乗り換えるまで (Vimmer 向け設定)

# こんな方へ

* Vim ではなく、Vim のキーバインドが好き。
* 設定ファイルをすべて自分でメンテナンスするのが面倒。勝手にアップグレードされて欲しい。しかし自分でカスタマイズする余地も欲しい。

この記事はあくまで Vimmer 向けの設定がメインです。

# Spacemacs とは

[Spacemacs](http://spacemacs.org/)
![screenshot](https://qiita-image-store.s3.amazonaws.com/0/102243/2fc8fb3b-7c16-521e-97f4-794eb0b0e491.png)

Vim の長所と Emacs の長所を融合させることを目的とした、コミュニティドリブンな Emacs の膨大な設定ファイル群です。

> 最強のエディタは Vim でも Emacs でもない。Emacs **と** Vim だ! ― @syl20bnr

Spacemacs は次のようなコンセプトをもっています。

* **人間工学的なキーバインド** - キーの入力回数を最小化するのではなく、覚えやすさを優先する。
* **発見可能であること** - エディタのキーバインド/レイヤー&パッケージ/設定方法をエディタの中から参照できる。
* **一貫していること** - 異なる言語モードでもほとんど同じキーバインドで言語特有の操作 (リファクタなど) を扱える。
* **コミュニティドリブン**

# Emacs のインストール

当然ですが、 最新版の Emacs をインストールしておきます。

```sh
sudo pacman -S emacs   # Arch Linux
# macOS
brew tap d12frosted/emacs-plus
brew info emacs-plus   # see install options
brew install emacs-plus
```

# Spacemacs のインストール

`master` ブランチよりも `develop` ブランチが遥かに進んでいます。人柱覚悟で新しい機能を試したい方は `develop` ブランチにしましょう。

```sh
git -C ~/.emacs.d checkout develop
```

このあと Emacs を一旦起動して終了すると `~/.spacemacs` が作成されます。これを `~/.spacemacs.d/init.el` に移動しておきます。

```sh
mkdir -p ~/.spacemacs.d
mv ~/.spacemacs ~/.spacemacs.d/init.el
```

# Vimmer 用に設定

## dotspacemacs/init

以下のように設定する。

| VAR                           | VALUE       |
|-------------------------------|-------------|
| `dotspacemacs-editing-style`  | `'vim`      |
| `dotspacemacs-remap-Y-to-y$`  | `t`         |
| `dotspacemacs-line-numbers`   | `'relative` |
| `dotspacemacs-folding-method` | `'evil`     |

## dotspacemacs/user-init

以下を追記する。

```emacs-lisp
(setq
 evil-want-C-i-jump t
 evil-want-C-u-scroll t)
```

## `C-h`, `C-w` の有効化

Emacs で `C-h` は Backspace ではなく `help` になっているので、Vim に合わせます。ついでに `C-w` も。
以下を `dotspacemacs/user-config` に追記します。

```emacs-lisp:dotspacemacs/user-config
(bind-key* "C-h" #'delete-backward-char)
(bind-key* "C-w" #'backward-kill-word)
(with-eval-after-load 'company
  (bind-key "C-h" nil company-active-map)
  (bind-key "C-w" nil company-active-map))
```

## jj で挿入モードを抜ける

私は jk が好きです。`dotspacemacs/user-init` に以下を追記する。

```emacs-lisp:dotspacemacs/user-init
(setq evil-escape-key-sequence "jk")
```

## evil-surround を vim-surround 風に

これは evil-surround の方が楽なので、慣れてしまってもいいかもしれません。

```emacs-lisp:dotspacemacs/user-config
(evil-define-key 'visual evil-surround-mode-map "s" #'evil-substitute)
(evil-define-key 'visual evil-surround-mode-map "S" #'evil-surround-region)
```

## evil-mc を vim-multiple-cursors 風に

Vim のノーマルモードとマルチカーソルは最強の組み合わせです。
縦にカーソルを作る機能は非常に多用するので実装しました。

```emacs-lisp:dotspacemacs/user-config
(defun user-custom/evil-mc-make-and-goto-next-match ()
  (interactive)
  (turn-on-evil-mc-mode)
  (evil-mc-make-and-goto-next-match))
(defun user-custom//evil-mc-make-vertical-cursors (beginning end)
  (turn-on-evil-mc-mode)
  (evil-mc-pause-cursors)
  (evil-apply-on-rectangle
    #'(lambda (startcol endcol real-line-number)
        (move-to-column startcol)
        (unless (= (line-number-at-pos) real-line-number)
          (evil-mc-make-cursor-here)))
    beginning
    end
    (line-number-at-pos))
  (evil-mc-resume-cursors)
  (evil-normal-state)
  (move-to-column (min (evil-mc-column-number beginning)
                        (evil-mc-column-number end))))
(require 'evil-core)
(evil-global-set-key 'normal
                      (kbd "C-n")
                      #'user-custom/evil-mc-make-and-goto-next-match)
(evil-global-set-key 'visual
                      (kbd "C-n")
                      #'(lambda (beginning end)
                          (interactive (list (region-beginning) (region-end)))
                          (if (eq (evil-visual-type) 'inclusive)
                              (user-custom/evil-mc-make-and-goto-next-match)
                            (user-custom//evil-mc-make-vertical-cursors beginning end))))
(with-eval-after-load 'evil-mc
  (evil-define-key 'normal evil-mc-key-map
    (kbd "C-n") #'evil-mc-make-and-goto-next-match
    (kbd "C-m") #'evil-mc-make-and-goto-prev-match
    (kbd "C-x") #'evil-mc-skip-and-goto-next-match
    (kbd "C-p") nil
    (kbd "C-t") nil
    (kbd "<escape>") #'(lambda ()
                          (interactive)
                          (evil-mc-undo-all-cursors)
                          (turn-off-evil-mc-mode)))
  (evil-define-key 'visual evil-mc-key-map
    (kbd "C-n") nil
    (kbd "C-p") nil
    (kbd "C-t") nil)
  ;; evil-escape don't work in evil-mc-mode
  (add-hook 'evil-mc-mode-hook
            #'(lambda ()
                (add-to-list 'evil-mc-incompatible-minor-modes
                              'evil-escape-mode))))
```

## avy の高速化

easymotion の代替 avy は、デフォルトで一定時間 2 ストローク目を待つので遅いです。

```emacs-lisp:dotspacemacs/user-init
(setq avy-timeout-seconds 0.0)
```

## デーモンモードで爆速起動

まず、デーモンの設定を有効にしておきます。

```emacs-lisp:dotspacemacs/init
   ;; If non-nil, start an Emacs server if one is not already running.
   ;; (default nil)
   dotspacemacs-enable-server t
  ...
   ;; If non-nil, advise quit functions to keep server open when quitting.
   ;; (default nil)
   dotspacemacs-persistent-server t
```

これで Emacs を `SPC q q` で終了しても Emacs はバックグラウンドで動作し続けます。(デーモンごと終了するには `SPC q Q`)
これに加えて「Emacs 起動時に、バックグラウンドで起動している Emacs デーモンが利用可能であれば利用する」という設定を加える必要があります。

* [oh-my-zsh/emacs](https://github.com/robbyrussell/oh-my-zsh/tree/master/plugins/emacs)
* [oh-my-fish/plugin-emacs](https://github.com/oh-my-fish/plugin-emacs)

上記のシェルプラグインは、Emacs を起動するときに極力デーモンを利用するようにするためのプラグインです。
実装量はそれほど多くないので、その他のシェルでもプラグインの実装を読めば自力で実装できます。(あと `emacsclient --help`)

更に、デーモンモードで起動するとウィンドウの背景が透明にならない不具合(?)があります。私はこのように回避しています。

```emacs-lisp:dotspacemacs/user-config
(defun user-custom//enable-frame-transparency (frame)
    (spacemacs/enable-transparency frame
                                  (cons dotspacemacs-active-transparency
                                        dotspacemacs-inactive-transparency)))
(user-custom//enable-frame-transparency nil)
(add-hook 'after-make-frame-functions
          #'user-custom//enable-frame-transparency))
```

# 使っていて困ったら

* `SPC SPC` でコマンド/キーバインドを調べることができます。
* `SPC h d` で、現在読み込まれている関数や変数のヘルプや初期値/現在の値を参照できます。
* `emacs --debug-init` で詳細なデバッグ情報を表示できます。
* evil-mode のロード前にエラーが起きてしまった場合は `C-x C-c` で Emacs を終了できます。
* S 式を直接入力して実行したい場合は `M-:`. Lisp をその場で実行したい場合は選択モードで `, e r`.