Emacs Server 启动方式探讨

发布: 2022-05-22   上次更新: 2022-05-29   标签: emacsclient

文章目录

在 Unix-like 的操作系统中,可以通过设置 EDITOR 环境变量来配置命令行工具(比如 git commit)默认的文本编辑器,比如:

1
2
3
export EDITOR=vim
# or
export EDITOR=emacs

通过这种方式,每一次都会新创建一个编辑器实例,对于 Vim 这种轻量级的编辑器还好,但对于 Emacs 这种十八般武艺样样精通的瑞士军刀来说就有些重了,理想状态是把 Emacs 作为一个类似浏览器的常驻进程,需要的时候 new 一个 frame/window 就好了,这时就用到了 Emacs Server 模式

顾名思义,Server 模式只需要启动一次,后续使用时通过 emacsclient 进行连接即可。一般来说,在配置文件中添加如下命令即可:

1
2
(unless (server-running-p)
 (server-start))

或者可以通过在命令行执行 emacs --daemon ,它会在加载完用户配置后,自动调用 server-start ,区别于前者,这种方式重复调用时会报错:

1
2
3
4
5
Starting Emacs daemon.
Unable to start the daemon.
Another instance of Emacs is running the server, either as daemon or interactively.
You can use emacsclient to connect to that Emacs process.
Error: server did not start correctly

笔者经过一番探索,发现其实可以直接通过 emacsclient 来直接启动 server 模式,命令如下:

1
emacsclient -a "" -c -n "$@"

通过把上面的命令封装成 shell 脚本或做成 alias(比如 e ),可以很方便的在命令行调用,比如 e ~/.bashrc ,比 vim 还方便。

stdin

在 Vim 中可以用 vim - 读取标准输入的内容,比如

1
echo 123 | vim -

很遗憾,默认 emacs/emacsclient 命令是不支持这种方式的,但可以通过间接的方式实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# cat ~/bin/e
function _emacsclient
{
  emacsclient -a "" -c -n "$@"
}

function main
{
  # If the argument is - then write stdin to a tempfile and open the
  # tempfile.
  if [[ $# -ge 1 ]] && [[ "$1" == - ]]; then
    tempfile="$(mktemp -t emacs-stdin-$USER.XXXXXXX)"
    cat - > "$tempfile"
    _emacsclient --eval "(find-file \"$tempfile\")" \
              --eval '(set-visited-file-name nil)' \
              --eval '(rename-buffer "*stdin*" t))'
  else
    _emacsclient "$@"
  fi
}

main "$@"

上述脚本通过重定向到一个临时文件的方式来解决,这样 emacsclient 就能够像 Vim 一样读取 stdin 了。

环境变量

通过在命令行启动 Emacs 还有一个额外的好处是:自动继承当前 Shell 中的所有环境变量,这样就不需要 exec-path-from-shell 这类插件了。

参考



收听方式

反馈