Emacsclient As Pager

随意使用,希望有人分享完美的、不依靠临时文件的版本。

emacs_pager() {
    content="$(cat)"
    temp="$(mktemp)"
    echo -e "$content" > $temp
    emacsclient -e "\
(let* ((name (concat \"*pager: \" \"$(pwd)\"  \"*\"))
       (buffer (find-file-read-only \"$temp\"))
       (inhibit-read-only t))
  (with-current-buffer buffer
    (ansi-color-apply-on-region (point-min) (point-max))
    (set-buffer-modified-p nil)
    (rename-buffer name t)
    (delete-file \"$temp\")
    (switch-to-buffer buffer)))
"
}
3 个赞

听说过 eless 吗?

孤陋寡闻了。不过 eless 和这个还是有区别。首先 eless 没有必要用 bash 实现, POSIX Shell 完全可以。然后就是,我这个调用的是 emacsclient ,给在 emacs 里面的终端用最方便,集成度最高。

这是别人的epipe, 可以参考

#!/bin/bash
set -e

cleanup() {
    trap - TERM INT EXIT
    if [[ -O "$FIFO" ]]; then
        rm -f "$FIFO" || :
    fi
    if [[ -O "$DIR" ]]; then
        rmdir "$DIR" || :
    fi
}
trap "cleanup" TERM INT EXIT

SOCKET="${XDG_RUNTIME_DIR:-/run/user/$UID}/emacs/server"
# SOCKET="/tmp/emacs$UID/server"

# Create a named pipe in /dev/shm
DIR=$(mktemp -d "/dev/shm/epipe-$$.XXXXXXXXXX")
FIFO="$DIR/fifo"
mkfifo -m 0600 "$DIR/fifo"

# Ask emacs to read from the names socket.
emacsclient -s "$SOCKET" -n --eval "(pager-read-pipe \"$FIFO\")" >/dev/null <&-

exec 1>"$FIFO"
cleanup # Cleanup early. Nobody needs the paths now...
cat

虽然我知道临时文件和 pipe 不一样,不过我的意思是最好不要有显式的文件创建操作。

不用文件,直接用 --eval

没创建窗口会立即退出吧?


不用临时文件的版本(详见 twlz0ne/6b7175a@gist):

emacs -Q -nw --eval "\
(progn
  (setq inhibit-startup-screen t)
  (add-hook 'emacs-startup-hook
            (lambda ()
              (if (string= \"${MAN_PAGE}\" \"\")
                  (progn
                    (require 'ansi-color)
                    (ansi-color-apply-on-region (point-min) (point-max))
                    (fundamental-mode))
                (require 'woman)
                (save-excursion
                  (if (re-search-forward \"^[.']\" 1000 t)
                      (woman-decode-buffer)
                    (woman-man-buffer)))
                (woman-mode))
              (read-only-mode 1))))" --insert <(cat) </dev/tty

配置可以完善一些然后 dump 出来加速。

效果如下:

  1. git log --oneline

Screenshot_2021-06-06_at_8.44.09_PM_emacs-as-pager-2

  1. man git-log

Screenshot_2021-06-06_at_8.41.02_PM_emacs-as-pager-1

加了一个环境变量 MAN_PAGE 来区分以上两种情况,不知有没有更好的方法。

2 个赞

可惜 client 似乎没法这么用。另外我本来是想把一个 shell 函数当 pager 的,但其实除了 shell 命令行,别的应用没法这么用,除非把它独立成脚本。

最终参靠了你的版本。不过 insert 是通过 emacsclient -e "(insert "'"$(sed 's/\\/\\\\/g' | sed 's/"/\\"/g')"'")" 。有点不可读,不过参考了 emacs 字符串的 syntax 。