- EmacsでMarkdownファイルをそのままスライドとして発表できる
logosパッケージの設定をしてみました。 logos-outlines-are-pagesを有効にすると、Markdownの見出しが自動的にページ区切りにできます。C-c l lでfocus modeを起動し、キー操作でページを前後に移動できます。- 配布用スライドが必要な場合はMarpを使い、同じMarkdownファイルをそのまま変換できます。
1. Emacsを発表に使いたい
手元のEmacsを画面に表示して、発表しているのをみることがあります。
Orgファイルの見出しを開閉して、スライドやマインドマップのように使っているのはわかりやすく、同じことをMarkdownでやりたくなりました。

Org modeでもよいのですが、Markdownの方が生成AIとの相性がよく、編集できる原稿がすぐに返ってくるからです。
そこで、Emacsで「そのまま発表する」ために、 logos パッケージを試してみました。
1.1. logosパッケージとは
logos は、Emacsのバッファをページ単位で読み進めるための focus mode パッケージです1。
MarpやBeamerのように「スライドファイルを出力する」ものではなく、Emacsのバッファをその場で発表者ビューのように使う道具です。

ページ区切りには、^L という改ページ文字を使います。
ただ、logos-outlines-are-pages を t にすれば、正規表現で判定した見出しが自動的にページになります。
そのため、見出し構造のあるMarkdownのバッファでは、そのまま動かせます2。
2. 設定したキーバインドと使うイメージ
logosには、デフォルトのキーバインドは用意されていないので、使いやすいように自分で設定します。
私の場合は、Markdownファイルを開いた状態で C-c l l を押すと、logos-focus-mode がオンになり、現在の見出しのページだけに表示が絞るようにしました3。
そして、→で次のページへ、←で前のページへ移動できます。
もう一度 C-c l l を押すと全文表示に戻ります。
たとえば、Markdownはこのように書けば十分です。
# Common Lispのキュー
今日話すこと。
## キューとは
- FIFO構造
- BFSでよく使う
- head と tail を持つ
## consセルによる実装
(defstruct queue
head
tail)
## まとめ
- キューは状態を持つ
- head と tail の更新が重要Code language: Markdown (markdown)
見出しがそのままページになり、C-c C-n を押すたびに次の表示に切り替わります。
2.1. init.elの設定コード
(use-package logos
:ensure t
:custom
(logos-outlines-are-pages t)
:bind
(("C-c l l" . my/logos-focus-mode))
:config
;; logos-focus-mode がオンのときだけ効くキー
(define-key logos-focus-mode-map (kbd "<right>")
#'logos-forward-page-dwim)
(define-key logos-focus-mode-map (kbd "<left>")
#'logos-backward-page-dwim)
;; face-remap を戻すための記録
(defvar-local my/logos-face-remap-cookies nil
"Face remap cookies used while `logos-focus-mode' is active.")
(defun my/logos-apply-presentation-faces ()
"Apply presentation-oriented faces in current buffer."
(setq my/logos-face-remap-cookies
(list
;; 全体の文字サイズ
(face-remap-add-relative 'default
:height 1.5)
;; Markdown 見出し2
(face-remap-add-relative 'markdown-header-face-2
:overline nil
:foreground "#3c3c3c"
:background "#F1F0DF"
:height 1.2
:slant 'normal)
;; Markdown 見出し3
(face-remap-add-relative 'markdown-header-face-3
:overline nil
:foreground "#3c3c3c"
:background "#F1F0DF"
:height 1.1
:slant 'normal)
;; Markdown 記号部分
(face-remap-add-relative 'markdown-markup-face
:foreground "#555400"
:background "#F1F0DF"
:inherit 'normal))))
(defun my/logos-clear-presentation-faces ()
"Clear presentation-oriented faces in current buffer."
(when my/logos-face-remap-cookies
(mapc #'face-remap-remove-relative
my/logos-face-remap-cookies)
(setq my/logos-face-remap-cookies nil)))
(defun my/logos-focus-setup ()
"Setup buffer-local presentation view for `logos-focus-mode'."
(if logos-focus-mode
(progn
;; 二重適用を避ける
(my/logos-clear-presentation-faces)
(my/logos-apply-presentation-faces))
(my/logos-clear-presentation-faces)))
;; logos-focus-mode の ON/OFF に表示変更を連動させる
(add-hook 'logos-focus-mode-hook
#'my/logos-focus-setup)
(defun my/logos-focus-mode ()
"Toggle `logos-focus-mode' and narrow/widen with it."
(interactive)
(if logos-focus-mode
(progn
(when (buffer-narrowed-p)
(widen))
(logos-focus-mode -1))
(logos-focus-mode 1)
(unless (buffer-narrowed-p)
(logos-narrow-dwim)))))Code language: Lisp (lisp)
設定には、3つの工夫があります。
logos-outlines-are-pages t によって、Markdownの見出しをページとして扱います。^L を手で入れる必要がないので、普通にMarkdownを書けば区切りができます。
→ と ← は logos-focus-mode-map に定義しています。
focus mode がオンのときだけページ送りのキーとして機能し、オフのときは markdown-mode 側の割り当てがそのまま使われます。
logos-focus-mode を直接キーに割り当てず、my/logos-focus-mode というラッパー関数を挟んでいます。
オンにするときは focus mode を有効化してから現在ページへ narrow し、オフにするときは先に widen してから無効化します。
あと、text-scale-modeで、フォントを拡大したり、戻したりします。
逆順にすると logos-focus-mode-hook 経由では無効化後の後処理が書きにくくなるためです。
なお、logos-narrow-dwim はトグル動作で、すでに narrow されている状態で呼ぶと widen します4。unless (buffer-narrowed-p) で囲んでいるのは、二重に呼ばれても widen にならないようにするためです。
3. logosとMarpとの使い分け
Emacs内でそのまま話すなら logos が向いています。
PDFやHTMLへの変換が不要で、編集しながら発表できます。
生成AIと往復しながらスライドを育てる用途にも合います。
一方、配布用のPDFやHTMLスライドが必要なら Marp です。
Marpは --- をスライド区切りとして、Markdownからスライドデッキを出力できます5。
frontmatterに marp: true を書くだけで使えて、VS Code拡張やCLIが充実しています。
Emacsで logos を使って発表し、同じMarkdownをMarpで変換して配布する、という流れはそのまま成立します。
4. 最終的なコード
Code language: Lisp (lisp)
- 作者はProtesilaos Stavrou氏で、GNU ELPAから入れられます。現在の安定版は1.2.0(2024年9月3日リリース)で、開発版として1.3.0-devが進行中です。GNU ELPAからは
M-x package-install RET logosで入れられます。 – logos GNU ELPA logosは設計上デフォルトでキーを一切バインドしません。公式マニュアルにも「To get the do-what-I-mean page motions add your own key bindings.」と明記されています。 – Logos Manual- narrowingはEmacsの機能で、バッファの特定範囲だけをアクセス可能にし、それ以外を一時的に非表示にします。ファイルの保存時は全体が書き込まれます。解除には
C-x n w(widen)を使います。 – Narrowing (GNU Emacs Manual) - この挙動は
logos-narrow-dwimのソースコード末尾に(t (widen))として実装されており、公式マニュアルにも「narrowing が有効なら widen する」と説明されています。 – Logos Manual - MarpはHTML・PDF・PowerPointへの変換に対応しています。変換にはGoogle ChromeまたはChromiumを使用します。VS Code拡張とMarp CLIが主な利用ツールです。 – Marp: Markdown Presentation Ecosystem