Running Emacs as a Server (Emacs Reboot #15)

Unlike more lightweight editors, it doesn’t really make sense to run a new instance of Emacs whenever editing a file. Emacs is at its best when managing many buffers, frames, and windows from a single master process. That way you can easily copy and paste betweem buffers, search across buffers, pull auto-completions from all open buffers, and much more. Not to mention that a fully configured Emacs often takes a few seconds to startup, something you don’t want to wait for every time you open a file.

To ensure I run Emacs as a single central process, I create a new shell script for starting Emacs.

#!/bin/sh
exec /usr/bin/env emacsclient -c -a "" $*

I save this script as /usr/local/bin/ec and make it executable with chmod +x /usr/local/bin/ec.

There’s a lot going on in this script:

  • #!/bin/sh says to execute the file as a shell script.
  • exec says to replace the shell process with what comes next, instead of creating a child process.
  • /usr/bin/env emacsclient says to search the current environment, specifically the PATH variable, for the command emacsclient.
  • emacsclient is part of the Emacs distribution. It communicates with a running Emacs server process to tell it to open new buffers or execute arbitrary ELisp code.
  • -c tells emacsclient to open a new window using the running Emacs server process.
  • -a tells emacsclient what command to use as an alternate if it can’t find a running Emacs server process. Giving it the empty string (“”) as an argument is a special flag which means “start a new Emacs process as a daemon in the background, and then try again to connect”.
  • $* passes any command-line arguments supplied to ec to the emacsclient executable.

Now I can just type ec FILENAME to open a file in a new Emacs window. If Emacs is already running, the window will pop open immediately. If it isn’t, a new Emacs server process is started and daemonized, and then the window pops open. The Emacs process that is started is a true daemon, so even if I close all Emacs windows or close the terminal from which I started it, it will still be running in the background, waiting for emacsclient to tell it to do something.

After sending its message to the Emacs server, the call to ec will pause until I signal I’m done editing the file using C-x # in the new window. Only then will the emacsclient process return control to the terminal. This behavior works well with programs like Git, which sometimes open an editor in order to get feedback from the user. These programs wait for the exiting of the editor process to signal that the user has finished making edits. I can set my EDITOR environment variable to ec, and it will play well with Git and other utilities.

If I just want to open a file in a new window and immediately get back to what I was doing in the terminal, I can call ec like this:

ec -n FILENAME

The -n flag tells emacsclient not to wait for the associated window to be closed with C-x #, but to exit immediately instead. Remember, it’s just the emacsclient process that exits, not the Emacs process itself.

One last thing: I’m running emacs as a daemon process in a graphical desktop environment. There are two keybindings which just don’t serve much purpose in this context: killing Emacs (I don’t want to do that often enough to warrant a keybinding), and minimizing a window (my window manager has its own keys for that). It just so happens that the default keybindings for these actions are close enough to C-x C-s (save-buffer) that I accidentally hit them way too often, so it’s high time I got rid of them.

I edit my keybindings file to unbind both:

(global-unset-key (kbd "C-x C-c")) 
(global-unset-key (kbd "C-x C-z"))

And that’s it for today.

[boilerplate bypath=”emacs-reboot”]

10 comments

  1. @avdi:disqus  thanks for this great tipI have one doubt, in my .emacs I am setting my font to Inconsolota. While running emacs as daemon I am getting this error
    error: Font not available, #Have you faced this issue? Can you suggest me any workaround?I googled about it couldn’t get any plausible solution.Thanks

  2. If you have file names with spaces in then you would be better with $@ rather than $*. $@ passes them through without expanding them if my memory serves.

    I’ve also found that a simple alias ec works for me without having to bother with the exec:

    alias ec=’emacsclient -n’

    1. I use a shell script because it makes it easier to integrate with other tools. Exporting EDITOR=/usr/local/bin/ec always works, I don’t have to worry about it failing because git (or whatever) executed the command “raw” instead of inside a shell session.

  3. I’m curious, then, do you use eshell or something from within emacs, or do you jump back and forth to a terminal window?

    1. I don’t use eshell that much, more often shell-mode. And I do a lot from external shells as well. I have a global quake-style pop-up terminal configured on my machines that I use quite a bit.

  4. Thanks for this Avdi! I’ve been using the structure you set up over the course of your reboot posts to set up my own Emacs24 configuration (tabolario/dotfiles on GitHub). Awesome stuff.

Leave a Reply to Avdi Grimm Cancel reply

Your email address will not be published. Required fields are marked *