裏紙に雑文

日記とか,とりとめのないこと

私的 YaTeX 事始め

YaTeX を使ってみたくて Emacs をインストールした (またはインストールしようとしている) 私みたいな人へ向けて, 設定のまとめみたいな記事を書きました.

最初に

EmacsLaTeX 入力支援環境に YaTeX: Yet Anoter TeX mode for Emacs というものがあります. 同様の入力支援環境に,Emacs 同梱の TeX mode とか AUCTeX とかがありますが,YaTeX の良いところは日本語でマニュアルが読めるという点です. もちろん機能も豊富で非常に良い環境だと思います. YaTeX のために Emacs をインストールしても損はないと思います.

ただ,インターネットを検索してもどうにも古そうな情報だったり,絶妙に痒いところに手が届かなかったりします. 本稿は私が調べた限りで,そこまで古くなく,(私が)有用だと思った設定を備忘録代わりにまとめたものです. 偉そうなことを書きましたが,私も Emacs Lisp は全くわかりませんので,問題点や疑問などあればコメントいただければ幸いです.

対象読者層としては,Emacs の設定ファイル ~/.emacs.d/init.el に何か書き込んだことがある人を想定しています. 以前書いた記事よりはもう少し初心者向けには書いたつもりです. YaTeX の使い方は Web サイトを見ていただくとして,本稿での設定をコピペすることで YaTeX を使い始められるようにするのが目標です.

また,本稿執筆時の筆者の環境は

macOS 10.13.6
GNU Emacs 26.1

です. 本稿では Emacs の設定ファイル (初期化ファイル?) は ~/.emacs.d/init.el を想定しています.

インストール

Emacs 24 から package.el というパッケージマネージャが同梱されています. package.el を用いた YaTeX のインストール方法は例えば 比較的まともな YaTeX のインストール方法 などの記事があります. 最近は use-package.el を用いるのが今風のという噂を聞いたので use-package.el の導入から簡単に説明します. use-package.el を利用するには Emacs 24.3 以上が必要で,特に 24.4 以上を推奨しているようです.

use-package の導入

インストール

use-package.el も yatex.el も MELPA からダウンロードできます. 詳しい導入方法は MELPA/Getting started を見てください.

以下のコードは,use-package.el がインストールされていなければ MELPA からダウンロード・インストールし use-package を読み込む,というものです. これを設定ファイルのなるべく最初の方に書き込みます.

