14

How can I make emacsclient -a '' -n create a new frame only if there isn't one already?

The problem with the -c flag is that it creates a new frame every time. The problem without it is that if there is no frame open it will open in the command line.

If I can check if there is an open Emacs frame from the shell, I can call with or without -c depending on that to get the behavior I want. I tried:

$ emacsclient -a '' --eval '(frames-on-display-list)'
(#<frame F1 0xba2740>)

I always get the same result.

I could use temporary files or pgrep, but those approaches are very error prone.

This is similar to this question, but it is not a duplicate, since the OP there was satisfied with having to have a frame open before calling emacsclient.

1

2 Answers 2

6

I ended up making this script based on this

#!/bin/bash -e

if [[ "$DISPLAY" ]]; then
        frame=`emacsclient -a '' -e "(member \"$DISPLAY\" (mapcar 'terminal-name (frames-on-display-list)))" 2>/dev/null`
        [[ "$frame" == "nil" ]] && opts='-c' # if there is no frame open create one
        [[ "${@/#-nw/}" == "$@" ]] && opts="$opts -n" # don't wait unless we've asked to run in a terminal
else
        opts='-nw'
fi

exec emacsclient -a '' $opts "$@"

If there is no display it opens with -nw. If $DISPLAY is set it looks for frames in that display to see if it needs to make a new one.

Edit: I've modified it so that you can manually specify -nw if you want to open in a terminal even if there is a display.

2
  • 1
    Minor nitpick: $@ should be quoted.
    – dshepherd
    Jun 4, 2015 at 18:32
  • I asked this question today, only later realizing this was asked and answered here. I came up with an answer based on your answer here - in case you're interested: emacs.stackexchange.com/a/72377/38372. It seems 7 years after the fact, this is still a problem that has no baked-in solution.
    – Lockszmith
    Jun 29, 2022 at 4:22
0

You can use:

emacsclient -s server_name -e '(+ 1 0)' >/dev/null 2>&1

to check if the Emacs server "server_name" is already running. If the command returns exit code 0, it is running. If so, just use the emacsclient command:

emacsclient -s server_name -n file_name.txt

If it is not running, you can open a new Emacs server with for example:

emacs --eval '(setq server-name "server_name")' --eval '(server-start)' file_name.txt &
9
  • But that way once you close the shell you'll kill the server, right? The emacsclient -a '' starts emacs --daemon if necessary, which persists even if you close the shell.
    – spelufo
    Jun 4, 2015 at 15:18
  • @spelufo The server is not killed by killing the shell. Note the & at the end of the command; it means to run the server as a background process.. Jun 4, 2015 at 15:56
  • Which forks it to the background of the current shell. It is not killed when you get back your shell, but it IS killed when you close that shell completely (C-d).
    – spelufo
    Jun 4, 2015 at 16:09
  • The daemon keeps running even if you close all your terminals. It would only keep on running if server-start starts the server as daemon process. What do you get if you start emacs that way and then close all emacs and terminals, then open a new terminal and run pgrep emacs?
    – spelufo
    Jun 4, 2015 at 16:10
  • @spelufo Actually it is still running after C-d. I tried this now using gnome-terminal on Ubuntu 14.10.. I think your are referring to a running instance after closing all Emacs frames? Then, that would require a daemon process yes.. Jun 4, 2015 at 16:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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