Using emacsclient on Linux Mint with update-alternatives

λ August 1, 2020
Tags: emacs, mint

I run a source build of emacs 28.0.50 and I have it installed in a non-standard location. This post will show you how to use update-alternatives to be able to use emacsclient effectively. I had problems because I had a mismatched emacs and emacsclient trying to work with each other. TL;DR make sure you have matching versions of emacs and emacsclient for health and happiness.

My set up, with ohmyzsh

In my ~/.zshrc file I have this line:

    export EDITOR=emacs

That tells anything that wants to launch an editor what I’d prefer to see in front of me, from general work to git commit messages. If in doubt, use -that- editor. Simples. Anyway, being a Mint user for a while now and loving it more every day, I realised that the current setup on my old-ish machine wasn’t ideal; I have a lot of custom files in my ~/.bin folder to make life slicker and some of those files relate to Emacs, namely:

  • enw –> run emacs in the terminal, --nw option
  • enc –> run emacs in the terminal with both --nw and no colour

Having an older machine, I decided I wanted to start using emacsclient just to avoid having to wait a few seconds too many, I am a hardcore Emacs user of some 25 years now, you’d think I’d have done this already but no!

It was good once I guess

So, determined to get my PC feeling as slick as possible, I knew that the time had come not only to do battle with the Emacs client configuration but also the update-alternatives script which is stock on most Debian based distros. The first time I ever tangled with it it felt hard but actually it’s not that bad, and very VERY useful for a cleaner command line experience. And what’s not to like about that ?

First steps: some poking at the box…

I first went back to the GNU site and read this page to get some memories back!

https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html#Emacs-Server

I then optimistically tried to go for it straight away:

╰─$ systemctl --user enable emacs
Failed to enable unit: Unit file emacs.service does not exist.

Bummer…so, I went to the place where I have my custom source build, the folder /opt/emacs, and had a look around to see what was given to me:

╰─$ find -name "*.service"
./lib/systemd/user/emacs.service
./share/emacs/28.0.50/etc/emacs.service

So many to choose from…one of them would be the correct one, so, using diff to compare them:

╰─$ diff ./lib/systemd/user/emacs.service ./share/emacs/28.0.50/etc/emacs.service 
0a1,4
> ## If your Emacs is installed in a non-standard location, you may need
> ## to copy this file to a standard directory, e.g. ~/.config/systemd/user/ .
> ## If you install this file by hand, change the "Exec" lines below
> ## to use absolute file names for the executables.
7,8c11,12
< ExecStart=/opt/emacs/bin/emacs --fg-daemon
< ExecStop=/opt/emacs/bin/emacsclient --eval "(kill-emacs)"
---
> ExecStart=emacs --fg-daemon
> ExecStop=emacsclient --eval "(kill-emacs)"

So all I had to do was copy the correct one to my local systemd configuration folder for user services, what could be simpler ?

╰─$ cd ~/.config/systemd
cd: no such file or directory: systemd

OK, so, nobody ever used it before… time to make one then with:

╰─$ cd mkdir -p ~/.config/systemd/user
╰─$ cp /opt/emacs/share/emacs/28.0.50/etc/emacs.service ./systemd/user/.

Spot the deliberate mistake, sadly, I didn’t. The next part is longer but it also was a great learning experience at the same time so I’ve written it up, warts and all, armed with the confidence of a fool who believes he’s done the right thing, I then tried this to enable the script:

╰─$ systemctl --user enable emacs
Created symlink /home/sean/.config/systemd/user/
(cont)    default.target.wants/emacs.service
(cont)    → /home/sean/.config/systemd/user/emacs.service.

Looks good, no errors, wow, almost done then. ….. :|

╰─$ emacsclient -c
emacsclient: can't find socket; have you started the server?
To start the server in Emacs, type "M-x server-start".
emacsclient: No socket or alternate editor.  Please use:

    --socket-name
    --server-file      (or environment variable EMACS_SERVER_FILE)
    --alternate-editor (or environment variable ALTERNATE_EDITOR)

WTF?

