📝

EmacsでMarkdownを書くときの折り返しをいい感じにする設定

2023/11/07に公開

EmacsでMarkdownを書くとき、画面上の行の折り返しに関していい感じの設定をしてみます。
Emacsは執筆時点での最新バージョン29.1を使っています。

何が問題?

Emacsでテキストファイルを書く際にはauto-fill機能を有効にしていました。ですが、Markdownなどの記法では勝手に改行されると困ることがあります。

例えばリンク関係。[〜](〜)の途中で勝手に改行されると都合が悪いです。
箇条書きなども途中で改行が入ると出力結果が変わってしまう。

  • 箇条書き。
    改行が入った場合。
  • 箇条書き。改行が無い場合。

ということでauto-fillは無効にするのですが、以下のような編集画面になります。truncate-linesが有効かどうかでどちらかになります。ちなみにM-x toggle-truncate-linesで切り替わります。(画像の緑の四角はカーソルです)

truncate-lines有効
truncate-lines有効
truncate-lines無効
truncate-lines無効

truncate-lines有効の場合は良さそうに見えますが、カーソルの移動が論理行単位なので編集しにくいです。具体的には、上記の例だとEmacsEにカーソルがある状態で下に1つ移動するとnではなくその下の空行に行きます。他にも論理行と表示上の物理行の違いで色々と編集しにくいです。

一方、truncate-lines無効だと長い行はカーソルを右に移動しないと見ることができず、非常に一覧性が悪いです。これも編集しにくい。

上記問題を解決するEmacs設定を調べてみました。

Emacsの設定

何はともあれ、最終的に自分の設定はこうなりました。

(use-package markdown-mode
  :mode ("\\.md\\'" . markdown-mode)
  :init
  (add-hook 'markdown-mode-hook #'turn-off-auto-fill)
  (add-hook 'markdown-mode-hook #'turn-on-visual-line-mode))

(use-package word-wrap-mode
  :hook (visual-line-mode . word-wrap-whitespace-mode)
  :config
  (add-to-list 'word-wrap-whitespace-characters ?\]))

(use-package visual-fill-column
  :hook (visual-line-mode . visual-fill-column-mode)
  :init
  (setq visual-line-fringe-indicators '(left-curly-arrow nil))
  :config
  (setq visual-fill-column-width 78))

(use-package adaptive-wrap
  :hook (visual-line-mode . adaptive-wrap-prefix-mode))

markdown-mode

まずmarkdown-modeをインストールします。

markdown-modeではauto-fillを無効にして、visual-line-modeを有効にしています。

(add-hook 'markdown-mode-hook #'turn-off-auto-fill)
(add-hook 'markdown-mode-hook #'turn-on-visual-line-mode)

visual-line-modeはEmacs標準に含まれていて、カーソル移動を物理行単位にしてくれます。

参考: Visual Line Mode (GNU Emacs Manual)

word-wrap-whitespace-mode

visual-line-modeを有効時にすると、右端の折り返しが単語単位(word-wrap)になる効果もあります。この「単語単位」というのが曲者で、スペースかタブで区切られたものを単語と認識します。つまり英語ならうまく機能しますが、日本語のように単語をスペースで区切らない言語だとうまく機能しません。特に技術系テキストのような英単語まじりの日本語になると都合が悪いです。

visual-line-mode無効
visual-line-mode無効
visual-line-mode有効
visual-line-mode有効

スペースがenglish wordsの部分にしかないため、そこで折り返されていて不自然な感じになってしまっています。

これを解決するためには、スペース、タブ以外の文字も単語区切りとして認識させるため、word-wrap-whitespace-modeを有効にします。これはEmacs標準のword-wrap-mode.elに含まれています。

visual-fill-columnとword-wrap-whitespace-mode有効
visual-fill-columnとword-wrap-whitespace-mode有効

さらにリンク表記の]も単語区切りとして認識させてみます。

(add-to-list 'word-wrap-whitespace-characters ?\])

すると以下のように[〜]の途中で切られていたのが、
word-wrap-whitespaceデフォルト設定
word-wrap-whitespace-modeデフォルト設定
以下のように]の後で切られるようになりました。
word-wrap-whitespace追加設定
word-wrap-whitespace-mode追加設定

visual-fill-column

visual-line-modeだと折り返しはウィンドウの右端になりますが、それを任意のカラム位置にするのがvisual-fill-columnです。これもインストールします。

visual-fill-column-widthを設定するとそのカラム位置で折り返してくれます。自分は78に設定しました。

(setq visual-fill-column-width 78)

あとfringe部分の表示設定もしていて、折り返された行のfringeに矢印を表示するかどうかがvisual-line-fringe-indicatorsで設定できます。自分は左側のみに表示させています。

(setq visual-line-fringe-indicators '(left-curly-arrow nil))

左右両方に表示させる場合は以下です。

(setq visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow))

adaptive-wrap

adaptive-wrapadaptive-wrap-prefix-modeを使うと、リストなどで折り返しがあった場合にインデントを付けてくれます。これもインストールします。

adaptive-wrap-prefix-mode無効
adaptive-wrap-prefix-mode無効
adaptive-wrap-prefix-mode有効
adaptive-wrap-prefix-mode有効

表示上はインデントが付いて行始まりにスペースがあるように見えますが、実際のテキストファイル上にはスペース等は入りません。リストで折り返しが入っても見やすくなります。

禁則処理

日本語の禁則処理まわりを考慮する場合は、上記設定とは別に以下を設定に書いておくと良いかもしれません。(他の設定等で自動で読み込まれているなら、明示的に書かなくても大丈夫)

(require 'kinsoku)

まとめ

Zennで記事を書くときはMarkdown記法で書くわけですが、Emacsで書こうとしたらちょっと不便だったので、良い設定ができないかと調べた結果です。Emacs 29.1に新しく入ったword-wrap-whitespace-modeを見つけたのが一番の収穫かもしれません。
まだ一部で微妙なところもありますが、とりあえず常用できる設定になったのではないかと思います。

Discussion