Braindump

バブちゃんへ贈る Emacs の歩き方

December 13, 2021
emacs

この記事は Emacs Advent Calendar 2021 の14日目の記事です.

はじめに #

Emacs を始めたての頃はパッケージ導入の際の設定は理解しないままネットからコピペすることが多いと思う.この記事では,パッケージ導入から自分に適した設定までの一連の動作を一人で行えるようになることに重点を置く.

タイトルにあるバブちゃんとは,Emacs の基本的な操作に慣れ始めて,コピペを駆使すればパッケージ導入を行うことができるようになった人を指す.いわばハイハイができるようになった状態である.この記事では,そんなバブちゃんが Emacs 内での二足歩行を会得する際の助けになるような情報提供を目指す.

記事の前半では便利な tips やパッケージの紹介を行い,後半では前半に紹介した内容を活用してパッケージの設定を行った実例を紹介する.

想定読者 #

  • 息をするように C-b, C-f, C-n, C-p などの移動ができる
  • C-c, M-x などの基本的な表記を理解している
  • 以下の記事で解説されている内容が5割くらい理解できていれば (たぶん) 大丈夫

この記事で扱わないこと #

  • elisp 全般
  • パッケージの導入方法
  • setqcustom-set-variables 等を用いた変数の設定方法

tips #

ここではパッケージ導入とその設定を行う際に知っておくと役に立つ built-in 機能を紹介する.

パッケージ検索 #

M-x list-packages でインストール可能なパッケージ一覧を見ることができる.(package-archives の設定が済んでいる前提)

このバッファ内で iserch 等の検索をかければ気になるパッケージに出会える可能性がある.パッケージをクリックまたは RET すればパッケージの説明と,github上で管理されていればそのリンクを見ることができる.

/images/2021-12-search-package.jpg

パッケージの説明はパッケージファイルの冒頭に書かれている #

多くの場合,パッケージファイルの冒頭にパッケージの説明が書かれている.親切なパッケージでは推奨設定が記載されていることもある.

/images/2021-12-package-doc.jpg

ユーザーオプションは defcustom で定義されている #

パッケージファイル内で grep すれば設定可能なオプションが見つかる.

以下の画像では consult-grep で集めた情報を embark-export で抽出している.このバッファで n/p を押すとファイルをまたいでプレビューしてくれるため,複数ファイルで構成されているパッケージをカスタマイズしたい時に便利.

/images/2021-12-defcustom.jpg

関数や変数の定義へ M-. でジャンプ #

xref-find-definitions (M-.) でポイント下にあるシンボルの定義へとジャンプすることができる.

ジャンプした後に迷子にならないために #

ジャンプ前にどこにいたのか覚えておくのは至難の技だと思う.少なくとも私はジャンプした瞬間に全てを忘れてしまう.

