起動速度のこと

init.elの初期化処理で時間がかかる事は起動後にやるようにした。 参考文書は定番とも言える下記2点。

(defvar my/delayed-configs nil)
(defvar my/delayed-config-timer nil)

(eval-and-compile
  (defconst my/prio-low    1)
  (defconst my/prio-normal 10)
  (defconst my/prio-urgent 100))

(defun my/add-to-delayed-configs (priority config)
  "Add CONFIG with PRIORITY to delayed configs."
  (push (cons priority config) my/delayed-configs)
  ;; sort the configs by priority
  (setq my/delayed-configs (sort my/delayed-configs (lambda (a b) (> (car a) (car b))))))

(defun my/start-delayed-configs ()
  "Execute `my/delayed-configs` list using a timer.

Start a timer to run each config in the list with a default interval of 10ms.
The timer runs until all configs are executed, then it stops.
Customize interval with `my/delayed-config-interval`.
Delayed configs can impact your Emacs environment."
  (setq my/delayed-config-timer
        (run-with-timer 0.0 0.01 ; start after 0ms with 10ms interval
                        (lambda ()
                          (let ((inhibit-message t))
                            ;; if there is a config, execute it
                            (if-let (config (cdr (pop my/delayed-configs)))
                                (eval config)
                              ;; if there is no config, cancel the timer
                              (cancel-timer my/delayed-config-timer)))))))

(add-hook 'after-init-hook 'my/start-delayed-configs)

こんなのを書いて、

(leaf igist
  :ensure t
  :init
  (with-delayed-startup-exec my/prio-low
    (leaf-key "C-c o g" 'igist-dispatch)
    (setopt igist-current-user-name "nekomimist")
    (setopt igist-auth-marker 'igist)))

こんなふうに使っている。leafの:customと:bindも遅延起動できるといいのだが、そういう記法はないので、 with-delayed-startup-execの中でsetoptとleaf-keyを直接使うようにしている。

あとはpackage.elの初期化まわりの処理を見直した。最近のEmacs1はpackage-enable-at-startupがtである限り、(package-initialize)は不要なので、leaf.elの初期化ブロックをそのように変更した。

  (unless package-enable-at-startup
    (package-initialize))

(package-initialize)はとても遅い処理なのでこれでけっこう早くなる。

1: Emacs27あたりだったはず。

2022年最後の段階で、emacs -nwでのemacs-init-timeが270ms程度。

2023年末現在は、このpostの頃とあまり変わらず85ms程度。

WSL2上での速度なので、たとえばnative linuxでやればさらに早くなるだろう。

Packageの追加/廃止

今年もいろいろ入れかえた。

el-get -> package-vc
今までELPA/NonGNU ELPA/MELPAにないパッケージはel-getを使っていたが、 Emacs 29以上ではpackage-vcでgithubから持ってくれるので、Emacs29以降では el-getを全廃した。
shackle -> popper
なんかうまく動いていないのに気付いたので変更。
project-x
標準のproject.elを補うパッケージ。 project-rootの.projectに状態を保存してくれたりする。
nameframe & nameframe-project
projectを開くとproject名のframeを開くようになる。 前述のproject-xと組み合わせるとどうかな?ということでトライ中。
sequential-command -> mosey
sequential-commandってメンテされてないよねってことでなんとなく。
treesit-auto
Emacs29で入ったtreesitter integrationを補うパッケージ。 tree-sitter対応のmajor-modeが使えるならtree-sitterモジュールも入れてくれる等。
multiple-cursors -> macrursors
macurosorsはmeowのBEACONモードみたいな挙動でマルチカーソル編集ができる。 multiple-cursorsがcursorを増やすととんでもなく重くなるけど、macrursorsは軽い。
deft -> xeft
Xapianでメモを検索できて軽い。 dynamic-moduleはwindowsでも動くんだけど、日本語ファイル名食えない(なぜならUTF-8固定だと思っているから)windows環境はdeftのまま。まあ、windowsが悪いよ。 作者がemacs-develでよく見るYuan Fuなので、メンテの継続性も期待できるんじゃないかなと。
zetteldeft -> denote
前述の通りdeftを止めたので、deftに頼らずnote takingできるdenoteに。 作者がmodus-theme等のProtesilaos Stavrouなので、メンテの継続性も期待できるかなと。
tabspaces
Emacsのtab-barの拡張。ただ、あまり活用できてない。
consult-dir
ミニバッファで作業中でも開けるconsultベースのdir名入力ツール。わりと便利かも? popperやgptelの作者karthinkなのでメンテの継続性も期待できるかな、と。
all-the-icons→kind-icon→nerd-icons
GUIだけならSVGで描画するkind-iconのほうがフォント依存がなくてよい点もあるのだが、EmacsでもWindows Terminalでもnerdフォントが入ったフォント(HackGen_NF)を使っているのでnerd-iconsに移行した。おかげでemacs -nwでもiconが出せる。
igist
gistのファイルを一覧で表示したり編集したりできる。便利。
ibuffers - >bufler
標準のibuffersより便利かなと思って入れてみた。 プロジェクト単位で自動グルーピングできるのが便利。
dired-sidebar -> treemacs
treemacsで好みの挙動を得ようとしていろいろhookやらを仕込んでいるのがイヤになってdired-sidebarに移行してたんだけど、やっぱり別の方向でいろいろやる羽目になって、だったらtreemacsのほうがよかったやんということに……。
gptel
ChatGPTを使えるシンプルなパッケージ……だったけど、最近いろんなものがバックエンドに使えるようになった。個人的にはChatGPTしか使ってないのだが、その範囲ではシンプルで使いやすい。 あと、gptel-requestを使ってカスタム問い合わせ関数を作るのも簡単にできて、非常によい。こんなのを書いて、任意の選択範囲あるは行を、任意のdirectiveで一撃で問い合わせできるようにしている。
    (defun my/gptel-query-send (bounds directive)
      "Send a query to ChatGPT.
Convert BOUNDS into plain text and add DIRECTIVE before sending it to ChatGPT.
If executed interactively, BOUNDS can be either a region/line and DIRECTIVE
prompts the user for input."
      (interactive
       (list
	(cond
	 ((use-region-p) (cons (region-beginning) (region-end)))
	 (t (cons (line-beginning-position) (line-end-position))))
	(completing-read "ChatGPT Directive: " my/gptel-query-send-directive-history
			 nil nil nil 'my/gptel-query-send-directive-history)))
      (when (string= directive "") (user-error "A directive is required"))
      (gptel-request
       (buffer-substring-no-properties (car bounds) (cdr bounds)) ; the prompt
       :system directive))
gpt-commit
gitのdiffを送ってcommit-messageを作ってくれる。便利かどうかはわりと悩ましいかもしれない。
immortal-scratch
scratch-bufferを殺しても復活する。定番だとは思うのが、何故か入れてなかった。
auto-dim-other-buffers
カーソルのないウィンドウの背景色を変えてくれる。 着目しているウィンドウがどこかがわかりやすくなる。
pulsar
カーソルがぽんと飛ぶ操作の後にカーソル行がパルスのように光る。 カーソル位置を見失いづらくなる。
zoom
カーソルがいるウィンドウの表示領域が「いい感じ」に拡大される。 わりとよい感じに使えている。
dogears
カーソルがいた場所の履歴を辿れる。標準だと俺の使い方にあまり合わないので、いろんな関数でdogears-rememberを呼ぶようにhookに仕込んだちadviceしまくっている。 trail.elの思想のほうが好きな気もするので、悩み中。
jit-spell
flyspellだとカーソルがあるあたりにだけしかチェックしないのだけど、こいつはバックグラウンドでispellを起動して全バッファチェックできる。libenchantを使うjinxのほうが軽いのだが、日本語に対する挙動の制御の仕方がよくわからかなったので、jit-spellを使っている。
zoxide.el
シェルでzoxideを使っているので一応入れたが、あまり使っていない。
meow → ×
Emacsのmodal editingパッケージ。標準のEmacsキーバインドをあまり阻害しないように作られているせいか、無意識にInsertモードに入ってmeowの機能を使わずに編集していることに気付いたので止めた。 ただ、BEACONモードは面白いと思った。
tree-sitter → × (emacs29以降)
Emacs29でtree-sitter integrationが入ったので、とりあえず外した。 Emacs28以前では使うようにしてあるけれど、そもそもEmacs28以前はあまり使わない。
zygospore → ×
C-x 1で閉じたwindowを再度同じ操作で開けるようにするものなのだが、なんかうまく動かなくなっていたので消した。