9

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.

3
  • Can you number them please, 1, 2, 3, 4, 5, 6, and maybe 7 and 8. Also, is a new frame being opened by default when you open a new file from the terminal even though there is an existing frame? I know some of the answers, but not all of them -- so numbers for the questions would be helpful. Do you want the daemon running on login, or would it be sufficient to load Emacs manually after the login?
    – lawlist
    Dec 7, 2013 at 3:46
  • @Lauri Ranta has a good answer. M-x server-start will manually start the server so that emacsclient can communicate with it. I have placed (server-start) in my init.el file instead of using a daemon at login -- however, many people prefer the daemon login option. And of course, the .emacs file would be a suitable place for (server-start).
    – lawlist
    Dec 7, 2013 at 18:20
  • With regards to opening files from Finder, I am assuming that you are far beyond the stage of needing something like this: dummies.com/how-to/content/… So, assuming that is out of the way, then you are probably going to be just fine with ns-find-file -- which is activated automatically when a file is associated with Emacs.app. My intercept file function in the links above also modifies ns-find-file if that is something that interests you. Of course, you need Emacs built --with-ns.
    – lawlist
    Dec 7, 2013 at 18:37

2 Answers 2

12

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.

0
2

Lauri's solution combined with suggestions from the comments have largely addressed my issues. I've pasted below some Applescript that I stitched together from stuff I found online. The script helps smooth out some remaining wrinkles, e.g., its behavior is a little better if there's no current Emacs frame.

EDIT: the purpose of the script is to be associated with .txt files in the Finder.

-- http://superuser.com/questions/457484/how-to-open-emacs-from-macs-finder
-- https://gist.github.com/ambethia/304964#comment-799519
on run {input}
    set filepath to quoted form of POSIX path of input
    tell application "Terminal"
        try
            -- we look for <= 2 because Emacs --daemon seems to always have an entry in visibile-frame-list even if there isn't
            set frameVisible to do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -e '(<= 2 (length (visible-frame-list)))'"
            if frameVisible is "t" then
                do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -n " & filepath
            else
                -- there is a not a visible frame, launch one
                do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -c -n " & filepath
            end if
        on error
            -- daemon is not running, start the daemon and open a frame     
            do shell script "/Applications/Emacs.app/Contents/MacOS/Emacs --daemon"
            do shell script "/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -c -n"
        end try
    end tell

    -- bring the visible frame to the front
    tell application "Emacs" to activate

    return input
end run
0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .