Context / initial need (works fine)
I wrote and use a script that generates a file and uses emacsclient
to edit it in an existing or new instance of emacs
, in a new window.
Similar to Set up Emacs on Windows to start a single instance and open files in the existing instance - Emacs Stack Exchange, it boils down to:
exec emacsclient -c -s "$SOCKETNAME" -a emacs "$GENERATEDFILENAME" <>/dev/null
It's been working for years. emacs
open a new frame, opens the requested file there. Works both if emacs already launched or not (my init files include server-start
). So far, so good.
Wish: open file and run some simple expression
That on opening the new file, the cursor, instead of landing on the first line, lands (1) at the end of the buffer or (2) at the end of some specific line.
Search before you ask
I actually use several one emacs instance per project, similar to frames - From File Manager, open file in specific instance of Emacs - Emacs Stack Exchange. So there are several emacs instances with servers that may be active at a given time.
But there's no finite, known-in-advance, list of servers/projects. So running that many servers in .xinitrc
like in emacsclient - Multiple Emacs instances each with their own server? - Emacs Stack Exchange is not an option.
Try before you ask
Interactive experiment in emacs
session, OK
Interactively,
M-x end-of-buffer
goes to the end of the buffer, and
C-u 11 move-end-of-line
move the cursor 11-1 lines down then at the end of that line.
So far, so good.
Scripted, new emacs instance: OK
Let's try first running a new instance.
emacs --eval "(find-file \"$GENERATEDFILENAME\")" --eval "(end-of-buffer)"
Line above correctly runs a new emacs instance, opens the requested file and puts cursor at end of buffer. So far so good.
Scripted, existing emacs instance through emacsclient
: OK
Let's run an emacs instance and make sure server-start
is run.
emacsclient -s "$SOCKETNAME" -e '(end-of-buffer)'
Line above outputs nil
, showing that it connects to the emacs-server
, but does not move the cursor.
emacsclient -c -s server- --eval "(find-file \"$GENERATEDFILENAME\")" --eval "(end-of-buffer)"
Line above appears to open file and put cursor at end.
Having emacsclient
do the job in both cases (emacs already running, and new emacs): NOK
Let's add -a emacs
.
emacsclient -c -s server- -a emacs --eval "(find-file \"$GENERATEDFILENAME\")" --eval "(end-of-buffer)"
Result:
- If emacs already runs with server, work okay.
- If emacs does not already run, instead of running the expressions, if opens two buffers names like the expression, as if the command was
emacs "(find-file \"$GENERATEDFILENAME\")" "(end-of-buffer)"
Bad bad bad. :-(
Showing why "no emacs running" case fails
strace
shows what happens.
When running emacs directly:
execve("/usr/bin/emacs", ["emacs", "--eval", "(find-file \"2015y12m28d-18h23m49"..., "--eval", "(end-of-buffer)"], [/* 68 vars */]) = 0
When emacsclient calls emacs (in this case GENERATEDFILENAME
is gfn.txt
).
execve("/usr/bin/emacsclient", ["emacsclient", "-c", "-s", "server-", "-a", "emacs", "--eval", "(find-file \"gfn.txt\")", "--eval", "(end-of-buffer)"], [/* 68 vars */]) = 0
execve("/usr/bin/emacs", ["--eval", "(find-file \"gfn.txt\")", "(end-of-buffer)"], [/* 68 vars */]) = 0
As you can see, emacsclient
does not call emacs
the same way when using --eval. Instead argv[0]
is --eval
which does not conform to exec tradition, and the other --eval
is skipped.
Probably emacsclient
does not assume that alternate editor is emacs or even emacs compliant.
Just in case, environment is Linux Mint 17.2 64-bit, which is base on Ubuntu 14.04.
Now what? Questions
- Should we consider
emacsclient
behavior in theexec()
call a bug? It sure has some inconsistency. - Is there a simple way to have desired behavior: run the expressions either on an existing emacs instance or a new if none exists?
emacsclient
behavior ... a bug" - Yes, see Bug#11474