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/shsays to execute the file as a shell script.
execsays to replace the shell process with what comes next, instead of creating a child process.
/usr/bin/env emacsclientsays to search the current environment, specifically the
PATHvariable, for the command
emacsclientis 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.
emacsclientto open a new window using the running Emacs server process.
emacsclientwhat 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
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
-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”]
@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
For the font issue this post helped
Hope someone else reading this blog will find it useful.
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’
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.
I’m curious, then, do you use eshell or something from within emacs, or do you jump back and forth to a terminal window?
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.
I used something like this for a while, then got irritated by Ruby’s caller strings not separating the line number from the file name. I’ve written up my solution to that over here: http://blackkettle.org/blog/2011/12/10/neat-emacs-trick-slash-number-1/
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.
Awesome, great to hear you’re enjoying it!
On Mar 1, 2012 5:48 PM, “Disqus”