Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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.

share|improve this question
    
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 '13 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 '13 at 18:20
    
Here is a complex method of controlling how buffers / frames are arranged when opening a file from Finder -- organize buffers by frames: stackoverflow.com/questions/18346785/… To keep everything in just one frame, @Lauri Ranta has provided the solution. See also an implementation of frame-bufs and tabbar: github.com/lawlist/tabbar-lawlist –  lawlist Dec 7 '13 at 18:25
    
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 '13 at 18:37

2 Answers 2

up vote 6 down vote accepted

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.

share|improve this answer

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
share|improve this answer
    
Thank you for the post -- I've spent a few hours tonight trying to figure out how to pass a second variable to a do shell script -- greatly appreciated! –  lawlist Dec 8 '13 at 5:17

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.