How can I get emacs 23 working nicely in multi-tty mode on OS X?
I've added (server-start) to my .emacs, and have discovered that running /Applications/Emacs.app/Contents/MacOS/bin/emacsclient -n ~/myfile.txt will open it in my emacs.app, but it doesn't bring emacs to the front.
So, how can I get emacs.app to come to the front when I run emacsclient? (I've considered writing a function that puts the current frame to the front every time a file is opened, or maybe writing an Applescript to do a similar job that could be called at the same time as emacsclient)
Is the emacsclient within emacs.app the best one to use? I assume I'll write an alias to it if so, but it seems weird to be using that rather than something in /usr/local/bin
Has anyone got any other tips or examples of getting this working?
The AppleScript would be simple:
tell app "Emacs" to activate
I have an alias from emacs to
open -a /Applications/Emacs.app "$@"
If you are annoyed by the fact that it opens a new frame (window) for each file -- add
(setq ns-pop-up-frames nil)
to your .emacs and fixed.
Perhaps this would work, just calling raise-frame when the client attaches:
(add-hook 'server-visit-hook 'call-raise-frame)
(defun call-raise-frame ()
(raise-frame))
(It happens to be redundant on my Linux machine.)
Some of the proposed solutions suggest using 'raise-frame'. That will raise the emacs frame, but it will not give it focus. When you start emacs from a terminal window, emacs will still be beneath the terminal window because the terminal window retains the focus. I use 'select-frame-set-input-focus' to raise and give focus.
Examples:
/Applications/Emacs.app/Contents/MacOS/bin/emacsclient -n ~/myfile.txt \
--eval '(select-frame-set-input-focus (nth 0 (frame-list)))'
I prefer to run separate instance of emacs, so when I exit with "^X^C" I don't lose all windows. To accomplish this I have a shell script:
#!/bin/bash
/Applications/Emacs.app/Contents/MacOS/Emacs \
--eval '(select-frame-set-input-focus (nth 0 (frame-list)))' \
"$@"
I use something like this in my .emacs to only call server-start if the server isn't already running:
(if (file-exists-p
(concat (getenv "TMPDIR") "emacs"
(number-to-string
(user-real-uid)) "/server"))
nil (server-start))
Then a couple of changes to my .zshrc so that I can mindlessly run ec as my editor command from the shell:
# I use the Emacs package from emacsformacosx.com
alias emacs='open -a emacs'
alias emacsclient='/Applications/Emacs.app/Contents/MacOS/bin/emacsclient'
alias ec='emacsclient -a /Applications/Emacs.app/Contents/MacOS/Emacs'
export EDITOR='ec'
To expand on the answers given by Trey Jackson and the comment by Singletoned: I have the following in my .emacs file
;;;
;;; Run in server-mode so other sessions can connet
;;;
(defun call-raise-frame ()
(raise-frame))
(defun end-server-edit ()
(shell-command "osascript -e \"tell application \\\"System Events\\\" to keystroke tab using command down\""))
(add-hook 'server-visit-hook 'call-raise-frame)
(add-hook 'server-done-hook 'end-server-edit)
(server-start)
And in my shell init file I have the following aliases:
alias e='emacsclient' # edit
alias enw='emacsclient -n' #edit (no wait)
Now I can have a shell open side-by-side with my CocoaEmacs instance and use the two seamlessly together. I can call the editor "inline" with my current terminal flow by using the e alias and once I finish editing in emacs focus will be returned to the calling terminal.
I define this function in my .emacs
(defun ns-raise-emacs ()
(ns-do-applescript "tell application \"Emacs\" to activate"))
Then use this to raise the frame:
emacsclient -e '(ns-raise-emacs)'
I recommend doing it this way instead of calling osascript. It seems to respond faster (significantly faster sometimes) than using osascript.
fwiw, here's my solution:
step 1: create a script at /usr/local/bin/emacs with the following
contents:
#!/usr/bin/bash
emacsclient -c --alternate-editor='/Applications/Emacs.app/Contents/MacOS/Emacs' "$@" 2>/dev/null
step 2. make it executable via: chmod +x /usr/local/bin/emacs
step 3. in your ~/.emacs file add the following:
(server-start)
(defun ns-raise-emacs ()
(ns-do-applescript "tell application \"Emacs\" to activate"))
(ns-raise-emacs)
(add-hook 'server-visit-hook 'raise-frame)
;;(add-hook 'server-visit-hook 'ns-raise-emacs)
explanation:
If the emacs script at /usr/local/bin/emacs is invoked and there's no emacs server currently running, the emacsclient will invoke the alternate editor, which in this case is the Emacs editor (/Applications/Emacs.app/Contents/MacOS/Emacs).
In step 3, the initial call to (ns-raise-emacs) seems to be necessary for the initial Emacs window to show in front of everything else.
The (add-hook 'server-visit-hook 'raise-frame) is so that subsequent frames show up in front of everything else.
Alternatively, if you prefer that all Emacs frames show up in front of everything else each time you invoke emacs from the command line, you can uncomment the (add-hook 'server-visit-hook 'ns-raise-emacs) line.
来源:https://stackoverflow.com/questions/945709/emacs-23-os-x-multi-tty-and-emacsclient