╰─$ systemctl start emacs
Failed to start emacs.service: Unit emacs.service not found.
╭─sean@sean-MS-7891  ~/.config ‹node-›  ‹› 
╰─$ systemctl start --user emacs
Failed to start emacs.service: Unit emacs.service is not loaded properly:
(cont)    Exec format error.
See user logs and 'systemctl --user status emacs.service' for details.
╭─sean@sean-MS-7891  ~/.config ‹node-›  ‹› 
╰─$ systemctl --user status emacs.service
● emacs.service - Emacs text editor
   Loaded: error (Reason: Exec format error)
   Active: inactive (dead)
     Docs: info:emacs
           man:emacs(1)
           https://gnu.org/software/emacs/

It took me a while to realise… I had copied the wrong file from the diff output in my haste to get it all working, this meant I had to do this to correct it:

╰─$ cp /opt/emacs/lib/systemd/user/emacs.service ./systemd/user/.

Using this page now as reference: https://www.emacswiki.org/emacs/EmacsAsDaemon

╰─$ systemctl enable --user emacs   
╰─$ systemctl start --user emacs

…but the command didn’t returned so assumed all was well….on a startup this would probably be spawned (think &) and be fine…simple way to check is to see what’s now running in the background! But just as I was about to CTRL-C it, it came back with this sorry arsed message:

Job for emacs.service failed because a timeout was exceeded.
See "systemctl --user status emacs.service" and
"journalctl --user -xe" for details.

Argh!!! So, I went back to -the- Emacs site and found this page: https://www.emacswiki.org/emacs/EmacsAsDaemon which showed some differences between the script on my machine and the ideal setup, namely the Type was not set to forking on my version, so I changed it to be this, it of course being ~/.config/systemd/user/emacs.service:

[Unit]
Description=Emacs text editor
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/

