はじめに
これはEmacs Advent Calendar 2024の18日目の記事です。そしてこれは以前書いた日記の改稿です。
最近は業務でもプライベートでも端末内で生活している時間が長く、特に業務ではsshなのでセッション数を増やすのも面倒で可能な限りなんでもEmacs上で済ませたいと思っています。なので、eshellを導入してEmacs内でコンパイルもバージョン管理も済ませるようにしたのですが、これが端末としての互換性はかなりきびしくてlessがまともに動かなく、しょうがないので環境変数PAGERにcatを設定して逃げていました。
それにしてもあまり快適ではないのでもっとよい方法がないのかと思っていたのですが、Emacs上でテキストファイル内のエスケープシーケンスを色付け表示する方法があるということで、それを使ってページャーとして動作するモードを作成すればよいのではないかと思って実験しました。
その後ずっと実用していますがすでに手放せなくなっていますので、この機会にご紹介したいと思います。
pager-modeの作成
まずは.emacsに以下のように追加してpager-modeを作ります。
(define-derived-mode pager-mode fundamental-mode
"Pager"
"Pager mode to view texts with ANSI colors."
(ansi-color-apply-on-region (point-min) (point-max))
(set-buffer-modified-p nil)
(setq buffer-read-only t)
(define-key pager-mode-map (kbd "SPC") 'scroll-up-command)
(define-key pager-mode-map "b" 'scroll-down-command)
(define-key pager-mode-map "q" 'kill-this-buffer))
(add-to-list 'auto-mode-alist '("\\.pager\\'" . pager-mode))
拡張子.pagerで起動するように、ANSIカラーを適用するように、バッファ削除時に確認されないように、そしてリードオンリーに設定します。キーバインドはスペース、B、Qくらいあればよいでしょう。
emacspagerの作成
続いてページャーコマンドを作ります。ここではPythonで書いてemacspagerという名前でパスが通っている場所に置きました。
#! /usr/bin/python3
import os
import sys
import tempfile
if __name__ == "__main__":
text = ""
if len(sys.argv) == 1:
done = False
while not done:
try:
text += input() + "\n"
except EOFError:
done = True
else:
with open(sys.argv[1]) as file:
text = file.read()
fd, file_name = tempfile.mkstemp(".pager", "")
with os.fdopen(fd, "w") as file:
file.write(text)
file.close()
os.system("emacsclient -n " + file_name)
やっていることは引数がなければ標準入力を、引数があればそのファイルの内容を一時ファイルに出力し、emacsclientを起動するだけです。
環境変数PAGERとEmacsサーバーの設定
最後に.emacsに環境変数PAGERを設定し、emacspagerがページャーとして使用されるようにします。emacsclientを使用するのでEmacsサーバーも起動する必要があります。
(server-start)
(setenv "PAGER" "emacspager")
その後eshell内でページャーを使用するコマンドを実行すると、その内容がEmacsのバッファ内に開かれるようになります。非常に便利ですがまあエラーハンドリングや大きい文書表示時のパフォーマンスなどいろいろ課題はあります... そのへんは追ってなんとかしたいところです。