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.

Tyler
  • 21,719
  • 1
  • 52
  • 92
spelufo
  • 303
  • 1
  • 9
  • 1
    The same question http://superuser.com/questions/358037/emacsclient-create-a-frame-if-a-frame-does-not-exist with `elisp`, `bash` and `sh` answers. – Konstantin Morenko Jul 12 '16 at 17:41

2 Answers2

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.

spelufo
  • 303
  • 1
  • 9
  • 1
    Minor nitpick: `$@` [should be quoted](https://github.com/koalaman/shellcheck/wiki/SC2068). – dshepherd Jun 04 '15 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: https://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 '22 at 04: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 &
Håkon Hægland
  • 3,608
  • 1
  • 20
  • 51
  • 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 04 '15 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.. – Håkon Hægland Jun 04 '15 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 04 '15 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 04 '15 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.. – Håkon Hægland Jun 04 '15 at 16:16
  • That is what I mean. – spelufo Jun 04 '15 at 16:21
  • @spelufo Ok, but it is not necessary to run a daemon.. If you close the server, it will simply be reopened the next time (since you check with `emacsclient` if it is running or not, before you open a file).. – Håkon Hægland Jun 04 '15 at 16:28
  • Sure. You can also much more simply enable server mode from your `init.el`, but I rather leave it running indefinitely. I can always kill it if I need to. – spelufo Jun 04 '15 at 16:34
  • @spelufo Ok, I find it easier to just add `--eval "(setq confirm-kill-emacs 'yes-or-no-p)"` and kill the server when I close the emacs frame using `C-x C-c`.. but I have a more complicated bash command, such that I can have multiple servers running at the same time. So in order to explain why I prefer this setup, I would need some more pages :) – Håkon Hægland Jun 04 '15 at 16:39