Emacs 25.3/26.1/28.1 を EMP版で快適に使う

# はじめに

この記事は，Emacs を IME（ことえりや Google IME など）と共に使う Macユーザに向けた記事です．

何度かのプレリリースを経て2016年9月に[リリースされた](https://lists.gnu.org/archive/html/emacs-devel/2016-09/msg00451.html)最新版の Emacsは，メジャーバージョンが 25になりました．早速，新しい環境へ移行した方も多いと思います．私もその一人でしたが，いざバージョンアップしてみると，なんだか日本語入力時にちらつきが，，，しかも意識し始めるとかなり気になる．少しでも快適に使える環境を探求した結果，Emacs 25.1の [EMP版ビルド](https://github.com/railwaycat/homebrew-emacsmacport/releases)にたどり着きました．その過程でわかった NextStep(NS)版と EmacsMacPort(EMP)版の操作感の違いと，手探りで施した設定群，そして関連情報を本記事にまとめます．

**NOTE1:** NS版のチラつきを解消するパッチが作成されたようです．
https://ja.osdn.net/projects/macemacsjp/lists/archive/users/2017-April/001756.html

**NOTE2:** 25.2用にインラインパッチを作り，上記のパッチを取り込みました．
https://gist.github.com/takaxp/3314a153f6d02d82ef1833638d338ecf

**NOTE3:** MozcとKarabiner-Elements で課題解決する方法が紹介されています．
https://tottoto.net/mac-emacs-karabiner-elements-japanese-input-method-config/

**NOTE4:** Emacs 28.1 用にパッチとビルドスクリプトを更新しました（2022-08-21)

# Emacs（NS版）で生じる日本語入力時のチラツキ

まず公式パッケージについて，24系から最新の25.1に移行すると，日本語入力時にカーソルが変換対象文字列前後に何度も移動して，激しいチラツキを生じます．しばらくは気にせずに使えていましたが，視覚的に疲れる状態でずっと使うのかー？と考えると，それ以降は気になって気になって．

[![Emacs（NS，25.1）](http://img.youtube.com/vi/rF5m9sFaTCE/0.jpg)](https://youtu.be/rF5m9sFaTCE)
↑クリックで再生

なんとか改善したいと，カーソルを一時的に非表示にする簡易的な[回避方法](http://qiita.com/takaxp/items/e07bb286d80fa9dd8e05)を考えましたが，やっぱり気になる．ということで，NS版ではなく，EMP版を使うことにしました．

**(2017-04-25) チラつき防止パッチを取り込んだインラインパッチを使うと，NS版でもチラつかなくなります．**  => http://qiita.com/takaxp/items/e07bb286d80fa9dd8e05

# EMP版のEmacs

EMP(Emacs Mac Port)版の入手にはいくつかの手段がありますが，プレビルドされたアプリをダウンロードするのが一番楽でしょう．railwaycat氏の Githubリポジトリに行き，emacs-25.1-mac-6.1-official-iconを選びます．

https://github.com/railwaycat/homebrew-emacsmacport/releases

EMP版は，公式の Emacsソースに[山本氏のパッチ](https://bitbucket.org/mituharu/emacs-mac/overview)を当てて作ります．railwaycat氏が頒布するバイナリは，すでに当該のパッチが当ててあるので，特に追加作業が不要でそのまま使えます．Homebrew経由で同じものが手に入りますが，アプリのアイコンが最新でなかったりします．詳細は下の方で．

さて，チラツキはどうなるでしょう．

[![Emacs（EMP，25.1）](http://img.youtube.com/vi/tzCPBqvhlxI/0.jpg)](https://youtu.be/tzCPBqvhlxI)
↑クリックで再生

全く気になりません！（↑再生しないとわかりませんが...）やったね！幸せだね！

と喜んだのはつかの間，実はNS版とEMP版で結構な点で挙動が違うのです．私のように，NS版にいわゆる [inline-patch](https://github.com/takaxp/ns-inline-patch) を当てて使っていたユーザは，正直戸惑うと思います．

以下では，それらの戸惑いを少しでも解消する解決策と設定群を示します．正直，まだ完璧とは言い難いですが，解決できたところから順次更新していきます．

# 野良ビルド不要で解決可能な項目

まずは上で紹介したプレビルドされたパッケージを使い，幾つかの設定を施すだけで解決できる項目について紹介します．

## C-M-SPC で絵文字入力が起動する

ほぼ確実に「ふぁ！」っとなります．これは MacOSのシステム環境で，顔文字のテーブルを表示するショートカットを変更することで解決します．具体的な設定方法は，[こちらの記事](http://wat-aro.hatenablog.com/entry/2015/09/20/005237)に譲ります．

## window-system の違い

`(eq window-system 'ns)` で切り分けていた部分は，`(eq window-system 'mac)` にします．うっかり忘れないように注意します．

## 日本語入力時に C-x が効かない

EMP版を何も設定せずに使うと，ウィンドウ間のカーソル移動（`C-x o`）すると，日本語入力が有効だとバッファに「お」が入力されます．NS版からするとクリティカルな違いです．ただこれにはデフォルトで解決策が提供されていて，`(mac-auto-ascii-mode 1)`と設定すると回避できます．`mac-auto-ascii-mode`は，2014年11月に導入されたマイナーモードで，`C-x`などのプレフィックスが押されたら自動的に ASCII入力へ移行して，その先のコマンド入力で不自由しない効果があります．

ところが，`C-x`を押下すると即座に日本語入力が解除されて ASCII入力に有効・固定化されます．したがって，日本語入力時にウィンドウ分割して，移動して，また入力を始める場合には，毎度日本語入力モードに手動で戻さないといけません．面倒です．この課題への対策が次の節です．

## mac-auto-ascii-mode を使うと ASCII固定になる

日本語入力時に特定の関数を呼び出したら，その実行後に ASCII入力から日本語入力に自動で戻すようにします．少々乱暴なやり方なので，環境によっては重くなるかもしれません（私の環境では目立った影響は無い）．日本語入力時に `C-x C-s` でファイルを保存してしまうのが癖の人には特にオススメです．未完全ですが，マスタカさんの記事 [OSXのEmacsにインラインパッチなんていらなかったんや...](https://masutaka.net/chalow/2015-01-04-1.html)へのアンサーソングです．

```el
(defvar mac-win-last-ime-status 'off) ;; {'off|'on}
(defun mac-win-save-last-ime-status ()
  (setq mac-win-last-ime-status
        (if (string-match "\\.\\(Roman\\|US\\)$" (mac-input-source))
            'off 'on)))

(defun mac-win-restore-ime ()
  (when (and mac-auto-ascii-mode (eq mac-win-last-ime-status 'on))
    (mac-select-input-source
     "com.google.inputmethod.Japanese.base"))) ;; Google IME 以外は要修正

(defun advice:mac-auto-ascii-setup-input-source (&optional _prompt)
  "Extension to store IME status"
  (mac-win-save-last-ime-status))
(advice-add 'mac-auto-ascii-setup-input-source :before
            #'advice:mac-auto-ascii-setup-input-source)

(defun mac-win-restore-ime-target-commands ()
  (when (and mac-auto-ascii-mode 
             (eq mac-win-last-ime-status 'on))
    (mapc (lambda (command)
            (when (string-match
                   (format "^%s" command) (format "%s" this-command))
              (mac-select-input-source
               "com.google.inputmethod.Japanese.base"))) ;; Google IME 以外は要修正
          mac-win-target-commands)))
(add-hook 'pre-command-hook 'mac-win-restore-ime-target-commands)

;; M-x でのコマンド選択でもIMEを戻せる．
;; ただし，移動先で q が効かないことがある（要改善）
(add-hook 'minibuffer-setup-hook 'mac-win-save-last-ime-status)
(add-hook 'minibuffer-exit-hook 'mac-win-restore-ime)


;; 自動で ASCII入力から日本語入力に引き戻したい関数（デフォルト設定）
(defvar mac-win-target-commands
  '(find-file save-buffer other-window delete-window split-window))


;; 自動で ASCII入力から日本語入力に引き戻したい関数（追加設定）
;; 指定の関数名でマッチさせるので要注意（ my: を追加すれば，my:a, my:b らも対象になる）

;; バッファリストを見るとき
(add-to-list 'mac-win-target-commands 'helm-buffers-list)
;; ChangeLogに行くとき
(add-to-list 'mac-win-target-commands 'add-change-log-entry-other-window)
;; 個人用の関数を使うとき
(add-to-list 'mac-win-target-commands 'my:)
;; org-mode で締め切りを設定するとき．
(add-to-list 'mac-win-target-commands 'org-deadline)
;; query-replace で変換するとき
(add-to-list 'mac-win-target-commands 'query-replace)
```

上の設定ではGoogle IMEを対象にしていますが，適宜変更することで他の IMEでも使えるはずです．上記の設定を加えてしばらく運用し，ASCII入力から日本語入力へ自動で戻したい関数が見つかったら `mac-win-target-commands` に随時追加していくのがオススメです．上の設定だけでも操作感は NS版にだいぶ近くなるはずです．

本当は `org-capture` を対象にしたいのですが，ディスパッチャ系は上のアプローチのままだと，うまくいかないようです．

## タイトルバーの表示がファイル名じゃない

EMP版ではタイトルバーにホスト名が表示されますが，NS版に合わせるならやっぱりファイル名です．

```el
(setq frame-title-format (format (if (buffer-file-name) "%%f" "%%b")))
```

## モードライン左端で入力タイプを確認できない

EMP版では提供されていない機能のようで，これは断念．代わりにカーソルの色を日本語とASCIIで分けることで代替します．慣れると特にモードラインに[あ]などと表示されてなくてもOKな気がしてきます．

以下の例は Google IMEの場合で，カーソルの形状と色を同時に制御しています．

```el

(defvar my:cursor-color-ime-on "#FF9300")
(defvar my:cursor-color-ime-off "#91C3FF") ;; #FF9300, #999999, #749CCC
(defvar my:cursor-type-ime-on '(bar . 2)) ;; box
(defvar my:cursor-type-ime-off '(bar . 2))

(when (fboundp 'mac-input-source)
    (defun my:mac-keyboard-input-source ()
      (if (string-match "\\.Roman$" (mac-input-source))
          (progn
            (setq cursor-type my:cursor-type-ime-off)
            (add-to-list 'default-frame-alist
                         `(cursor-type . ,my:cursor-type-ime-off))
            (set-cursor-color my:cursor-color-ime-off))
        (progn
          (setq cursor-type my:cursor-type-ime-on)
          (add-to-list 'default-frame-alist
                       `(cursor-type . ,my:cursor-type-ime-on))
          (set-cursor-color my:cursor-color-ime-on)))))

(when (and (fboundp 'mac-auto-ascii-mode)
           (fboundp 'mac-input-source))
      ;; IME ON/OFF でカーソルの種別や色を替える
      (add-hook 'mac-selected-keyboard-input-source-change-hook
                'my:mac-keyboard-input-source)
      (my:mac-keyboard-input-source))

;; たまにカーソルの色が残ってしてしまう．
;; IME ON で英文字打ったあととに，色が変更されないことがある．禁断の対処方法．
(when (fboundp 'mac-input-source)
  (run-with-idle-timer 3 t 'my:mac-keyboard-input-source))
```

## org-mode で Webリンクが開かなくなる

google-chromeが無いよと怒られます．`browse-url-browser-function` と `browse-url-generic-program` を設定すればOKですが，NS版と少し違う振る舞いになるので，別な解決策を模索する方がいいかも．

```el
(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome")
```

## hl-line を使っていると，日本語変換中にその領域の背景色が白のまま

例えば次のような設定で，カーソル行に背景色を設定しているケースを想定します．

```el
(global-hl-line-mode t)    
(custom-set-faces
 '(hl-line
   ((((background dark)) :background "#484c5c")
    (t (:background "#DEEDFF")))))
```

この時に，日本語変換中の単語の背景色だけ変に目立つようになるので以下の設定で回避します．ただし，ミニバッファでも同じ補正をかけるには，次節の野良ビルドが必要です．

```el
;; なおテーマを切り替えたら，face の設定をリロードしないと期待通りにならない
(custom-set-faces
 ;; 変換前入力時の文字列用 face
 `(mac-ts-converted-text
   ((((background dark)) :underline "orange" 
     :background ,(face-attribute 'hl-line :background))
    (t (:underline "orange" 
                   :background ,(face-attribute 'hl-line :background)))))
 ;; 変換対象の文字列用 face
 `(mac-ts-selected-converted-text
   ((((background dark)) :underline "orange"
     :background ,(face-attribute 'hl-line :background))
    (t (:underline "orange"
                   :background ,(face-attribute 'hl-line :background))))))
```

# 独自のパッチを当てて野良ビルドが必要な項目

さて，コレ以降はプレビルドされたバイナリではなく，個人的に作成した[EMPの拡張パッチ](https://gist.github.com/takaxp/fc5ae440b3279679dc854e5b9adbfe08)を追加で適用して[EMP版Emacsを野良ビルドする](https://gist.github.com/takaxp/53fc9e9df6017124824d11ddccc7ce89)ことで解決できる項目です．野良ビルドの詳細は後段で．

**(2022-08-21)** Emacs 28.1用に，[EMP版向け拡張パッチ](https://gist.github.com/takaxp/ed9ae4a736628156a28fddb20a2fe0d7)と，[EMP版Emacsの野良ビルドスクリプト](https://gist.github.com/takaxp/77acfca20579a899e68a4fe90d9c596f)を作りました．

## 日本語確定時にカーソルを非表示にする（カーソル表示位置の安定化）

変数 `mac-win-ime-cursor-type`を独自に追加した野良ビルドEMP版Emacsを使って，

```el
;; 変換語指定時にカーソルをオフにする．復帰後のカーソルタイプを指定すると発動．
;; (setq mac-win-ime-cursor-type 'box)
(setq mac-win-ime-cursor-type cursor-type)
```

すると，日本語入力の変換候補決定時にカーソルが文字列先頭へ飛ばなくなるので，さらに目に優しくなります．この点においては Atomと同じような振る舞いになります．

動画でみるとこんな感じです．

[![Emacs（EMP，25.1, Custom）](http://img.youtube.com/vi/j5mC9WMOhOY/0.jpg)](https://youtu.be/j5mC9WMOhOY)
↑クリックで再生

## 日本語変換中にその領域の背景色を無効にする

上の方の設定で hl-line の背景色を有効にしましたが，NS版に合わせるために，ミニバッファとエコーエリアでは背景色を無効にします．

```el
;; minibuffer では hl-line の背景色を無効にする
(when (fboundp 'mac-min--minibuffer-setup) ;; 野良ビルド用パッチの独自関数です．
  (add-hook 'minibuffer-setup-hook 'mac-min--minibuffer-setup))

;; echo-area でも背景色を無効にする．野良ビルド用パッチの独自変数です．
(setq mac-win-default-background-echo-area t) ;; *-text の background を無視
```

# その他

未解決で気になるけど，実用上の問題はないと思われる項目をまとめます．

## display-startup-echo-area-message が重複呼び出しされる

EMP版特有の現象です．起動スピードに影響を与えるような処理が重複しているわけではないので，スルーしてOKです．

## 起動時間が遅い

残念ながら100[ms]オーダーで遅くなります．我慢．

## 日本語入力中の「q」が通らない

`q`にウィンドウを閉じるなどが設定されていて，日本語入力が有効だとうまく機能しない．これはなんとかしたい．

## Query-replace に日本語入力モードで入ると，連続する変換処理(y)が入らない．

これも本当は直したい．


# EMP版と NS版の野良ビルド情報

EMP版ビルドとNS版ビルドについて簡単にまとめます．

1. NS版：公式Emacsを `--with-ns` でビルドしたバイナリ．
2. NS版(inline-patch)：公式Emacsに[inline-patch](https://github.com/takaxp/ns-inline-patch)をあてて，`--with-ns`でビルドしたバイナリ
3. EMP版：公式Emacsに `Emacs Mac Port` パッチをあてて，`--with-mac`でビルドしたバイナリ
4. EMP版(拡張パッチ)：公式Emacsに `Emacs Mac Port` パッチと本記事で紹介した [拡張パッチ](https://gist.github.com/takaxp/fc5ae440b3279679dc854e5b9adbfe08)または[拡張パッチ(28.1)](https://gist.github.com/takaxp/ed9ae4a736628156a28fddb20a2fe0d7)をあてて，`--with-mac`でビルドしたバイナリ

## 各パッケージの入手先

### NS版

ビルド済みのバイナリは，[https://emacsformacosx.com/](https://emacsformacosx.com/)からダウンロードできます．日本語パッチは[こちら](https://github.com/takaxp/ns-inline-patch)をどうぞ．

### EMP版

通常のEMP版は，山本氏が管理する千葉大のサーバからパッチを入手して作ります．入手元には[Gitサーバ](http://www.math.s.chiba-u.ac.jp/~mituharu/emacs-mac.git)と[FTPサーバ](ftp://ftp.math.s.chiba-u.ac.jp/emacs/)があります．普通にビルドすると **古いアイコン** かつ **`self-contained`なパッケージではない** ことに留意してください．

**(2022-08-21確認)** configure で `--enable-mac-self-contained` を指定すれば，self-contained なパッケージになります．

山本氏のパッチをベースとしたHomebrewから取れるパッケージは， [Github](https://github.com/railwaycat/homebrew-emacsmacport) にあります．

本記事で紹介したEMP版に拡張パッチを適用して作る野良ビルドは，基本的にEMP版と同じで，幾つかの変数を埋め込んでいるだけです．変数に値を渡さなければ，オリジナルのEMP版と同じふるまいになります．

https://gist.github.com/takaxp/53fc9e9df6017124824d11ddccc7ce89 (25.1 / 25.2)

https://gist.github.com/takaxp/88b9e7f7e73e386173a0337fb87e51e0 (25.3)

https://gist.github.com/takaxp/ed9ae4a736628156a28fddb20a2fe0d7 (28.1)

に置いたスクリプトを実行すると，

1. 公式のEmacsソースの入手と展開
2. 山本氏のEMP版パッチの入手と適用
3. 本記事で言及したEMP版の拡張パッチの入手と適用

を自動で実施し，最終的に Emacs 25の新しいアイコンで self-contained なバイナリを作ってくれます．興味のある方は是非どうぞ（事前に`xcode-select --install`の実行が必要なので要注意）．

[Updated: 2017-02-08]
上記スクリプトを Emacs 25.2のプレテストでも使えるように手を加えました．スクリプト中の `source_url`, `version`, `patch_version` をそれぞれ書き換えるとうまくいきます．

（25.1の場合）
source_url=http://ftpmirror.gnu.org/emacs
version=25.1
patch_version=25.1-mac-6.1

（25.2 の場合）
source_url=http://ftpmirror.gnu.org/emacs/
version=25.2
version_postfix=""
patch_version=25.2-mac-6.3

(26.1 の場合）
source_url=http://ftpmirror.gnu.org/emacs/
version=26.1
version_postfix=""
patch_version=26.1-mac-7.0

(28.1 の場合)
source_url=http://ftpmirror.gnu.org/emacs
version=28.1
version_postfix=""
patch_version=28.1-mac-9.0

28.1の場合は，以下のようにすれば `Emacs.app` の生成まで実行してくれます．

```sh
cd ~/Desktop
curl -LO https://gist.githubusercontent.com/takaxp/77acfca20579a899e68a4fe90d9c596f/raw/2d842e471e4c675bca496bda34202d9ef844752b/emacs-mac-port-build.sh
sh ./emacs-mac-port-build.sh
```

# まとめ
本記事では，Macで Emacs25.1を快適に使うには EMP版がオススメですよ〜との趣旨で，加えておけばより快適に使えるようになる設定をいくつか紹介しました．また，結局はEMP版も野良ビルドすると痒いところに手が届くことも紹介しました．

皆様の快適なEmacsライフに貢献できれば幸いです．設定等でうまくいかないところが見つけましたら気軽にコメントを残してください．非常に助かります！


# おまけ
## lem

日本語入力を試してみましたが，やっぱりチラつきますね．残念．それからデフォルトインスールかつコンソールにも関わらず起動が異常に遅いのは，なんか私のインストール手順に誤りがあったかな...

（参考: [Common Lisp 製 Emacs 風エディタ lem のインストールと起動方法](https://darui.io/posts/try-lem-commonlisp-editor)）

[![Emacs（Lem, JP input）](http://img.youtube.com/vi/a9vQnapUkT4/1.jpg)](https://youtu.be/a9vQnapUkT4)
↑クリックで再生