9

I start emacs server using

emacs --daemon

then open files using

emacsclient filename.ext

but the first file has to be opened using

emacsclient -c filename.ext

in order to create a new frame which can be later used by subsequent files without using -c command line flag for emacsclient.

I want to automate this. "if there is no emacs frame, emacsclient should create a frame else it should use the current frame". How can it be done?

  • When I do man emacsclient it doesn't tell me about a -c option. Do you know what versions exhibit this behavior? – dmckee Nov 16 '11 at 16:19
  • @dmckee emacsclient -c is new to the much improved emacsclient in Emacs 23. – Gilles Nov 17 '11 at 1:08
9

This is like dimitri's solution, but it handles the case when emacs was launched as emacs --daemon. emacs --daemon makes a hidden window that causes xprop to give a false positive when checking for an existing window.

#!/bin/bash

emacsclient -n -e "(if (> (length (frame-list)) 1) 't)" | grep -q t
if [ "$?" = "1" ]; then
    emacsclient -c -n -a "" "$@"
else
    emacsclient -n -a "" "$@"
fi
  • one can put this in a function nicely in ,say, .bashrc file: myemacsclient () {_here goes the code_}, so that no extra script file is required. – HongboZhu Feb 26 at 12:12
  • 1
    perhaps use grep -q t to shut up grep. – HongboZhu Feb 26 at 12:19
7

You can first create a frame if there isn't one already, then open the file in a now existing frame. Here's a snippet that creates a frame on the initial display if there isn't any frame now opened on a window display. You may wish to tweak this in a number of ways, such as checking whether there is already a frame on the display with x-display-list. You need (require 'cl) in your `.emacs. This may require some adaptation to work on Windows or Aqua.

emacsclient -e '(unless (find-if (lambda (f)
                                   (let ((p (frame-parameters f)))
                                     (assq '\''window-system p)))
                                 (frame-list))
                  (make-frame-on-display (getenv "DISPLAY")))'
emacsclient filename.ext
  • This is what I'm after, but I'm getting the error Symbol’s function definition is void: find-if. Any idea why? (Running GNU Emacs 25.2.2.) – aioobe Dec 26 '18 at 10:30
  • @aioobe Do you have (require 'cl) in your init file? If not add it. – Gilles Dec 26 '18 at 10:45
7

Here is the emacs-client.sh script I use under Linux to do exactly what you ask for:

#!/bin/sh

xprop -name emacs >/dev/null 2>/dev/null
if [ "$?" = "1" ]; then
    emacsclient -c -n -a "" "$@"
else
    emacsclient -n -a "" "$@"
fi
  • This answer needs more upvotes! – Arash Apr 17 '14 at 21:34
  • This seems to get confused when you kill the emacs frame. At that point the emacs server is still running and the xprop line returns 0 so it won't open up a new frame after the first time. Am I missing something? – demented hedgehog Sep 19 '15 at 2:17
  • 1
    Jim Hunziker's solution does not seem to have the same problem. – demented hedgehog Sep 19 '15 at 2:18
2

I think adding Gilles' function to server-switch-hook might do what you want. Unfortunately, I can't seem to get emacs --daemon working to test it.

(add-hook 'server-switch-hook
          (lambda ()
            (unless (find-if (lambda (f)
                               (let ((p (frame-parameters f)))
                                 (assq 'window-system p)))
                             (frame-list))
              (make-frame-on-display (getenv "DISPLAY")))))
2

My solution is to force the creation of a frame after starting the daemon:

function em() {
  emacs --bg-daemon --display=:0
  # Forces emacs to notice I'm using X as well.
  emacsclient --create-frame --display=:0 --no-wait
}

and then I never have to use --create-frame.

0

On OSX I just define this function (similar to Jim Hunziker's approach)

emacs () { pgrep -xiq emacs && emacsclient -n $@ || emacsclient -n -c --alternate-editor="" $@; }
0

Jim Hunziker's answer does not quite work for me (in some situations frame-list returns two items even though there is no X frame). Assuming you only use one DISPLAY, the following works:

#!/bin/bash

emacsclient -n -e "(null (cl-remove-if (lambda (frame) (null (display-graphic-p frame))) (frame-list)))" | grep >/dev/null nil
if [ "$?" = "1" ]; then
    emacsclient -c -n -a "" "$@"
else
    emacsclient -n -a "" "$@"
fi
0

Yet another version that also works in tty/console mode:

#!/bin/bash                                                                                                                          

emacsclient -n -e "(if (> (length (frame-list)) 1) 't)" | grep t                                                                     
if [ "$?" = "1" ]; then                                                                                                              
    if [ "$DISPLAY" = "" ]; then                                                                                                     
        emacsclient -c -a "" "$@"                                                                                                    
    else                                                                                                                             
        emacsclient -c -n -a "" "$@"                                                                                                 
    fi                                                                                                                               
else                                                                                                                                 
    if [ "$DISPLAY" = "" ]; then                                                                                                     
        emacsclient -a "" "$@"
    else
        emacsclient -n -a "" "$@"
    fi
fi

(Based on Jim Hunzikers answer)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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