Yesterday’s Thoughts

August 15, 2005

Emacs and emacsclient

I use emacs as my preferred text editor. In general I prefer text files to more complicated or proprietary formats such as Word .doc files. Text is easy to use. Text files are small. Text can be processed with standard tools such as grep, diff, sed and awk.

In that light emacs is a somewhat heavy tool, but I have become accustomed to it and there are frequently tasks that emacs can do, that would be much harder with any other set of tools, such as cutting a particular rectangle out of the middle of a text file, or the kind of processing that is possible with a particular query-replace-regexp or keyboard macro. Moore’s Law has solved the only issues that I ever had with emacs, I can now run it on every computer that I own. In any case, I have been using emacs off and on for almost 20 years as my programming environment. I keep trying other tools and environments, but I always end up returning to emacs.

The one set of infelicities about using emacs that were still causing me to occasionally drop into vi(m) were that I hadn’t managed to configure emacs to start up correctly in all of the different situations in which I needed to use it. I use emacs in a terminal window when connected to my Linux server. Sometimes that window is direct ssh, so it supports X-forwarding, to the X-server that I may have running on my local computer. (I use X-win32.) Sometimes I am running emacs on my local computer, editing both local and remote files. And most problematically sometimes I am deep in some other tool and relying on the value of my shell EDITOR variable to determine what editor to start up.

The issue is that each of these situations has two alternatives: when I have already started emacs, and when I haven’t. When I have already started emacs, I want to use that existing emacs so that I can take advantage of being able to access the other windows that I have open, refer to a man page, etc. There is a tool to do that, if you start the first instance of emacs that you open as a server, then later instances can connect to that server with the emacsclient command. I use gnuclient on Windows which solves these problems there, but I still have problems when on Linux.

The problem is that if I defined my EDITOR as emacsclient, then the command would fail half the time because I hadn’t first started the server. If I defined the EDITOR as emacs (the server) then the command failed the other half of the time.

Christoph Pfisterer posted about 85% of the solution to my problems here. He wrote a set of scripts to test for the definition of the DISPLAY variable, the universal indicator for the presence of X, and the file that the emacs server uses, and launching plain terminal emacs, emacs server, or emacsclient. In the last two cases, the script launches to X and then returns to the command line immediately.

A second script, ew, will not return immediately in the last two cases. This version is for the case where the script is called from a tool like less or crontab, which wants to get the return from the script.

Actually Christoph’s version of the script will not return normally until the emacs exits in the case where there is not currently a server running. I made a simple modification to his code to handle this case. Here is the full script, tested under bash on Linux.

!/bin/sh EMACS=emacs EMACSCLIENT=emacsclient if [ -f $HOME/.emacsconfig ]; then . $HOME/.emacsconfig fi if [ -z "$DISPLAY" ]; then exec $EMACS "$@" else tempuid=`id -u` temphost=`hostname` if [ -e "/tmp/esrv$tempuid-$temphost" ]; then exec $EMACSCLIENT "$@" else exec $EMACS & while [ ! -e "/tmp/esrv$tempuid-$temphost" ] ; do sleep 1 ; done $EMACSCLIENT "$@" fi fi

This is the change that I made:
17c17,19 < exec $EMACS "$@" --- > exec $EMACS & > while [ ! -e "/tmp/esrv$tempuid-$temphost" ] ; do sleep 1 ; done > $EMACSCLIENT "$@"

Christoph’s code was launching emacs and was waiting for it to return before returning control. I modified it to launch emacs in the background (you might want or need to pass the parameters -f server-start, to loop until emacs opens the socket, and then to launch the emacsclient with the appropriate arguments, waiting for the return of the client, but leaving the server running.

My small modification solves the remaining 15% of my problem. Thanks to Christoph.

Sorry, comments for this entry are closed at this time.