GNU Emacs 27.2 for Windows で Emacs に入門したときの個人的な備忘録

Emacs 27.2 を Windows 環境に構築しました。GUI と Cygwin + CUI で使う前提ですが、Mac の Emacs の設定も同居させております。
その際の設定の備忘録です。

Emacs のバイナリについて

この文章を書いている 2021 年 8 月 1 日において、Emacs 27.2 が最新です。現在としては、下記手段で Windows では Emacs が利用できます。

・Cygwin 版 Emacs
・GNU 公式が配布している GUI 版 Emacs

GUI 版 Emacs は Chocolatey でインストールするのが一番簡易かと思います。また、GUI 版 Emacs は IME と相性が悪く、いくつか設定が必要となります。後述しますが、メンテナ・先駆者の方々には頭の下がる思いで設定いたしました。

Emacs の設定方針について

個人的な使い方として、カット・コピー・ペーストは cua-mode を有効にしてます。そこだけは一般的なショートカットキーです。
一つの init.el に GUI 及び CUI の設定を記入しまして、GUI のみ有効にしたい設定などは if で分岐させてます。
設定の段落は、

・Emacs 本体の基本的な設定
・キーバインド
・UI
・package
・各 mode などの設定

という形に分けました。それなりに分かりやすく、綺麗にできたかなと思ってます。
パッケージマネージャはデフォルトの package を使用してます。デフォルトで用意されているものはそのまま活用したい主義ではありますが、他を使用してみたいと思うほど不満は一切ないです。

Emacs 本体の基本的な設定

起動時に表示する scratch バッファを text-mode にする

Lisp ファイルよりかは圧倒的にメモ書き・プレーンテキストが多いので、text-mode にしてしまいます。