(require 'package)
(add-to-list 'package-archives
         '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
(unless package-archive-contents (package-refresh-contents))
(unless (package-installed-p 'use-package)
  (package-install 'use-package))
(require 'use-package)

これを保存して (C-x C-s) Emacs を再起動させれば use-package.el がインストールされます.

use-package の大まかな使い方

use-package の使い方については良い記事がたくさんあります. 例を挙げると

などです. これらの記事に書かれていないことや,新しく追加された機能も見受けられますので use-package の Web サイトも参照してください. 大まかな使い方は

(use-package package
  :init
  ;; package を読み込む前に設定することを書く
  :config
  ;; package を読み込んだ後に設定することを書く
  )

となります. つまり今まで requireautoload, with-eval-after-loadadd-hook で行ってきた設定の置き換えができます.

YaTeX のインストール

ひとまず YaTeX をインストールするには次のようにすれば良いです.

(use-package yatex
  :ensure t)

:ensure t を書くことで YaTeX がインストールされていない場合,自動的にインストールしてくれます.

YaTeX の基本設定

さて YaTeX の基本的な設定について行っていきます. ここでは

などを設定します.

YaTeX-inhibit-prefix-lettert にすると,YaTeXキーバインドC-c 英字 から C-c C-英字 へと変わります. これは Emacs Lisp の習慣で C-c 英字 の形のキーバンドは個々のユーザ向けに予約されているものだからだそうです. (setq YaTeX-inhibit-prefix-letter t)yatex.el が読み込まれる に設定する必要があります.

latexmk は自動的に必要な回数だけ (u)platex や (u)pbibtex, (up)mendex を実行してくれるツールです. これも様々な解説記事があります. 最近は llmkClutTeX などを使うのも良いかもしれません. latexmk ではなく (u)platex + dvipdfmx などの組み合わせを用いてタイプセットを行うには (setq tex-command "platex")(setq YaTeX-dvipdf-command "dvipdfmx") などと設定します.

UTF8 を使うには変数 YaTeX-kanji-code を 4 に設定します. 1 は SJIS, 2 は JIS, 3 は EUC のようです.

(use-package yatex
  :ensure t
  :init
  (setq YaTeX-inhibit-prefix-letter t)
  :mode (("\\.tex\\'" . yatex-mode)
         ("\\.sty\\'" . yatex-mode)
         ("\\.ltx\\'" . yatex-mode))
  :defer t
  :config
  (setq YaTeX-kanji-code 4) ; 1 => SJIS, 2 => JIS, 3 => EUC, 4 => UTF8
  (setq YaTeX-use-AMS-LaTeX t)
  (setq tex-command "latexmk"))

YaTeX そのものの使い方は,例えばクイックリファレンスなどを参照してください. 現在の設定ではクイックリファレンスでの [prefix] が C-c C- となっていることに注意してください. ただし,領域を () でくくるためのコマンド等は C-c C-) でなく C-c ) のままです.

RefTeX との連携

LaTeX の相互参照 (\ref) や文献の引用 (\cite) などの支援環境が RefTeX です. 特に BibTeX 利用時の reftex-citation (C-c [) が非常に便利です. ラベルの相互参照については YaTeX のセクション型補完 (C-c C-s SPC) でもできます.

YaTeX と RefTeX ではいくつかキーバインドが衝突するので,適当に処理する必要があります. たとえば C-c ) などのキーが衝突します.

キーバインドについては私は次の表のように割り当てています.

キー 操作
C-c = アウトラインをみる
C-c ( \ref の挿入
C-c [ \cite の挿入

LaTeX の相互参照は非常に便利ですが,それを更に強化するパッケージがいくつかあります. 例えば私は cleveref というパッケージをよく使います. 少し古いですが「cleveref で賢く参照する」という紹介記事があります.

さて C-c ( としたときに \cref を挿入するためには次の 2 通りの方法があります:

  1. 関数 reftex-cleveref-cref を利用する.
  2. 変数 reftex-ref-style-default-list("Cleveref") に変更する.

ここでは 2 番目の方法で設定してみたいと思います.

(use-package reftex
  :ensure nil
  :hook (yatex-mode . reftex-mode)
  :bind (:map reftex-mode-map
          ("C-c )" . nil)
          ("C-c (" . reftex-reference))
  :defer t
  :custom
  (reftex-ref-style-default-list '("Cleveref") "Use cref/Cref as default"))

company-math による補完

f:id:mtino1594:20190407021325p:plain
company による補完

YaTeX には数学記号のイメージ補完がありますが,イメージ以外でも補完してほしいので company-mode を利用します. イメージ補完に関しては各自で調べてみてください.

まずは company の設定をします.

(use-package company
  :ensure t
  :hook (after-init . global-company-mode))

これで起動後に company-mode が有効になります. M-nM-p で補完候補選択し, RET で決定します.

TeX/LaTeX 用の補完は company-math というパッケージが必要になります.

(use-package company-math
  :ensure t
  :demand t
  :after (company yatex)
  :config
  (push 'company-math-symbols-latex company-backends)
  (push 'company-latex-commands company-backends))

数学記号の補完は YaTeX のイメージ補完に一任する場合は company-math-symbols-latex の行を消してください.

flycheck による文法チェック

TeX Live などのディストリビューションには chktex や lacheck といった文法チェッカが同梱されています. 役に立つか否かは微妙なところですが (個人の感想です),flycheck を通してこれらの文法チェッカを利用することができます.

まず flycheck をインストールします.

(use-package flycheck
  :ensure t
  :hook (after-init . global-flycheck-mode)
  :config
  (flycheck-add-mode 'tex-chktex 'yatex-mode)
  (flycheck-add-mode 'tex-lacheck 'yatex-mode))

これで起動後に flycheck-mode が有効になります. 特定のモードでだけ有効にしたい場合は after-initXXX-mode に, global-flyehck-modeflycheck-mode にそれぞれ書き換えれば良いです.

さて,flycheck が定義する tex-chktex と lacheck はデフォルトでは YaTeX に対応していないため修正する必要があります. これは flycheck-add-mode 関数を使えば良いでしょう. :config 以降の設定です.

例えば C-c ! l (flycheck-list-errors) でエラー一覧を見ることができます.

outline-minor-mode との連携

f:id:mtino1594:20190407022745g:plain
アウトラインの折りたたみ

f:id:mtino1594:20190407022739g:plain
アウトライン構造の編集

Emacs には outline-mode というのがあります. これによって文章のアウトラインを把握したり,詳細テキストを隠したりできます. Web を検索すると outline-minor-mode と YaTeX とを組み合わせる方法がいくつか見つかります. ここでは Emacs 同梱の tex-mode.el の設定を (ほぼ) コピーします. 変数 outline-promotion-headings は後述の outline-magic のためのものですので,必要のない方は読み飛ばしてください.

tex-mode.el は GPL (GNU 一般公衆ライセンス) でライセンスされているので以下の記述を公開する場合は GPL か, その互換ライセンスでライセンスしておく必要があります1

(defvar my-YaTeX-section-alist
  '(("part" . 0)
    ("chapter" . 1)
    ("section" . 2)
    ("subsection" . 3)
    ("subsubsection" . 4)
    ("paragraph" . 5)
    ("subparagraph" . 6)))

(defvar my-YaTeX-metasection-list
  '("documentclass"
    "begin{document}" "end{document}"
    "frontmatter" "mainmatter" "appendix" "backmatter"))

(defvar my-YaTeX-outline-regexp
  (concat (regexp-quote "\\")
      (regexp-opt (append my-YaTeX-metasection-list
                  (mapcar #'car my-YaTeX-section-alist))
              t)))

(defvar my-YaTeX-outline-promotion-headings
  '("\\chapter" "\\section" "\\subsection"
    "\\subsubsection" "\\paragraph" "\\subparagraph"))

(defun my-YaTeX-outline-level ()
  (if (looking-at my-YaTeX-outline-regexp)
      (1+ (or (cdr (assoc (match-string 1) my-YaTeX-section-alist)) -1))
    1000))

(defun my-YaTeX-with-outline ()
  (outline-minor-mode 1)
  (setq-local outline-regexp my-YaTeX-outline-regexp)
  (setq-local outline-level #'my-YaTeX-outline-level)
  (setq-local outline-promotion-headings my-YaTeX-outline-promotion-headings))

これらの設定を記述した後, yatex-mode-hookmy-YaTeX-with-outline を追加します.

outline-minor-mode のキーバインドは,デフォルトだと気が狂いそうになるため適当に設定したほうが良いと思います. 次の outline-magic が有用です. しかし,outline-magic を使うと,上の画像で見るように(上下に)アウトライン構造を移動した場合,折り畳まれていたサブツリーが展開されてしまいます. これを回避するために my-outline-move-subtree-down 関数を定義し,outline-magic 読み込み後に上書きします.

(use-package outline-magic
  :ensure t
  :preface
  (defun my-outline-move-subtree-down (&optional arg)
    "Move the currrent subtree down past ARG headlines of the same level.
If the current subtree is folded, call `outline-hide-subtree' after move down."
    (interactive "p")
    (let* ((headers (or arg 1))
           (movfunc (if (> headers 0) 'outline-get-next-sibling
                      'outline-get-last-sibling))
           (ins-point (make-marker))
           (cnt (abs headers))
           (folded (save-match-data
                     (outline-end-of-heading)
                     (outline-invisible-p)))
           beg end txt)
      ;; Select the tree
      (outline-back-to-heading)
      (setq beg (point))
      (outline-end-of-subtree)
      (if (= (char-after) ?\n) (forward-char 1))
      (setq end (point))
      ;; Find insertion point, with error handling
      (goto-char beg)
      (while (> cnt 0)
        (or (funcall movfunc)
            (progn (goto-char beg)
                   (error "Cannot move past superior level")))
        (setq cnt (1- cnt)))
      (if (> headers 0)
          ;; Moving forward - still need to move over subtree
          (progn (outline-end-of-subtree)
                 (if (= (char-after) ?\n) (forward-char 1))))
      (move-marker ins-point (point))
      (setq txt (buffer-substring beg end))
      (delete-region beg end)
      (insert txt)
      (goto-char ins-point)
      (if folded (outline-hide-subtree))
      (move-marker ins-point nil)))
  :bind (:map outline-minor-mode-map
          ("C-<tab>" . outline-cycle)
          ("M-<left>" . outline-promote)
          ("M-<right>" . outline-demote)
          ("M-<up>" . outline-move-subtree-up)
          ("M-<down>" . outline-move-subtree-down))
  :demand t
  :after (outline)
  :config
  (advice-add 'outline-move-subtree-down :override #'my-outline-move-subtree-down))

これで C-<tab> でのサブツリーの折りたたみ・展開や, M-矢印 でのアウトライン構造の編集が行なえます.

最終的な設定

いろいろ書いてきましたが,以上の設定をまとめておきます. ただ設定しているだけなのでライセンスを明記する必要があるのかわかりませんが,一応 GPL of version 3 or any later versions としておきます.

Footnotes

1 Emacs に付属しているアレコレは GPL なので,標準のアレコレを前提としたプログラムは全て GPL になるような気がするのですが難しくてよくわかりません.