2016/05/13

Emacs で日本語を保存しようとすると "undecided-unix cannot encode" というエラーが出るようになったので修正してみた

### 日本語のメッセージ保存でエラー
私は [Git](https://git-scm.com/) のエディタとして [Emacs](https://www.gnu.org/software/emacs/) を使用しています。  
つい最近まで問題なく使用していたのですが、ここ最近、日本語(マルチバイト)のメッセージを保存しようとすると以下のようなエラーが出るようになってしまいました。  
都度、コーディングシステムを指定すれば保存は出来るのですが、不便なので原因を探ってみました。



```
These default coding systems were tried to encode text
in the buffer `COMMIT_EDITMSG':
  (undecided-unix (1 . 12486) (2 . 12473) (3 . 12488))
However, each of them encountered characters it couldn't encode:
  undecided-unix cannot encode these: テ ス ト

Click on a character (or switch to this window by `C-x o'
and select the characters by RET) to jump to the place it appears,
where `C-u C-x =' will give information about it.

Select one of the safe coding systems listed below,
or cancel the writing with C-g and edit the buffer
   to remove or modify the problematic characters,
or specify any other coding system (and risk losing
   the problematic characters).

  utf-8 euc-jp shift_jis iso-2022-jp euc-jis-2004 iso-2022-jp-2004
  big5 euc-kr euc-tw gb2312 gb18030 gbk big5-hkscs hz-gb-2312 utf-7
  utf-16 utf-16be-with-signature utf-16le-with-signature utf-16be
  utf-16le japanese-shift-jis-2004 japanese-iso-7bit-1978-irv
  iso-2022-7bit utf-8-auto utf-8-with-signature eucjp-ms korean-cp949
  japanese-cp932 utf-7-imap utf-8-emacs
```

### 設定では utf-8 が優先されるようになっている
設定を確認してみると、`~/.emacs.d/init.el` の coding system 関連は以下のようになっています。

```lisp
(set-language-environment "Japanese")
(prefer-coding-system 'utf-8-unix)
(set-default-coding-systems 'utf-8)
```

`coding-system-priority-list` を確認してみても、`utf-8` が最優先になっています。
```lisp
(coding-system-priority-list) C-j
(utf-8 japanese-iso-8bit iso-2022-jp japanese-shift-jis iso-2022-jp-2 iso-2022-7bit iso-latin-1 iso-2022-8bit-ss2 emacs-mule raw-text in-is13194-devanagari utf-8-auto ...)
```

### 読み込みの判定に問題有り
実験してみたところ、英字(アスキーコード) しかないファイルを読み込んだ際、Emacs が自動判定する coding system が `undecided` になってしまうのが原因だとわかりました。  
ちなみに、判定された coding system は `M-:` で `buffer-file-coding-system` を評価するとわかります。
 
### 解決策1 読み込みを強制的に utf-8 にする(非推奨)
読み込み時の coding system を強制的に `utf-8` にすれば問題は解決です。  
具体的には、以下を `~/.emacs.d/init.el` に追加します。

```lisp
(setq coding-system-for-read 'utf-8)
```

この方法、やってみるとちゃんと動作するのですが、読み込む全てのファイルを `utf-8` にしてしまいます。
つまり、`sjis` のファイルなんかを読み込むと文字化けしてしまいます。

さらに、以下には `coding-system-for-read` はグローバルに設定すべきでは**ない**変数だと書いてあります。
[GNU Emacs Lisp Reference Manual: Specifying Coding Systems](https://www.gnu.org/software/emacs/manual/html_node/elisp/Specifying-Coding-Systems.html)

というわけで、他の方法が必要です。

### 解決策2 coding system 判定後に入れ替える
`buffer-file-coding-system` が `undecided` だった場合のみ coding system を変更するようにしてみました。  
`coding-system-for-read` を一時的に変更してバッファを読み込み直すという方法です。  
以下を `~/.emacs.d/init.el` に追加します。  

```lisp
(add-hook 'find-file-hook '(lambda ()
                             (cond ((string-match "undecided-?.*" (format "%s" buffer-file-coding-system))
                                    (let ((coding-system-for-read 'utf-8))
                                      (revert-buffer t t))))))
```

いまのところ、この方法でうまく動いています。

0 件のコメント: