macOS上のEmacs 27.x/28.x/29.xの日本語入力設定 (inline-patch, Ctrl-\,ことえり)

# macOS上のEmacsの日本語入力設定

**(2024/8/1) シェルスクリプト化して、最初にまとめをつけました。**

**(2021/8/9) BigSurでも使えるように対応しました。**

**(2022/4/22) Emacs-28.1について追記。**

**(2024/1/22) Emacs-29.2について追記。**

## まとめ

- macOSでEmacsを使う際に、 ``Ctrl-\``で、MacOSのIME(ことえり)による日本語入力ON/OFFがしたい。
- `macports`を使い、@takaxpさんのinlineパッチを当てて使う。
- [インラインパッチの配布元](https://github.com/takaxp/ns-inline-patch)から、パッチをダウンロードして、macportsでコンパイル・インストールする。
- 必要な作業をシェルスプリプト化したものが下記。
```bash:build_macports_patched_emacsa-app
#!/bin/bash

patchfiles_url=( "https://raw.githubusercontent.com/takaxp/ns-inline-patch/master/emacs-29.1-inline.patch" )
variant_opts=( "+imagemagick" "+rsvg" "-nativecomp" "+treesitter" "+xwidgets")

macports_version=2.8.1
#macports_root=/opt
macports_root="${HOME}/Documents/workspace/opr/depot/macports-${macports_version}"

this="$0"
this_bn="${this##*/}"
tmpdir="${TMPDIR:-${HOME}/Documents/workspace/opr/var/tmp}"
workdir="${tmpdir%/}/${this_bn}"

port_cmd="$(realpath "${PORT:-${macports_root}/bin/port}")"
port_top="${port_cmd%/bin/*}"

patchfiles=()
mkdir -p "${workdir}"
for purl in "${patchfiles_url[@]}"; do
    ${CURL:-curl} --silent -OL --output-dir "${workdir%/}/" "${purl}"
    patchfile_path="${workdir}/${purl##*/}"
    if [ -f "${patchfile_path}" ] ; then
        patchfiles=( "${patchfiles[@]}" "${patchfile_path}" )
    fi
done

"${port_top}/bin/port" -N    install       autoconf
"${port_top}/bin/port"       clean   --all emacs emacs-app
"${port_top}/bin/port" -v -f patch         emacs-app "${variant_opts[@]}"

build_dir="$("${LS:-ls}" -trd "${port_top}/var/macports/build/"*"/emacs-app/work/emacs-"* | "${TAIL:-tail}" -1)"
pushd ${build_dir} > /dev/null 2>&1
for pf in "${patchfiles[@]}"; do
    echo "${PATCH:-patch} -p1 < ${pf}"
    "${PATCH:-patch}" -p1 < "${pf}"
done
sleep 30
./autogen.sh
popd > /dev/null 2>&1
"${port_top}/bin/port" -v -f install emacs-app "${variant_opts[@]}"
```

- 冒頭の、`patchfiles_url`という変数で、パッチファイルを指定している。また、`macports`のインストールで指定するvariantは、その次の行の`variant_opts`という変数で指定している。 `macports`のインストールされている場所は、`macports_root`という変数を書き換えるか、`port`コマンドを環境変数`PORT`で指定できる。これらを適宜設定して実行する.
- これを実行することで `% port install emacs-app`まで一気に行われる。ただし、正しくパッチが当たったかが人の目に留まるよう、inlineパッチを当てた後にあえて30秒待つ。
- これの後、emacsの設定ファイル(`~/.emacs`か、`~/.emacs.d/init.el`)に、下記の設定(BigSur以降のもの)を追記する.
```emacs-lisp:~/emacs.d/init.el
... 

(when (featurep 'ns)
  (if (version< "27.0" emacs-version)
      (set-language-info "Japanese" 'input-method "MacOSX")
    (set-language-info "Japanese" 'input-method "macOS")
    (setq default-inline-patch "macOS")
    (when (and (memq window-system '(ns nil))
               (fboundp 'mac-get-current-input-source))
      (custom-set-variables
       '(mac-default-input-source "com.apple.inputmethod.Kotoeri.RomajiTyping.Japanese"))
      (mac-input-method-mode 1))))
(set-language-environment 'Japanese)

(when (equal system-type 'darwin)
  (define-key global-map [?\C-¥] 'toggle-input-method))

...

```


## 動機

最近のmacOSでのEmacsの日本語入力設定に関しては、[EMP版Emacs](https://qiita.com/takaxp/items/a86ee2aacb27c7c3a902)というものの情報が多い。しかしながらEMP版Emacsは操作感に違和感を感じてしまった。

永らくEmacsをつかっていたり、Unix/Linuxなど他のプラットフォームでもEmacsを使うことがある場合には、昔ながら/共通のキーバインドや操作感の環境にカスタマイズしたくなるのものと思う。とくに実現したいのは、

  - ``Ctrl-\``で、MacOSのIME(ことえり)による日本語入力ON/OFF

という点である。下記の配布元にはコンパイル済みバイナリの配布もあるようだが、まるべく既存のパッケージ(``macports``など)を利用して、汎用的(ルーチンワーク的)にインストール作業を行えるようにしたい。

これまでは、``macports``の[いわゆるインラインパッチのあたった最後のバージョンの``emacs-25``をインストールして使っていた](https://qiita.com/Nanigashi_Uji/items/ecc05def13e352586140)が、その後Emacsもバージョンアップが進んでいるので、``macports``にある最新のEmacs 27.2 (2021/3月現在)にインラインパッチを当てて日本語入力可能な環境の構築を試すことにした。

# 参考情報

  - [インラインパッチの配布元](https://github.com/takaxp/ns-inline-patch)
  - [インラインパッチ作成者の解説](https://qiita.com/takaxp/items/e07bb286d80fa9dd8e05)

# Macports による作業

下記では、シェル変数``${macports_root}``には、``macports``のインストール先(普通は``/opt/local/``以下？)を指す。
また、上記の配布元から、``emacs-27.1-inline.patch``, ``revert-89d0c445.patch``, ``fix-working-text.patch``の3つのファイルをダウンロードして適当なディレクトリ(下記例では``~/tmp/``)にダウンロードしてあるもととする。

```tcsh:tcshでのターミナル作業(27.1/27.2)
% cd ~/tmp/
% curl -OL https://raw.githubusercontent.com/takaxp/ns-inline-patch/27f15d87f1ce35d7362f2f583655825eab720a8e/emacs-27.1-inline.patch
% curl -OL https://raw.githubusercontent.com/takaxp/ns-inline-patch/27f15d87f1ce35d7362f2f583655825eab720a8e/fix-working-text.patch
% curl -OL https://raw.githubusercontent.com/takaxp/ns-inline-patch/27f15d87f1ce35d7362f2f583655825eab720a8e/revert-89d0c445.patch
% port clean --all emacs emacs-app
% port -v -f patch emacs-app +imagemagick +rsvg
% pushd ${macports_root}/var/macports/build/*/emacs-app/work/emacs-27.2/
% patch -p1 < ~/tmp/emacs-27.1-inline.patch
% patch -p1 < ~/tmp/revert-89d0c445.patch
% patch -p1 < ~/tmp/fix-working-text.patch
% ./autogen.sh
% popd
% port -v -f install emacs-app +imagemagick +rsvg
% open ${macports_root}/Applications/Emacs.app
```

ソースが展開される場所のパス、Emacsのバージョン、``Emacs.app``のインストール先は、``macports``のインストール設定によって環境依存があると思われます。
また、本来なら``Portfile``を修正するのが筋とおもうが、それはおいおい試すことにする。

(2022/4/22追記)
いつのまにかMacportsのEmacsのデフォルトが28.1になっていて、新しいinlineパッチもできていたので、使ってみました。(@takaxpさん、ありがとうございます。)

```tcsh:tcshでのターミナル作業(28.1)
% cd ~/tmp/
% curl -OL https://raw.githubusercontent.com/takaxp/ns-inline-patch/master/emacs-28.1-inline.patch
% port clean --all emacs emacs-app
% port -v -f patch emacs-app +imagemagick +rsvg
% pushd ${macports_root}/var/macports/build/*/emacs-app/work/emacs-28.2/
% patch -p1 < ~/tmp/emacs-28.1-inline.patch
% ./autogen.sh
% popd
% port -v -f install emacs-app +imagemagick +rsvg
% open ${macports_root}/Applications/Emacs.app
```

(2024/1/22追記)
いつのまにかMacportsのEmacsのデフォルトが29.2になっていて,inlineパッチも新しい版が用意されていました。(@takaxpさん、ありがとうございます。) 新しいvariantsが増えていて、``imagemagick``, ``nativecomp``, ``rsvg``, ``treesitter``, ``xwidgets``があります.
多分私の個人的な環境の問題かもしれないですが、よく使っている``Mew``と``nativecomp``の相性が良くない印象なので(ちゃんとテストしてないだけかもしれないですが)、まだ``nativecomp``はdisableして使ってます。

```tcsh:tcshでのターミナル作業(29.2)
% cd ~/tmp/
% curl -OL https://raw.githubusercontent.com/takaxp/ns-inline-patch/master/emacs-29.1-inline.patch
% port clean --all emacs emacs-app
% port -v -f patch emacs-app +imagemagick +rsvg -nativecomp +treesitter +xwidgets
% pushd ${macports_root}/var/macports/build/*/emacs-app/work/emacs-29.2/
% patch -p1 < ~/tmp/emacs-28.1-inline.patch
% ./autogen.sh
% popd
% port -v -f install emacs-app  +imagemagick +rsvg -nativecomp +treesitter +xwidgets
% open ${macports_root}/Applications/Emacs.app
```


# Emacsの設定(``~/.emacs.d/init.el``)の編集

下記の設定例は、Emacsのバージョンが27以降なら上記のパッチが当たっているバージョンで、そうでない場合には``macports``で[いわゆるインラインパッチのあたった最後のバージョン](https://qiita.com/Nanigashi_Uji/items/ecc05def13e352586140)と仮定している。

(2021/8/9追記) **macOSのバージョンによって"ことえり"のメソッド名が変わっているので注意が必要である。**

## Big Sur (11.5)

```emacs-lisp:~/emacs.d/init.el
(when (featurep 'ns)
  (if (version< "27.0" emacs-version)
      (set-language-info "Japanese" 'input-method "MacOSX")
    (set-language-info "Japanese" 'input-method "macOS")
    (setq default-inline-patch "macOS")
    (when (and (memq window-system '(ns nil))
               (fboundp 'mac-get-current-input-source))
      (custom-set-variables
       '(mac-default-input-source "com.apple.inputmethod.Kotoeri.RomajiTyping.Japanese"))
      (mac-input-method-mode 1))))
(set-language-environment 'Japanese)

(when (equal system-type 'darwin)
  (define-key global-map [?\C-¥] 'toggle-input-method))

```
## Catalina (10.15) 以前

```emacs-lisp:~/emacs.d/init.el
(when (featurep 'ns)
  (if (version< "27.0" emacs-version)
      (set-language-info "Japanese" 'input-method "MacOSX")
    (set-language-info "Japanese" 'input-method "macOS")
    (setq default-inline-patch "macOS")
    (when (and (memq window-system '(ns nil))
               (fboundp 'mac-get-current-input-source))
      (custom-set-variables
       '(mac-default-input-source "com.apple.inputmethod.Kotoeri.Japanese"))
      (mac-input-method-mode 1))))
(set-language-environment 'Japanese)

(when (equal system-type 'darwin)
  (define-key global-map [?\C-¥] 'toggle-input-method))
```

## OSのバージョンを気にせず使うには

外部コマンドの実行により`emacs`の起動が遅くなるのを厭わなければ、下記のようなOSバージョン自動判定も可能であろう。

```emacs-lisp:~/emacs.d/init.el
(when (featurep 'ns)
  (if (version< emacs-version "27.0")
      (set-language-info "Japanese" 'input-method "MacOSX")
    (set-language-info "Japanese" 'input-method "macOS")
    (setq default-inline-patch "macOS")
    (when (and (memq window-system '(ns nil))
               (fboundp 'mac-get-current-input-source))
      (custom-set-variables 
       (if (< (string-to-number (nth 0 (split-string
                                        (shell-command-to-string "sw_vers -productVersion")
                                        "[\f\t\n\r\v\.]+")))
              11)
           '(mac-default-input-source "com.apple.inputmethod.Kotoeri.Japanese")
         '(mac-default-input-source "com.apple.inputmethod.Kotoeri.RomajiTyping.Japanese")))
      (mac-input-method-mode 1))))
(set-language-environment 'Japanese)

(when (equal system-type 'darwin)
  (define-key global-map [?\C-¥] 'toggle-input-method))
```

これで以前と同じ操作感で日本語入力可能な``macOS``上の``Emacs27.x``を構築できた。