そんな鶏のような人のために, Emacs には以下2種類の便利な機能が用意されている.

  • C-u C-SPC or (set-mark-command 4)

    set-mark-command 自体は範囲選択でおなじみの C-SPC だが,これに prefix キー C-u を付けて実行するとジャンプ前のところに戻ってくれる.(ただし,移動は同じバッファ内に限る).ちなみに,prefixとして C-u を入力すると関数には 4 が渡される.

    Emacs には mark-ring というものがあり,そこにポイントの位置が保存されている.保存タイミングは C-SPC や前述の M-. が実行されたとき,他にも様々. C-u C-SPC を実行すると mark-ring を遡るようにしてポイントを移動してくれるという仕組み.

  • switch-to-prev-buffer

    バッファの並び順で一つ前のバッファに移動するコマンド.定義ジャンプした際に別ファイルに飛ばされたら C-u C-SPC で帰ってくることはできない.そんなときは M-x switch-to-prev-buffer を実行すれば元の場所に戻ることができる.

    実行しすぎて元いたバッファを通り過ぎた場合は M-x switch-to-next-buffer を実行すればバッファを進めることで帰って来ることができる.

    私は C-x C-p, C-x C-p にバインドして使っている.

    (global-set-key (kbd "C-x C-p") #'switch-to-prev-buffer)
    (global-set-key (kbd "C-x C-n") #'switch-to-next-buffer)
    

describe-* を実行すればたいてい分かる #

歩き回っていると未知のものに多々遭遇する.そんなときは M-x describe-* を実行すれば Emacs さんが describe してくれる.

  • describe-variable: 変数の中身確認ならこれ

  • describe-function: 関数定義の確認ならこれ

  • describe-symbol: alias や macro はこっちで見つかることがある

  • describe-key: キーバインドに割り当てられたコマンドを調べたいときはこれ. describe-key の実行後に調べたいキーバインドを入力すると describe してくれる.

    /images/2021-12-define-key.jpg

そもそも elisp が良く分からん #

*scratch* バッファ (lisp-interaction-mode) で C-j しよう.ポイントの直前のシンボルやS式を評価して,結果を下に表示してくれる.

Emacs の中を歩き回るときや新しい elisp を学ぶとき,理解できないものに多々直面する.そんなときに実行結果を確認しながら試行錯誤すれば理解の助けとなる.

/images/2021-12-scratch.png

lisp-interaction-mode 以外では C-j による結果の確認はできない.代わりに C-x C-e (eval-last-sexp) を実行しよう.結果は *Message* バッファに出力される.

エラー箇所を知りたい #

*Message* バッファにエラーは出るけど,それがどのタイミングで発生しているか分からないことがある.そんなときは M-x toggle-debug-on-error or (setq debug-on-error t) を実行しよう.エラーが発生したときに,その詳細な箇所を教えてくれる.

/images/2021-12-debug.jpg

便利な外部パッケージ #

ここでは歩き回る際に便利なパッケージを紹介する.

Helpful #

describe-* 実行時に表示される情報がリッチになる.ドキュメントに加え,定義や reference も表示される.

command-log-mode #

実行したキーバインドとコマンドを表示してくれる.キーボードを触っていて「今なにが起こった?!」となることは多々ある.そんなときは M-x command-log-mode をオンにして M-x cml/toggle-command-log-buffer を実行すれば,実行したキーバインドとコマンドが表示されるバッファが開く.

/images/2021-12-command-log.png

実例 #

ここでは前半に紹介した tips を活用して設定を行なった実例を2つ紹介する.

Example 1 #

パッケージ設定ではないが, s-[hjkl]window の移動をしたくなって設定したことがあるので,それを紹介する.

まず describe-function (helpful-function) でいい感じの関数がないか調べる. move left で調べるとそれっぽい関数が見つかった.

/images/2021-12-windmove-search.jpg

関連する windmove-right なども見つかり,バインドして動作確認したら望むものだったので採用.

/images/2021-12-windmove-demo.jpg

Example 2 #

最近,bib ファイルから TeX や org へと適切なフォーマットで参考文献を挿入するために citar というパッケージを導入した.

便利な反面,参考文献の挿入の際に少々面倒な点があったため,その点の改善の過程を紹介する.

このパッケージを用いて TeX で参考文献を挿入するには以下3ステップを踏む必要がある.

  1. 文献選択

    /images/2021-12-citar-ref.png
  2. 挿入フォーマット (cite, citet, citep など) の選択

    /images/2021-12-citar-cite-old.png
  3. Prenoteの入力

    /images/2021-12-citar-prenote.png

上二つは必要だとしても,三つ目はいらない.そもそも Prenote ってなんだ.Enter を連打するのも面倒くさいので,なんとかしてこれを消したかった.

とりあえず関数定義へ #

現在手元にある情報は citar-insert-citation を実行したらその最後に Prenote の入力画面が出るということ.

まずはこの関数が何をしているのか調べる. describe-function (or helpful-function) で citar-insert-citation を検索してゴニョゴニョする.

/images/2021-12-citar-help.png

なるほど,分からん.

grep で Prenote という文字を探す #

elisp 何も分からないマンなので,Prenote という文字で grep して関係していそうなところを探していく.

まずはパッケージのある場所へ移動する.describe (or helpful) のバッファに親切にリンクが表示されているのでそれをクリックすれば飛べる.

バッファ内で prenote で検索しても見つからなかった. find-file をしてみると,このパッケージは複数ファイルで構成されていて prenote は別ファイルのどこかで定義されていそうなことが分かる.

/images/2021-12-citar-find-file.png

そんなときは grep で串刺し検索.私は consult-grep を使っている.

/images/2021-12-citar-grep.png

とりあえず上から見ていくとそれっぽいものが見つかった.大量の cite コマンドも見覚えがある.そう言えば cite コマンドが大量に出るのも邪魔に感じていた.これをいじればいい感じになりそうな気がする.

/images/2021-12-citar-def.png

試行錯誤のために *scratch* バッファへとコピペ.不要な部分を削って setq で再定義してみる.

/images/2021-12-citar-scratch.png

動作確認してみると期待通りに反映されていた.今回は運よく一発で期待通りになったが,普段は上記の工程を繰り返す.

/images/2021-12-citar-cite-new.png

おわりに #

本投稿ではパッケージ導入とその設定を行う際に活用可能な tips や外部パッケージの紹介を行った.この記事が Emacs という沼に沈んで行く際の重石になれば幸いである.

最後におすすめリンクをいくつか紹介してこの記事を締めたいと思う.

2020年代のEmacs入門
全人類必読の Emacs 入門記事
Emacsの次世代ミニバッファ補完UI
Emacs のミニバッファ補完 UI の紹介を行っている全人類必読の記事
emacs-from-scratch
Emacs を真っ新な状態から設定していく記事/動画