EMACS-DOCUMENT

=============>集思广益

通过-daemon参数让Emacs在后台运行使之避免随X崩溃而退出

我的X server有时会停止响应,这时我不得不将之杀掉再重启. 也许是我的配置有问题,每次X server启动时,一开始分辨率总是很低(since it starts off in low-graphics mode ). 直到我手工重启图形登录管理器之后(我用的是sddm)才恢复正常. 总之,由于很难调试和修复这个问题, 我决定将注意力放在重启X时真正对我造成困扰的事情上:即,X退出时,Emacs也会跟着退出. M-x recover-session 能够很好的恢复我修改过的文件,而且一般来说我也会记得一打开Emacs就调用该命令来恢复上次的修改,但有时我会忘了这样做,则结果是我丢失了之前做出的那些更改.

考虑到我调用了 (server-start) 以便允许不同的Emacs客户端连接到同一进程. 因此每次我需要重启X时,我都会先切换到控制台,使用 emacsclient -c 连接上Emacs, 然后使用 M-x save-buffers-kill-emacs 来关闭Emacs. 但是我依然需要在重启X后重启Emacs.

使用 emacs --daemon 可以将Emacs作为后台进程运行,然后使用 emacsclient -c 连接上它. 然而,当我这么操作时,emacsclient frame并未应用我设置的主题. 需要为 after-make-frame-functions 变量添加下面函数才能修复这个问题:

(defun my/setup-color-theme ()
  (interactive)
  (color-theme-solarized-dark)
  (set-face-foreground 'secondary-selection "darkblue")
  (set-face-background 'secondary-selection "lightblue")
  (set-face-background 'font-lock-doc-face "black")
  (set-face-foreground 'font-lock-doc-face "wheat")
  (set-face-background 'font-lock-string-face "black")
  (set-face-foreground 'org-todo "green")
  (set-face-background 'org-todo "black"))
(add-hook 'after-make-frame-functions
          (lambda (frame)
            (select-frame frame)
            (my/setup-color-theme)))

我对 emacs --daemonemacsclient -c 这种方式很满意,因此我决定更进一步,让它在我开启电脑时就自动运行. 我试过使用 https://www.emacswiki.org/emacs/EmacsAsDaemon 中的init脚本. 但是由于我的Linux版本使用的是systemd,因此启动该init脚本会导致一个"缺少service文件"的错误信息. 所以我删除了这个init脚本然后创建了自己的脚本作为代替 ~/.config/systemd/user/emacs.service :

[Unit]
Description=Emacs: the extensible, self-documenting text editor

[Service]
Type=forking
ExecStart=/usr/local/bin/emacs --daemon
ExecStop=/usr/local/bin/emacsclient --eval "(progn (setq kill-emacs-hook 'nil) (kill-emacs))"
Restart=always
TimeoutStartSec=0

[Install]
WantedBy=default.target

接着我用自己的一般用户账号来运行下面这些命令:

systemctl --user enable emacs
systemctl --user start emacs

再然后,我将 ~/.xsession 中的 emacs 修改为 emacsclient -c, 这样新产生的X session会连接上已有的session而不是重新创建一个新session. 这样一来,每次我重启电脑时,Emacs都会以我用户的权限启动,当我启动X时,都会有一个emacsclient连接上这个Emacs.

然而,我发现,重启X依然会倒使Emacs daemon崩溃掉. 这个bug在 emacs --daemon 中有相关警告,它可能跟GTK有关. 我使用 ./configure --with-x-toolkit=lucid; make; make install 重新编译Emacs后,似乎就没什么问题了; 我可以随意重启X而不会影响Emacs了. 而且这样还带来一个好处: 由于Emacs是在我启动计算机时进行的初始化,而我所需要作的仅仅是连接上那个进程而已,因此当我登录用户后,给人的感觉Emacs启动真的很快.

最后一点: 我注意到TRAMP无法找到我的SSH keyring,因此当我用Org Babel运行远程服务器上的代码(就像下面这段代码一样)时,TRAMP会卡住等待我输入passphrass:

#+begin_src sh :dir [email protected]:~
perl library-new.pl Business
#+end_src

由于我的SSH socket看起来就像 /tmp/ssh-BLAHBLAHBLAH/agent.PROCESSID 一样, EmacsWiki中所描述的SSH_AUTH_SOCK设置方法(Environment=SSH_AUTH_SOCK=%t/keyring/ssh)不适用于我. 好在 https://github.com/nhoffman/.emacs.d/blob/master/init.org 中的脚本适用于我.

(defun my/ssh-refresh ()
  "Reset the environment variable SSH_AUTH_SOCK"
  (interactive)
  (let (ssh-auth-sock-old (getenv "SSH_AUTH_SOCK"))
    (setenv "SSH_AUTH_SOCK"
            (car (split-string
                  (shell-command-to-string
                   "ls -t $(find /tmp/ssh-* -user $USER -name 'agent.*' 2> /dev/null)"))))
    (message
     (format "SSH_AUTH_SOCK %s --> %s"
             ssh-auth-sock-old (getenv "SSH_AUTH_SOCK")))))
(my/ssh-refresh)

另外, emacs --daemon 并不会使用我在KDE中配置的默认浏览器. 当我打开Org mode中的URL链接时会打开一个新的Chromium进程,而不是使用Google Chrome浏览器. 我通过将 browse-url-browser-function 的值从 browse-url-default-browser 改为 browse-url-generic 从而解决这个问题:

(setq browse-url-generic-program "google-chrome")
(setq browse-url-browser-function 'browse-url-generic)

让我们来看看这样设置后的效果如何吧!