Emacs に vterm を入れる

# はじめに

Emacs には標準でもいろんなシェルがありますが、例えば Docker コンテナの psql コマンドを使いたいみたいな時は、Readline も使えて、less なども使える term または ansi-term を使うことがありました。

ただ、実際のところ、ansi-term だとカーソル位置の表示が乱れて、何を入力したか確認できなくなったり、そのせいで誤った値を入力してしまったり、char モードのつもりでコマンドを入力したら、line モードに切り替えていたことを忘れていて、編集中の余計な行まで実行されてしまったりと、誤爆しがちで ansi-term でデリケートな作業は避けた方が良いなという印象がありました。
他にも、凝ったシャレオツなインジンジケータがうまく表示できなかったり、対話形式で複雑めなインタラクションが可能な今風なコマンドラインツールがまともに使えなかったりしていました。

一方、VS Code の統合ターミナルはとてもよくできていて、スタンドアロンな端末アプリケーションとほぼ変わらない使用感で、デリケートな作業をすることも怖くないという感じでした。

Emacs でももっとちゃんとしたシェルを使えたらなぁ [^1] と普段から切実に思っていて、Emacs User Survey でも強化してほしいポイントとして挙げたりしていたのですが、ちょくちょく [vterm](https://github.com/akermu/emacs-libvterm) という単語が目に入ることがあって、時間があったら試そうと思っていたところでした。

ちょうど最近、Amplify CLI を使った時に、ansi-term ではやっぱり辛い...と思ったところだったので、vterm を実際に入れて試してみたところ、Emacs のターミナルに関するストレスがほぼなくなったので、同じようにストレスを感じている方にオススメしたい。って記事です。（前置きが長い）

ちなみに vterm は Neovim などのターミナルに使われている libvterm というライブラリを使って作られているそうです。宗教戦争している場合ではないですね。ありがたく使わせていただきます :pray:

[^1]: EXWM を使ったりすれば当然解決できたりはしますが、そこまで大げさな方法でない方が良い。

# インストールする

vterm は Emacs 25.1 で導入された[ダイナミックモジュール](https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Modules.html)を使った実装になっているため、ダイナミックモジュールが有効になっている Emacs でしか動作しません。

自分は今のところダイナミックモジュールを使用するパッケージを他に使っていなかったようで、vterm をインストールするために Emacs を再インストールしました。

ダイナミックモジュールを使用できるようにするには、configure オプションの `--with-modules` を指定して Emacs をコンパイルする必要があります。

# vterm をインストールする

vtrem は MELPA からダウンロードできるようになっているので、 <kbd>M-x package-install RET vterm</kbd> でインストールできます。

# シェルの設定をする

README にシェルの設定がいくつか載っているのですが、vterm のインストールディレクトリ以下の `etc` ディレクトリ以下に各シェル向けの設定ファイルが含まれています。

自分は bash を使っているので、雑に `.bashrc` に下記の記述を追加しました。

```sh
if [[ "$INSIDE_EMACS" = 'vterm' ]]; then
    . "$(find ~/.emacs.d/elpa -maxdepth 1 -name 'vterm-*')/etc/emacs-vterm-bash.sh"
fi
```

# vterm モジュールをビルドする

vterm は vterm コマンドを実行したタイミングで、vterm モジュールをビルドするようになっていました。

ちなみに、自分はここでエラーになってビルドに失敗したので、後学のために対応した内容を残しておきます。

## 必要なライブラリやツールをインストールする

ドキュメントに記載されているとおり、下記を事前にインストールする必要があります。

1. ダイナミックモジュールが使える Emacs (>= 25.1) 
2. cmake (>= 31)
3. libtool-bin
4. オプション: libvterm (>= 0.1)

自分は最後の libvterm をインストールしたことが原因で vterm モジュールのビルドに失敗していました。

具体的には WSL2 上の Debian (buster) で、apt コマンドを使って libvterm-dev をインストールしたのですが、これが古すぎることが原因だったようです。`0~bzr718-1` というバージョンでした。きっと これは `0.1` より古いんでしょう。

ちょっと古めのバージョンの OS を使っていたり、パッケージ管理システムで管理されたソフトウェアのバージョンが比較的古めの環境の場合は、`4.` の手順は実施しない方が良いかもしれません。

## エラーの対処

`error: ‘VTermColor {aka struct <anonymous>}’ has no member named ‘indexed’` といったエラーが出てビルドに失敗してしまったのですが、同じエラーメッセージを報告している [issue](https://github.com/akermu/emacs-libvterm/issues/323
) があり、そこで回答されていた対処で自分も対処できました。よくよく読んだら README にも書いてありました :see_no_evil: 

具体的には `vterm-module-cmake-args` というカスタム変数に `-DUSE_SYSTEM_LIBVTERM=no` という形で CMake に引数を渡すようにすると、ローカルのライブラリの vterm.h ではなく、コマンド実行時にダウンロードした vterm.h を使うようになるみたいです。

```emacs-lisp
(setq vterm-module-cmake-args "-DUSE_SYSTEM_LIBVTERM=no")
```

ちなみに、エラー発生後に上記の変数に値をセットしても、CMakeCache.txt に以前の実行時のオプションが記述されてしまっていて、時すでに遅しでした。

自分は <kbd>M-x pacakge-delete RET vterm</kbd> してパッケージを削除してから、再インストールしました。

# まとめ

vterm を入れたことで、Emacs でも本物のターミナルの使用感にほぼ近い使用感を手に入れました。そうなると、`term` モードや `ansi-term` モードは中途半端な存在になってしまうので、今後使うことはなくなりそうです。

ただ、まだアルファ版らしいので、その点はご留意ください。

以上。