Hack of the day: keep the Emacs server running in the active login session

By | May 21, 2023

Prereqs for this hack being useful to you: (1) you use GNU Emacs; (2) you keep a single Emacs running in your session and use emacsclient to open files for editing in it; (3) you have Linux computers that use systemd on which you keep multiple concurrent login sessions open; and (4) you want emacsclient on those computers to automatically send your edits to the Emacs running in your currently active session.

My use case: I log into my computer while sitting in front of it (GNOME). I log into the same computer remotely over SSH and connect to a persistent Screen session. I keep Emacs running persistently in both contexts (GNOME, Screen). I want emacsclient to instantly and invisibly do the right thing regardless of which session (GNOME, Screen) I happen to be in at the moment.

Solution: Have Emacs launch the server on startup. After that, check every few seconds to see if the current systemd session has transitioned from idle to active. When that happens, restart the server in this Emacs process if it doesn’t already own it.

To use it: download server-sucker.el (gist below), save it somewhere in your Emacs lisp search path, and put (require 'server-sucker) in your .emacs file.

Note: read on below the code for an alternative solution which does most of what mine does without requiring any custom lisp code.

Code:

(Mostly) solving this problem with emacsclient -t and emacsclient -c

After I posted this, Christian Lynbech, pointed me at emacsclient’s -t and -c command-line options. In a nutshell, if you have an Emacs running in any session on the computer with the Emacs server started inside it, then you can use emacsclient -t to open a file for editing inside that Emacs process but with Emacs using your current terminal as its display for the purpose of editing the file, or (if you’re in a graphical session) emacsclient -c to open a new graphical Emacs frame to edit a file in.

Furthermore, you can launch Emacs in the background with emacs --daemon and it’ll respond to these emacsclient -c and emacsclient -t requests.

This is nearly good enough to solve the problem I was trying to solve when I wrote the lisp code above, and it may be good enough for you, but here are the reasons why I prefer my solution and you might as well:

  • I don’t want to have to remember to specify -c or -t. I just want emacsclient to do the right thing.
  • I can’t specify -t or -c when emacsclient is called by another program via $EDITOR or $VISUAL.

I could potentially fix both of the above by writing a smart wrapper around emacsclient which knows how to do what I want, but there are other problems…

  • Something has to “own” the master Emacs process for this to work, but I want a solution that works even whether or not I’m logged in on the console.
  • You can’t use emacsclient -t inside an Emacs shell buffer, and you can’t use emacsclient -c inside the shell buffer if you’re not currently on a graphical desktop, and if you don’t specify -t or -c you have no control over which window/frame Emacs decides to open the file for editing in.
  • emacsclient -t doesn’t work properly for me in a GNOME terminal window; there’s something wrong with the screen drawing.
  • There’s currently a bug in GNOME which causes new Emacs frames to sometimes open with the wrong geometry. Very annoying.

My solution above avoids all of these problems.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *