公開日: 2023年9月20日

2023 年ですが、Windows で Emacs を使います

阪神タイガースなどで活躍した新庄剛志選手は、プロ入りして最初の給料で買った 7,500 円のグローブを現役引退するまで使用したそうです。そう、何十年も使い続けて手になじんだ道具は、そう簡単には手放せないのです (私は新庄選手とちがって一流ではないけれど…)。

はじめに

本稿では GNU Emacs の設定のうち Windows に関する部分を扱います。それ以外の設定は FreeBSD に関して書いた次の記事とほぼほぼ共通ですので、そちらを参照してください。

ダウンロード

ここでは、インストールが不要な zip 版を下記のサイトからダウンロードします。ファイル名は emacs-<バージョン>.zip です。本稿の執筆時点での最新版は emacs-29.1_2.zip でした。

前準備

  • もし未設定なら、環境変数 HOME に適当なフォルダを設定します。これが UNIX でいうホームディレクトリとなります。本稿では以降、そのフォルダを $HOME と表記します。
  • Emacs 本体や外部ツールをまとめてつっこむためのフォルダを作成します。本稿ではそのフォルダを $HOME\emacs-win\ とし、以降 $emacs-win と表記します。
  • ダウンロードした emacs-<バージョン>.zip を $emacs-win に展開します。後々の都合を考え、展開してできたフォルダ「emacs-<バージョン>」を「emacs」にリネームします。本稿では以降、このフォルダを $emacs と表記します (本稿の想定では $emacs = $HOME\emacs-win\emacs\ となります)。
  • Emacs を起動するには $emacs\bin\runemacs.exe をダブルクリックします。必要に応じてショートカットを作成しましょう。

初期設定ファイル

Emacs の初期設定は $HOME\.emacs.d\init.el に書きます。FreeBSD 側の init.el と共通化を図るために、system-type変数を参照して、Windows の場合とそうでない場合とで設定を切り替えるようにします。具体的には次のように書きます。

(if (eq system-type 'windows-nt)
  (
    ; for Windows
  )
  (
    ; for FreeBSD
  )
)

あるいは

(when (eq system-type 'windows-nt)
  ; for Windows
)

それでは、設定例を示します。Emacs のウィンドウサイズ (フレームサイズ)、フォント、IME などの設定を、Windows とそれ以外とで分けて設定します。

$HOME\.emacs.d\init.el
;;
;; フォントと IME その他環境依存の設定
;; - ON/OFF は C-Backslash
;; - ON/OFF に連動してカーソルの色を切り替える
;;
(if (eq system-type 'windows-nt)
  ;; Windows
  (progn
    ;; フレームの表示位置とサイズ (文字数指定)
    ;; モニタ解像度によって調整する
    (if (> (x-display-pixel-height) 1080)
      (setq initial-frame-alist
        (append (list
          '(top . 50)
          '(left . 200)
          '(width . 110)
          '(height . 50))
        initial-frame-alist))
      (setq initial-frame-alist
        (append (list
          '(top . 50)
          '(left . 100)
          '(width . 110)
          '(height . 40))
        initial-frame-alist)))
    (setq default-frame-alist initial-frame-alist)

    ;; 作業フォルダを ~/ にする
    (setq default-directory "~/")
    (setq command-line-default-directory "~/")

    ;; フォント
    (set-face-attribute 'default nil :family "Consolas" :height 110)
    (set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "MS Gothic"))
    (setq use-default-font-for-symbols nil)

    ;; tr-ime
    (tr-ime-standard-install)

    ;; W32-IME
    (setq default-input-method "W32-IME")
    (setq-default w32-ime-mode-line-state-indicator "[--]")
    (setq w32-ime-mode-line-state-indicator-list '("[--]" "[あ]" "[--]"))
    (w32-ime-initialize)
    (add-hook 'w32-ime-on-hook
      #'(lambda () (set-cursor-color "SteelBlue4")))
    (add-hook 'w32-ime-off-hook
      #'(lambda () (set-cursor-color "gray40")))

    ;; IME 制御 (yes/no などの入力のときに IME を off にする)
    (w32-ime-wrap-function-to-control-ime 'universal-argument)
    (w32-ime-wrap-function-to-control-ime 'read-string)
    (w32-ime-wrap-function-to-control-ime 'read-char)
    (w32-ime-wrap-function-to-control-ime 'read-from-minibuffer)
    (w32-ime-wrap-function-to-control-ime 'y-or-n-p)
    (w32-ime-wrap-function-to-control-ime 'yes-or-no-p)
    (w32-ime-wrap-function-to-control-ime 'map-y-or-n-p)
    (w32-ime-wrap-function-to-control-ime 'register-read-with-preview)
  )
  ;; FreeBSD
  (progn
    ;; フォント
    (add-to-list 'default-frame-alist '(font . "Ricty 12"))

    ;; mozc の設定
    (setq default-input-method "japanese-mozc")
    (add-hook 'input-method-activate-hook
      (lambda() (set-cursor-color "SteelBlue4")))
    (add-hook 'input-method-deactivate-hook
      (lambda() (set-cursor-color "gray40")))
  )
)

Windows 用の設定では最初にウィンドウサイズを設定しています。一方、FreeBSD では私は awesome というウィンドウマネージャを使用していて、ウィンドウサイズを気にする必要がないので、FreeBSD 側はなにも設定していません。

tr-ime (37 ~ 38 行目)、W32-IME (40 ~ 48 行目)、IME 制御 (50 ~ 58 行目) に関しては、tr-ime の README.md (https://github.com/trueroad/tr-emacs-ime-module) を参照してください。

ほかにも C/Migemo などの外部ツールを使用する場合は、上と同様に設定を切り替える部分がありますが、それについては本稿の後半で都度例示します。

外部ツールの取得と設定

ここからは外部ツールを Emacs から使えるようにする話です。 次のツールを使えるようにします。

まず、ツールをまとめてつっこんでおくためのフォルダを $emacs-win の中に作りましょう。以降、そのフォルダを $tools と表記します (本稿の想定では $tools = $HOME\emacs-win\tools\ となります)。

次に、init.el に外部ツールのパスをまとめて追加します。上に掲載した init.el の Windows 設定が書かれている if 文の中 (58 行目と 59 行目の間あたり) に、次のコードを追加してください。これらのパスはまだ存在していませんが、あとで用意します。

$HOME\.emacs.d\init.el
    ;; 外部ツールのパスを追加
    (add-to-list 'exec-path "~/emacs-win/tools/cmigemo")
    (add-to-list 'exec-path "~/emacs-win/tools/global/bin")
    (add-to-list 'exec-path "~/emacs-win/tools/patch-diff-w32")
    (setenv "PATH"
      (concat
        (concat (expand-file-name "~/emacs-win/tools/patch-diff-w32") ";")
        (getenv "PATH")))
    (setenv "PATH"
      (concat
        (concat (expand-file-name "~/emacs-win/tools/pdfout") ";")
        (getenv "PATH")))

ここからは個々のツールの設定方法を説明します。

C/Migemo

ダウンロードしてきた cmigemo-...-20110277.zip を $tools で展開すると、cmigemo-default-win64 というフォルダができますが、長いので cmigemo にリネームします。あとは init.el に次のように書けば、C/Migemo を利用できるようになります。

$HOME\.emacs.d\init.el
;;
;; Migemo
;;
(when (require 'migemo nil t)
  (setq migemo-command "cmigemo")
  (setq migemo-options '("-q" "--emacs"))
  (if (eq system-type 'windows-nt)
    (setq migemo-dictionary (expand-file-name "~/emacs-win/tools/cmigemo/dict/utf-8/migemo-dict"))
    (setq migemo-dictionary "/usr/local/share/cmigemo/utf-8/migemo-dict")
    )
  (setq migemo-user-dictionary nil)
  (setq migemo-regex-dictionary nil)
  (setq migemo-coding-system 'utf-8-unix)
  (setq helm-migemo-mode 1)
  (migemo-init)
)

8、9 行目で Migemo の辞書のパスを設定していますが、ここでも例の if 文で Windows とそれ以外とを分けて設定しています。

GNU Global

ダウンロードした glo669wb.zip を $tools で展開すると、glo669wb というフォルダができますが、わかりやすいように global にリネームします。あとの設定は下記のリンク先にある手順とまったく同じなので、そちらを参照してください。

ただし、もしかしたら zip を展開したフォルダの中にある bin というフォルダを環境変数 PATH に追加しておく必要があるかもしれません。そうしておかないと、最初にタグファイルを作るときに「gtags コマンドが見つからない」というようなエラーが表示されました。しかしその後、再現確認のために bin フォルダを PATH から削除したところ、問題なくタグファイルが作れたので、現在の私の環境では PATH は特に設定していません。

ファイルやバッファどうしを比較する

ダウンロードした patch-diff-w32.zip を $tools で展開します。あとは上で示したパスの設定以外、特に設定は必要ありませんが、init.el に次のように書いておくことで [M-F] キーでファイル比較、[M-B] キーでバッファ比較を実行できるようになります。

$HOME\.emacs.d\init.el
(global-set-key (kbd "M-F") 'ediff-files)      ; ファイル比較
(global-set-key (kbd "M-B") 'ediff-buffers)    ; バッファ比較

テキストを PDF 化する

ダウンロードした pdft100.zip を $tools で展開すると、pdft100 というフォルダができますが、わかりやすいように pdfout にリネームします。

また、nkfwin.zip を展開してできる nkfwin\vc2005\win32(98,Me,NT,2000,XP,Vista,7)Windows-31J フォルダから nkf32.exe を取り出して pdfout フォルダにコピーしてください。それが済んだら nkfwin フォルダは削除してしまってかまいません。

初期設定のために、pdfout フォルダの下にある pdft.exe を実行し、次の例のように設定します (一例なのでお好みでやってください)。ここで設定した内容は、pdft.exe と同じフォルダに pdft.ini というファイル名で保存されます。

  • [全般] タブ (図 1)
    • 用紙のサイズ: A4、縦
    • フォント: MS 明朝 (または MS ゴシック)
    • サイズ: 9
    • しおりを作成する: ON
    • 文書ファイルの圧縮: OFF
    • 文字をボックスで囲む: OFF
    • ラインを描画: OFF
    • 作成日: ON
    • ページ番号: ON
    • 行番号: OFF
    • ヘッダー: OFF
    • タブの文字数: 4
  • [詳細] タブ (図 2)

    デフォルトのまま

  • [環境] タブ (図 3)
    • Acrobat / Acrobat Reader で表示: OFF
    • PDF ファイルの保存先を確認: OFF
    • 既存の PDF ファイルの上書きを確認: OFF
    • ページの順番を選択する: ON
図 1
図 1
図 2
図 2
図 3
図 3

pdfout フォルダの中に次のようなバッチファイルを置きます。ファイル名は pdfout.bat としておきます。

$tools\pdfout\pdfout.bat
rem
rem emacs のバッファテキストを PDF に変換するためのバッチファイル
rem pdft.exe が Shift_JIS しか受け付けないため、前段で nkf を用いて変換する
rem
@echo off
set fname=%~n1
nkf32.exe -s > %fname%.tmp
pdft.exe %fname%.tmp
del %fname%.tmp

注意: このバッチファイルは PDF 化したいファイルの拡張子が .tmp ではない という前提で作っています。拡張子が .tmp のファイルをこのバッチファイルで処理すると消えてしまいますので、なにかしら工夫が必要となります。

init.el に戻り、Emacs から pdfout.bat を呼び出す設定を書きます。次のように書いておくことで、[M-P] キーで選択中のリージョンを、[M-p] キーでバッファを、それぞれ PDF 化することができます。

$HOME\.emacs.d\init.el
(when (eq system-type 'windows-nt)
    (setq pdfout-fmt "pdfout.bat %s")
    (defun pdfout-region (begin end)
        (interactive "r")
        (shell-command-on-region begin end (format pdfout-fmt (file-name-base buffer-file-name))))
    (defun pdfout-buffer ()
        (interactive)
        (pdfout-region (point-min) (point-max)))
    )

(global-set-key (kbd "M-P") 'pdfout-region)    ; リージョンを PDF 出力
(global-set-key (kbd "M-p") 'pdfout-buffer)    ; バッファを PDF 出力

動作確認してみましょう。適当なファイルを開いて、[M-p] キーを押すと、図 4 のようなダイアログが表示されます。拡張子が .tmp になっていますが、気にせず OK ボタンを押します。元のファイルと同じフォルダに <元のファイル名>.pdf が作成されれば成功です。

図 4
図 4

grep (ripgrep)

ダウンロードした ripgrep-...-msvc.zip を $tools で展開すると、ripgrep-...-msvc というフォルダができますが、長いので ripgrep にリネームします。そして init.el に次のように書きます。まず、ripgrep に渡す引数と実行パスの設定です。実行パスは Windows とそれ以外で分けて書いています。

$HOME\.emacs.d\init.el
;;
;; helm-ag, ripgrep
;;
(setq helm-ag-base-command "rg --vimgrep --no-heading")
(setq helm-ag-insert-at-point 'symbol)
(setq ripgrep-arguments '("-S"))
(if (eq system-type 'windows-nt)
  (setq ripgrep-executable (expand-file-name "~/emacs-win/tools/ripgrep/rg.exe"))
  (setq ripgrep-executable "/usr/local/bin/rg")
)

次に、Shift_JIS なファイルを読み込んだら ripgrep のエンコーディング指定を切り替える処理を書いておきます。Shift_JIS の場合はこうしておかないとダメだった記憶がありますが、昔のことなので詳細は忘れてしまいました。

$HOME\.emacs.d\init.el
(when (eq system-type 'windows-nt)
  (defun set-ripgrep-encoding ()
    (let ((name (symbol-name buffer-file-coding-system)))
      (if (string-match "japanese-shift-jis" name)
          (setq ripgrep-arguments '("-S -E Shift_JIS"))
          (setq ripgrep-arguments '("-S")))))
  (add-hook 'find-file-hook 'set-ripgrep-encoding)
)

[M-G] キーで grep を呼び出す設定です。ここも Windows と FreeBSD で処理を分けています。

$HOME\.emacs.d\init.el
(if (eq system-type 'windows-nt)                  ; ディレクトリ内の文字列検索
  (global-set-key (kbd "M-G") 'ripgrep-regexp)    ; Windows では helm-ag から ripgrep を呼ぶ方法が不明
  (global-set-key (kbd "M-G") 'helm-ag)           ; FreeBSD では helm-ag から ripgrep を呼ぶ
  )

最後に、ripgrep などの外部プロセスに対する文字コードを指定します。プロセスへの入力は cp932、プロセスからの出力は utf-8-dos とします。注意点として、この設定は setq-default-coding-systems の後に記述しないと上書きされてしまうので、init.el の末尾に近い位置に書くようにします。

$HOME\.emacs.d\init.el
(when (eq system-type 'windows-nt)
  (setq default-process-coding-system '(utf-8-dos . cp932))
)

動作確認してみましょう。[M-G] キーを押すとミニバッファに「Ripgrep search for: 」と表示されるので検索文字列を入力します。[Enter] キーを押すと「Directory: 」と表示されるので、検索のルートディレクトリを指定します。*ripgrep-search* バッファが開いて検索結果が表示されれば OK です。

その他の設定

その他の設定は FreeBSD と共通のはずなので、(何度も書いていますが) 関連記事「GNU Emacs TIPS」を参照してください。~/.emacs.d/ の下にあるファイルや、パッケージとしてインストールされた *.el、*.elc なども、フォルダ構造を保ったまま FreeBSD 側から丸ごとコピーしてくれば動作します。