[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Restart=on-failure

[Install]
WantedBy=default.target

Charged with hope, I saved this and then:

╰─$ systemctl start --user emacs 
Job for emacs.service failed because a timeout was exceeded.
See "systemctl --user status emacs.service" and
(cont)    "journalctl --user -xe" for details.

And asking for some more information:

╰─$ systemctl --user status emacs.service                                   1 ↵
● emacs.service - Emacs text editor
   Loaded: loaded (/home/sean/.config/systemd/user/emacs.service; enabled; vendo
   Active: active (running) since Sat 2020-08-01 06:59:28 BST; 2min 14s ago
     Docs: info:emacs
           man:emacs(1)
           https://gnu.org/software/emacs/
  Process: 8991 ExecStart=/opt/emacs/bin/emacs --daemon (code=exited, status=0/S
 Main PID: 8992 (emacs)
   CGroup: /user.slice/user-1000.slice/user@1000.service/emacs.service
           └─8992 /opt/emacs/bin/emacs --daemon

Aug 01 06:59:26 sean-MS-7891 systemd[1444]: Starting Emacs text editor...
Aug 01 06:59:27 sean-MS-7891 emacs[8991]: Loading time...
Aug 01 06:59:27 sean-MS-7891 emacs[8991]: Loading time...done
Aug 01 06:59:27 sean-MS-7891 emacs[8991]: Loading paren...
Aug 01 06:59:27 sean-MS-7891 emacs[8991]: Loading paren...done
Aug 01 06:59:28 sean-MS-7891 emacs[8991]: Starting Emacs daemon.
Aug 01 06:59:28 sean-MS-7891 systemd[1444]: Started Emacs text editor.

WAT? WAAAAT?It says it’s running!!! At this point I was close to almost getting a tad miffed but being a seasoned veteran, used to realising my own fallibility, I knew I’d still not got something right so I then decided to check what was being run when I type these things on faith:

╰─$ which emacsclient
/usr/bin/emacsclient

╰─$ ll /usr/bin/emacsclient
lrwxrwxrwx 1 root root 29 Mar 27 10:15 /usr/bin/emacsclient
(cont)    -> /etc/alternatives/emacsclient

╰─$ ll /etc/alternatives/emacsclient
lrwxrwxrwx 1 root root 28 Mar 27 10:15 /etc/alternatives/emacsclient
(cont)    -> /usr/bin/emacsclient.emacs25

╰─$ sudo update-alternatives --list emacsclient
[sudo] password for sean:                      
/usr/bin/emacsclient.emacs25

╭─sean@sean-MS-7891  ~/.config/systemd/user ‹node-›  ‹› 
╰─$ sudo update-alternatives --list emacs      
/opt/emacs/bin/emacs
/usr/bin/emacs25-x

SOLVED: mismatched versions, thanks to this Reddit thread which tipped me off as to what might be the source of this problem: version mismatch!

Using update-alternative to make it CLI friendly

There is a program called update-alternatives which you may or may not be aware of. When you type the name of a program to run from the command line, it may not be running what you think! If you look in a folder called /etc/alternatives/ you will find an enormous amount of symbolic links (sym-links) to actual real programs. What update-alternatives does is manage those links so that you can use different versions of things from the command line without having to know where they are, this is great for version updates etc. I suggest some light reading on the matter at some point.

Anyway, realising that I had to make them versions the same, I did some viewing and then set about making things right with the world:

╰─$ sudo update-alternatives --install /usr/bin/emacsclient
(cont)    emacsclient /opt/emacs/bin/emacsclient 0

╰─$ sudo update-alternatives --list emacs
/opt/emacs/bin/emacs
/usr/bin/emacs25-x

╰─$ sudo update-alternatives --list emacsclient
/opt/emacs/bin/emacsclient
/usr/bin/emacsclient.emacs25

(Note: using 0 was a mistake, but I didn’t know what number to use at the time as the prioroty..read on!)

OK, looks good (mwah hah hah to come…), let’s finally go back to having it started as a system service when the machine boots up so I don’t have to wait so long:

    ╰─$ systemctl start --user emacs                      
    ╰─$ 

Instant! success!! No errors no time-out errors etc…well, this is great I must say…I thought I’d see what emacs related processes were running now:

╰─$ ps ax | grep emacs
8992 ?        Ssl    0:01 /opt/emacs/bin/emacs --daemon
9897 pts/5    S+     0:00 grep --color=auto --exclude-dir=.bzr
(cont)  --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg
(cont)  --exclude-dir=.svn --exclude-dir=.idea --exclude-dir=.tox emacs
17409 ?        Sl     0:52 emacs

The first one is cool, second is our grep and the last one is ’cos I was already running a session of emacs, to maintain the history that became this article actually.

Nooooooooooooooo

So finally, using emacsclient is now a done deal right?

emacsclient: can't find socket; have you started the server?
To start the server in Emacs, type "M-x server-start".
emacsclient: No socket or alternate editor.  Please use:

    --socket-name
    --server-file      (or environment variable EMACS_SERVER_FILE)
    --alternate-editor (or environment variable ALTERNATE_EDITOR)

Sensing that something was still not right with The Force I knew that the final check was to make sure that the alternative links were correctly set for both emacs and emacsclient so that they could play ball.

I know Kung-Fu

WTAF??? Beats head on desk and wonders what’s left to go wrong… time to take control of the legendary alternatives magic once and for all. I first checked on emacs and the emacsclient links:


╰─$ sudo update-alternatives --config emacsclient
There are 2 choices for the alternative emacsclient (providing /usr/bin/emacsclient).

Selection    Path                          Priority   Status
------------------------------------------------------------
* 0            /usr/bin/emacsclient.emacs25   28        auto mode
1            /opt/emacs/bin/emacsclient     0         manual mode
2            /usr/bin/emacsclient.emacs25   28        manual mode

Press <enter> to keep the current choice[*], or type selection number: 1

╰─$ sudo update-alternatives --config emacsclient
There are 2 choices for the alternative emacsclient (providing /usr/bin/emacsclient).

Selection    Path                          Priority   Status
------------------------------------------------------------
0            /usr/bin/emacsclient.emacs25   28        auto mode
* 1            /opt/emacs/bin/emacsclient     0         manual mode
2            /usr/bin/emacsclient.emacs25   28        manual mode

Press <enter> to keep the current choice[*], or type selection number: 

OK NOW it looks like it might work!! It did…I typed emacsclient a file and it opened way quicker this time… on my older PC this makes me feel like I have a faster PC…now just to reboot and make sure it works as expected.

A few minutes later… still working! Now I can enjoy the impression that my PC is faster than it is by having Emacs loaded and ready to roll in the background. All you need is perseverance and a clear head, once the flower of anger has grown from a seed and blossomed there’s no hope for the day!

Happy Hacking!

Comments