Since I became a happy user of Org Capture Chrome Extension, I needed to have the ability to properly run emacsclient.
Few words of introduction: emacsclient is a separate binary, which can connect to running Emacs instance, sharing all its resources. It starts almost instantly, which helps, if we want to use it for quick editing in a separate terminal (instead of vi). To connect to server, client requires a configuration file, which contains socket address and some additional data (for me, it is located
~/.emacs.d/server/). There could be multiple servers running, and every one of them would have its config file. Usually, the first one uses the file named
server, and subsequent ones add a number to the name.
As I wanted only one Emacs server in the system, I have configured my
init.el file as follows:
(if (not (server-running-p)) (start-server))
I was in constant trouble. Sometimes the server was working fine and clients could connect to it. When Emacs crashed (which is happening often under Windows), the server file was left in the folder, and when another instance came up, it was using a different server name.
Finally, I could put some time into investigation. It turns out that predicate
(server-running-p) is not limited to returning
nil. When another server file exists, it returns
:other. I assume it only checks the server file existence, as after crash it still returns
:other. Apparently, we need to check not only if file exists, but also if the Emacs instance it points to is active. After quick Google search, I learned about function
(server-eval-at), which allows to execute code on another Emacs instance. Given these conditions, I came up with a little switch-like construct:
(cond ((eq (server-running-p) nil) (progn (message "Starting new server.") (server-start))) ((eq (server-running-p) :other) (let ((my-status 0)) (ignore-errors (setq my-status (server-eval-at server-name (+ 1 1)))) (if (/= my-status 2) (progn (message "Killing stale socket and starting server.") (server-force-delete) (server-start)) (message "Other server works.")))) (t (message "Server already started.")))
It checks the
server-running-p and depending on its value starts new server instance, removes stale server file and spawns new server, or does nothing. Being a beginner in Elisp, I suspect this code could be written in more efficient and prettier form, but it works for now.