Macos – Basic setup of Emacs server under OSX

emacsmacmacos

I recently bought my first Mac in a decade and am in the process of configuring it. I'm an Emacs user and have determined I want just regular Emacs not Aquamacs so that I can use my existing configuration from other operating systems. I've tried following a lot of how-tos I've found online (like this one, this one and this one from the site from which I downloaded Emacs), and have tried combining the pieces any number of ways, but have never gotten things into a state even approaching what I'm used to/hoping for:

  1. An Emacs daemon starts running either at startup or as soon as I need it; either is fine. Any new Emacs frames are backed by the same server.
  2. When I open a text file from the Finder the file opens in Emacs, in an existing graphical frame if possible.
  3. If I run Emacs.app, the system reuses the emacs daemon that is running in the background instead of starting a new instance and opening a new window on it. (hat tip)
  4. When I run Emacs from a terminal the terminal goes about its business without waiting for me to finish with Emacs (unless I use '-nw')
  5. AFAIK at no point during the operations described above should Emacs end up in a state ("server-edit mode?") where it's waiting for me to type C-x #, although I don't have a deep understanding of this one.
  6. (I would regard this as a bonus) There is some way for me to invoke Emacs from a terminal so that Emacs reuses an existing frame if possible.

How could I configure Emacs to behave like this?

I'm particularly perplexed by getting the Finder to open things in Emacs that way I want (#2), since the guides I've found generally create a number of aliases, Applescripts, bash scripts, etc. and I'm not sure which I want to tell the Finder to use to open text files.

Thanks!

A. @lawlist asks, "Is a new frame being opened by default when you open a new file from the terminal even though there is an existing frame?" The answer is that if I start a server at startup as described here, open a frame, and then open a file by typing /Applications/Emacs.app/Contents/MacOS/bin/emacsclient -n <whatever>, I can get the file to open in an existing frame. If there is no frame currently open I have to use "-nc" or when I try to open a file nothing happens.

B. @lawlist asks, "Do you want the daemon running on login, or would it be sufficient to load Emacs manually after the login?" Running manually would be fine.

Best Answer

To make Emacs.app open files in an existing frame instead of a new frame, add (setq ns-pop-up-frames nil) to a configuration file like ~/.emacs.

You can open a file from a terminal with open -a emacs file or emacsclient -n file. If Emacs.app is not open but there is an Emacs --daemon process, for some reason emacsclient -n file doesn't work but emacsclient -nc file does.

Make sure you use the emacsclient binary included with the version of Emacs you use, like /Applications/Emacs.app/Contents/MacOS/bin/emacsclient, or /usr/local/bin/emacsclient if you installed Emacs with Homebrew.

To start an Emacs server at login, for example save this plist as ~/Library/LaunchAgents/my.emacsdaemon.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>my.emacsdaemon</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Applications/Emacs.app/Contents/MacOS/Emacs</string>
    <string>--daemon</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <true/> <!-- run the program again if it terminates -->
</dict>
</plist>

The plist is loaded automatically the next time you login, but you can load it immediately by running launchctl load ~/Library/LaunchAgents/my.emacsdaemon.plist.

Edit: I still don't know why people are associating file types with an AppleScript application instead of just Emacs.app. The script in kuzzooroo's answer could also be written as a shell script though:

macos=/Applications/Emacs.app/Contents/MacOS
if pgrep -qf 'Emacs.*--daemon'; then
  [[ $($macos/bin/emacsclient -e '(<= 2 (length (visible-frame-list)))') = t ]] && args=-nc || args=-n
else
  $macos/Emacs --daemon
  args=-nc
fi
$macos/bin/emacsclient $args "$@"
open -a /Applications/Emacs.app

You can use Platypus to save the script as an application:

I just started using Emacs, but I have a completely different setup. I made my own Emacs application by making a copy of iTerm.app, changing the CFBundleIdentifier in the Info.plist so that the application uses a different preference file, and setting the default command to /usr/local/bin/emacs. I have added (server-start) to ~/.emacs and I open the custom Emacs application at login. I used Platypus to create an application that runs emacsclient -n "$@";open -b my.emacs and I made it the default application for text files.