web analytics
Emacs Logo

Emacs to rule your (editing) world

March 17, 2014

I’m not an avid Emacs user as much as I would like to. Sure I keep my to-do list with org mode, SQL scripts, as well as the occasional lisp hacking, but right now my job revolves around coding in PHP and Java, neither of which are particularly well suited for Emacs. Java coding in particular benefits greatly from IDE support, and PHP coding is perfectly possible in Emacs, but I’ve been spoiled by PHPStorm, especially the ease of setting up XDebug. Still I always keep open an Emacs instance just in case. I’m such a fan of Emacs that I think there should be a Website called I fucking love Emacs where one could submit posts when you have one of those I fucking love Emacs moments. If you’re an emacs user you’ll know what I mean.

The one area where I always use Emacs for is JavaScript coding. Coupled with JS2 mode, JS2 refactor, JS Lint for syntax checking, Node.js as REPL and other niceties (some included, some not), Emacs is a powerhouse for JavaScript coding. I love dropping into a JS REPL and trying things quickly, I love how JS Lint warns me of style issues, and how a simple tab fixes my indentation. There’s a long list of things I love about JS coding in Emacs.

Over time I’ve been able to smooth out my Emacs experience, working around the kinks. My configuration files reflect this fact, as well as the packages I use on a daily basis. The thing about using packages in Emacs, is that they are loaded each and every time Emacs is loaded. Add a new package, and you literally add more milliseconds to Emacs startup time. You may not notice initially, but in my case starting a new Emacs instance on a cold boot takes somewhere around 4 – 6 seconds. It isn’t much, but enough to be annoying.

Any self respecting Emacs guru will tell me:

That’s what Emacs –daemon is for…

Along with some expletives and deprecating remarks about my intelligence and overall being. I tried, several times, to get Emacs as a daemon working in my setup. As most things Emacs, the server mode is very powerful but not as easy to use as you would think. Don’t get me wrong, the basics are very easy, but again as most things Emacs you’ll want to tweak a thing here and change a bit there to get it just right for you. That was certainly my case.

What I was looking for:

  • Emacs starting as a daemon when I logged in to my machine
  • A way to spawn new frames (that’s Emacs speak for new Emacs windows) that connect to the running daemon
  • The new frames shall have all the configuration options (theme, fonts, etc) specified in my config files
  • Using a frame shall be the same as using a regular Emacs session. I don’t want to re-learn any bindings
  • And last but not least, it must work across computers

Let me explain the last point: I do my work on my desktop, but when I’m away from home I take my laptop. Both are running OS X and both must have everything I need installed, configured and ready to go. The idea is whenever I’m going away I just pull the latest changes from git and that’s it. This scenario poses a challenge for Emacs configuration; ideally the same configuration would be shared across computers, but the reality is different.

Most of my Emacs configuration is the same for my desktop and my laptop, however there are subtle differences that are machine dependant: mainly the color theme and frame size. You see, I hate doing the same thing over and over again, so when my Emacs starts up I set the frame size depending on the machine I’m at: my desktop has a 27 inch Cinema Display hooked up, while my laptop (a MacBook Pro 15 inch retina) has… well a retina display. There are two other differences: theme color and line highlight. In my desktop I use a dark theme (moe-dark) but in my laptop I use a light theme (moe-light). Because of this, the line highlight must also be different: a dark color for my dark theme, and a light color for my light theme.

The Solution

Like stated before, using Emacs –daemon takes care of the startup speed. Emacs is launched as part of the login process and waits for connections. Instead of opening a new Emacs, you use emacsclient to connect a frame to the running Emacs instance. This uses no more memory than having the same Emacs session running in the background, but with the added benefit of your Emacs frame appearing instantly before your eyes. Bliss.

Read all the details in this Gist. However I had to do a few modifications of my own:

  1. I’m using Emacs installed from homebrew
  2. I need to customise each created frame depending on the machine it was opened (desktop or laptop)

If you follow the Gist steps you’ll end up with a functional daemonized Emacs. But we don’t want functional, we want just right. Thus, for the Emacs Server part I use:

do shell script "/usr/local/Cellar/emacs/HEAD/Emacs.app/Contents/MacOS/Emacs --daemon"

That’s it. No “tell Terminal” nonsense. Follow the same steps included in the Gist to start it up when you log in. Now for the interesting part: customising each frame. For the Emacs client part:

do shell script "/usr/local/Cellar/emacs/HEAD/bin/emacsclient -c -n -e '(load \"~/.emacs.d/emacs_init_minas.tirith.el\")' &"

We’re invoking emacsclient with a few options:

  • -n so the client exists immediately. Since buffers are kept in the Emacs server instance, we don’t need it to wait until all buffers are closed. Basically all your buffers will be kept open for your whole session, and the cursor will be in the same spot where you left it. Ain’t it cool?
  • -c create a new graphical frame. That is, create another window instead of reusing an existing one. Leave this out if you would like to keep a single Emacs frame all the time (which might be a good idea)
  • -e evaluate some code. This is the magic sauce. You can tell here your client which config file to use.

I have two configuration files for my two machines: emacs_init_minas.tirith.el is for my desktop, and emacs_init_galadriel.local.el for my laptop. Here’s the content of the minas.tirith.el file:

;; window size
(set-frame-size (selected-frame) 200 65)

;; set theme. Default theme is moe-light
(load-theme 'moe-dark t)

;; set highlight line for dark theme
(set-face-background 'highlight-current-line-face "gray17")

;; default font for this frame
(set-default-font "Inconsolata-13")

And that’s it. When I fire up Emacs, it starts instantly and I’m happy.