​(setq initial-major-mode 'text-mode)
(setq default-major-mode 'text-mode)

バックアップファイル、スワップ、ロックファイルを作らない

ファイルを読み込み時に Emacs により勝手に作られるファイルを無効化します。

(setq make-backup-files nil)
(setq auto-save-default nil)
(setq create-lockfiles nil)

他、詳細は解説しませんが下記のような設定を追加しました。

(column-number-mode t)  ; モードラインに列番号を表示
(delete-selection-mode t)  ; リージョン選択時に文字入力やヤンクをすると上書き https://dev.classmethod.jp/articles/emacs-settings/
(setq scroll-step 1)  ; スクロールは 1 行ずつ
(setq ring-bell-function 'ignore)  ; ベルはならさない
(setq scroll-preserve-screen-position t)  ; ポイント位置を保ったままスクロール

キーバインド

cua-mode の有効

cua-mode を有効にしてます。何か文字列をリージョン選択しているときは、C-x は切り取りの動作になりますが、それ以外は通常の C-x となります。
C-c でコピーしたとき、デフォルトではリージョン選択を解除しますが、cua-keep-region-after-copy を t にすると解除しません。Windows OS や各種テキストエディタにおける標準の挙動になります。

(cua-mode t)
(setq cua-keep-region-after-copy t)

C-h は Backspace に、C-k にも一手間を加える

C-h は Backspace に変更してますが、C-k も一手間加えております。行全体を削除するために C-k は便利なのですが、キルリング + クリップボードに削除した内容が毎回入るのは面倒です。そのため、キルリングに入れずにカーソル位置から行全体を消す関数を作成しました。 https://stackoverflow.com/questions/637351/emacs-how-to-delete-text-without-kill-ring を参考にしてますが、こちらの投稿の通りの関数の場合、オリジナルの C-k と若干挙動が違うため、オリジナルに合わせております。

(define-key key-translation-map (kbd "C-h") (kbd "<DEL>"))
(defun delete-line-no-kill ()
 (interactive)
 (if (looking-at-p "$")  ; 行末で C-k したとき、改行を削除する
   (delete-char 1)
   (progn
     (delete-region
      (point)
      (save-excursion (move-end-of-line 1) (point))
    ))))
(global-set-key (kbd "C-k") 'delete-line-no-kill)

Shift キーと矢印キーの動作を OS 標準っぽく

shift とカーソルキーを押した場合、OS 標準では文字が選択されますが、Emacs でも shift-select-mode を有効にすると同じような動作になります。C-space のキーバインドよりかは便利かなと思ってます。ただし、Cygwin では使用できないようです。

(setq shift-select-mode t)

UI

フルパスの表示

モードラインのファイル名をフルパスにするようにしました。モードラインはもっと便利に使用できるようカスタマイズしていきたいですね。

(set-default 'mode-line-buffer-identification
            '(buffer-file-name ("%f") ("%b")))

細かい UI の調整

GUI 版と CUI 版で細かい UI が変更できるように、下記のように if で分岐させてます。GUI ではテーマや、ツールバーなどの非表示、カーソルの形状変更やウインドウのサイズなどを指定しています。一方で、CUI は xterm の色の指定ですね。

 (if window-system
 (progn
   (load-theme 'afternoon t)
   (tool-bar-mode -1)
   (setq-default cursor-type 'bar)
   (set-window-scroll-bars (minibuffer-window) nil nil)  ; ミニバッファにスクロールバーを表示させない
   (set-fringe-mode '(0 . 0))
   ; window size 200x60
   (set-frame-size (selected-frame) 200 60)
 )
 (progn
   (menu-bar-mode -1)
   (set-face-foreground 'font-lock-comment-face "green")
   (set-face-foreground 'font-lock-string-face  "red")
   (set-face-foreground 'font-lock-type-face "red")
   (set-face-attribute 'line-number nil
		    :foreground "black"
		    :background "yellow")
 )
)

GUI 版でのフォントの指定を OS ごとに

フォントの指定は Windows と Mac でそれぞれ別個に指定できるようにしました。Windows も set-face-attribute で指定できるようにしたかったのですが、上手くいかず、一旦は記載の通りで設定しています。表記ゆれ以外は困ったこともないので、これでよしとしてます。
IME にて変換中のフォントが本文のテキストのフォントと異なる指定になります(変換中のフォントは必ずMSゴシックの 13pt?)。
tr-ime を有効時、modify-all-frames-parameters の ime-font を指定することで、フォントの指定をすることができるので、これで合わせることができます。
Mac のフォントの指定は http://misohena.jp/blog/2017-09-26-symbol-font-settings-for-emacs25.html を参考にいたしました。

(if window-system
 (progn
   (when (eq system-type 'windows-nt)
     (progn
	(setq default-frame-alist (append (list '(font . "HackGen-9")) default-frame-alist))
	(set-face-font 'mode-line "HackGen-9")
	(modify-all-frames-parameters '((ime-font . "HackGen-9")))))
   (when (eq system-type 'darwin)
     (progn
	(set-face-attribute 'default nil :family "Cascadia Code" :height 140 :weight 'regular)
	(set-fontset-font nil '(#x80 . #x10ffff) (font-spec :family "Hiragino Kaku Gothic ProN"))
	(setq use-default-font-for-symbols nil)
	))))

静かな Emacs になってもらう

起動時の各種メッセージは以下の通り設定して、寡黙にしました。この他、不要なメッセージは抑制しようと思ってますが、他特に消したいと思ったメッセージは見つけておりません。

(setq inhibit-startup-message t)
(setq initial-scratch-message "")
(setq inhibit-message "")

左側に行番号の表示

27.2 現在、行番号の表示は display-line-numbers が主流です。過去、主流であった linum よりは高速とのことですが、有効・無効時比較して、まだつっかかりを感じるような……そんな気分です。
global への適用のため、imenu や neotree 使用時、行番号が表示されますが、各 hook に (display-line-numbers-mode 0) を追加することで非表示にさせてます。
display-line-numbers-mode の設定で適用しない Major mode を指定できればスマートかなと思ってますが、はたしてこの設定が適当なのか不明瞭です。

(global-display-line-numbers-mode)

;;; neotree
(add-hook 'neotree-mode-hook (lambda ()
			       (setq mode-line-format nil)
			       (display-line-numbers-mode 0)))

;;; imenu
(add-hook 'imenu-list-major-mode-hook (lambda ()
					(setq mode-line-format nil)
					(display-line-numbers-mode 0)))

packages とインストールしたもの

Emacs 上から package-install でパッケージを選択し、インストールを行っております。そのため、init.el の package-selected-packages リストは手動では修正をしたことがありません。
init.el を他のマシンに同期をしたとき、同期元のマシンではパッケージはインストールされておりませんが、同期先のもう一方はパッケージは存在しません。その場合 package-install-selected-packages を実行すれば、インストールされていないパッケージを自動でインストールしてくれるため非常に便利です。

各種プログラミング言語の Major mode 以外、インストールしたパッケージは以下です。

・テーマ
→ afternoon-theme(色々とお試し中であるが、今のところしっくりきている)

・ivy を使用している各種補完計コマンド
→ ivy
→ swiper
→ counsel

・アウトラインエディタっぽく使用するために必要
→ imenu-list

・ツリーでファイルリストを表示
→ neotree

・日本語入力のために必須
→ tr-ime

ivy, swiper, counsel の設定

swiper は C-s の isearch の上位互換、counsel は M-x のコマンド補完となります。どちらも対象をリッチなビジュアルのインクリメンタルサーチで検索できるため、非常に便利です。
find-file も counsel に置き換えができますが、これもインクリメンタルサーチでファイルを絞り込みできるのが便利です。
swiper 使用時に IME をオンにする手間がそこまで面倒に感じなかったため、migemo 連携は一旦保留にしてます。swiper + ivy + migemo の連携を取るのがいまいち上手くできなかったというのもあります。

;;; ivy
(require 'ivy)
(ivy-mode 1)
(setq ivy-use-virtual-buffers t)
(setq enable-recursive-minibuffers t)

;;; counsel
(global-set-key (kbd "M-x") 'counsel-M-x)
(global-set-key (kbd "C-x C-f") 'counsel-find-file)
(setq counsel-find-file-ignore-regexp (regexp-opt '("./" "../")))

;;; swiper
(global-set-key "\C-s" 'swiper)

tr-ime の調整(C-h はそのまんまにしてもらう)

tr-ime は advance で使用してまして、今のところ便利に使用させてもらっております。Emacs + IME での日本語入力に不満はありません。
ごく細かい事を気にすれば、cua-mode 有効時にリージョン選択時は prefix-key として認識しないで欲しい、というのがありますが、若干のディレイを感じる以外は困っておりません。
C-h はヘルプの prefix キーから Backspace へ変更しておりますので、prefix キーとして認識しないようにしました。C-h で大量に文字を消そうとしているとき、tr-ime が有効になりつっかかりが発生する……、といったことがなくなります。

(when (eq system-type 'windows-nt)
 (progn
   (tr-ime-advanced-install)
   (setq default-input-method "W32-IME")
   (w32-ime-initialize)
   (custom-set-variables '(tr-ime-prefix-key-list
                       '(#x20058 #x20043 #x1b)))
   )
)

サーバ有効化

Windows から

runemacs.exe -f server-start 

で起動させるのが一番楽かなと思ってます。一方で、複数の Emacs のウインドウを開きたい、といった場合、どのように複数のサーバを開けばいいか、どのようにサーバを指定してファイルを開くか、は試行錯誤してます。コマンドラインを一々指定するのも色々とやりようがあるので、一番上手く行く方法が見つかると嬉しいですね。

まとめ

この後、git 管理や各種プログラミング言語のパッケージはインストールしていきますが、とりあえず通常の文章を書くにあたって困らない程度にはなりました。
Emacs の設定は膨大な中から探していく大変さがありますが、テキストエディタとして必要なことをリストアップして調べながら設定すると、なかなか面白いものです。
猫も杓子も Visual Studio Code が一世を風靡している世の中ですが、Emacs も年々進化をしておりますし counsel や swiper など、びっくりするくらい便利な機能も開発され続けております。未だに世界の第一線で使われているエディタとして脱帽です。


老後、奥さんと世界一周のための費用にします。