One of the things I really hate in Emacs is that prompt you normally get when you try to exit Emacs when there are some sub-processes running (e.g. some external shell you’ve started).
I’m a big believer in just doing all the necessary exit cleanup automatically when the user requests an exit. Simple as that. On a practical note - that prompt tends to interrupt the rather inept shutdown/restart sequence of macOS, which waits for all applications to be gracefully closed before proceeding. The time I’ve spent on macOS was the reason that prompted me to look for some solution of this issue.
So, can we do something about this? Historically we couldn’t, but Emacs 26 finally introduced a configuration setting for this -
confirm-kill-processes. By default it’s set to
t, meaning you’ll get the confirmation prompt on exit, but you can easily change this:
(setq confirm-kill-processes nil)
Problem solved. That’s all I have for you today.
Note: That article is only relevant for Linux users.
For as long as I can remember I’ve been installing Emacs (primarily) in one of two ways:
- Via the standard package manager of the operating system I’m using (e.g.
apton Ubuntu or
- From source
Typically, I’d go with the first option unless I am doing some development work on Emacs or I want to experiment with some build options, when I’d go with the second approach. Obviously, nothing beats the convenience of the built-in package manager, but from time to time you’d want to use a version of Emacs that’s not available in your package manager’s repositories and then you have to get more creative (e.g. find third-party repos, some (random) pre-built packages, or build Emacs from source).
Turns out today there’s a third option (at least for Linux users) - installing Emacs via
snap. Simply put,
snapis a distro-agnostic package management framework that distributes self-contained applications (they don’t have any external dependencies). Think of it as something similar to Apple’s App Store. There are other similar projects in the realm of Linux (e.g.
snapseems to be the most popular today, mostly because it was developed by the makers of Ubuntu, Canonical.
Emacs is available at snapcraft.io in 3 flavors:
- latest stable version (published to the
- latest release candidate (published weekly to the
- snapshot build (published weekly to the
Provided you’ve already setup
snap, installing Emacs is trivial:2
# install stable version $ sudo snap install emacs --classic # install release candidate $ sudo snap install emacs --beta --classic # install snapshot version $ sudo snap install emacs --edge --classic
Super simple, right?
While I still plan to use
aptmost of the time (these days I’m using Ubuntu), I have to admit that
snapgives you a trivial way to get access to the latest and greatest version of Emacs on all major Linux distros. I think that’s a very convenient option for anyone who’s not using a rolling release distro, or simply doesn’t want to waste time on upgrading their Emacs.
That’s all I have for you today! Meta-end!
- Via the standard package manager of the operating system I’m using (e.g.
A long time I presented a simple hack that allowed you to quickly navigate to your shell’s user config file (e.g.
.zshrc). While the solution gets the job done it was pretty basic and limited - most notably it’d ignore the fact that you typically have several shell config files that are often built on top of each other - e.g.
~/.bashrc. Fortunately the original hack evolved rather nicely and today lives in the crux library under the name
Provided you’ve installed
cruxall you need to do is run that command (e.g. with
M-x crux-find-shell-init-file) and you’ll get something like this as the result:
Pretty neat, right? Even in its updated state the command is not complex at all:
(defun crux-find-shell-init-file () "Edit the shell init file in another window." (interactive) (let* ((shell (file-name-nondirectory (getenv "SHELL"))) (shell-init-file (cond ((string= "zsh" shell) crux-shell-zsh-init-files) ((string= "bash" shell) crux-shell-bash-init-files) ((string= "tcsh" shell) crux-shell-tcsh-init-files) ((string= "fish" shell) crux-shell-fish-init-files) ((string-prefix-p "ksh" shell) crux-shell-ksh-init-files) (t (error "Unknown shell")))) (candidates (cl-remove-if-not 'file-exists-p (mapcar 'substitute-in-file-name shell-init-file)))) (if (> (length candidates) 1) (find-file-other-window (completing-read "Choose shell init file: " candidates)) (find-file-other-window (car candidates)))))
I guess one thing that we can improve down the road is adding an option to display the shell config in the same window, but that’s a small thing. The variables like
crux-shell-bash-init-filesare simply lists of all potential files that we should look for, that’s why I’ve opted to omit them from the code listing.
I stand by my original suggestion to bind this useful command to
(global-set-key (kbd "C-c S") #'crux-find-shell-init-file)
That’s all I have for you today! Meta-x forever!
Did you notice the subtle difference in the names of the original and the updated article? ↩
Recently I’ve switched back to Linux, after having used macOS for the past 9 years. While I was generally happy with my overall macOS experience, I was also disappointed that Emacs simply didn’t work as well there, as it does on Linux for various reasons.
When I was a Linux user I’d always run Emacs as a daemon (server) and I’d connect this daemon from multiple instances of
emacsclient. This was both elegant and efficient - my clients started instantly and shared access to everything that was running on the daemon instance. While this was doable to some extent in macOS, it never worked quite as well for me, and I abandoned that workflow eventually. Now, however, I’m back! Time to revive the workflow!
Historically I ran the Emacs daemon by adding something like this to my shell init (e.g.
export ALTERNATE_EDITOR='' alias e='emacsclient --tty'
The magic is in the first line - leaving
ALTERNATE_EDITORblank. That way the first time I ran
emacsclientit’d start an Emacs daemon and connect to it. Many people preferred to make the daemon a “proper” service that they can start, restart and monitor, but this felt like an overkill to me. I’ve noticed, however, that Emacs 26.1 bundles a
systemdunit, so it’s now trivial to control your Emacs daemon with
systemd. It all boils down to running this command:
$ systemctl --user enable --now emacs
Run this command with your regular user (or whatever user account you want to be running Emacs). Don’t run it as
root, though! You’ll get a message that the unit file was copied to
/usr/lib/systemd/user/emacs.serviceand you can examine it if you’re curious:
[Unit] Description=Emacs text editor Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/ [Service] Type=simple ExecStart=/usr/bin/emacs --fg-daemon ExecStop=/usr/bin/emacsclient --eval "(kill-emacs)" Environment=SSH_AUTH_SOCK=%t/keyring/ssh Restart=on-failure [Install] WantedBy=default.target
At this point your Emacs daemon is up and you can connect to it using both terminal clients (
emacsclient -t) and GUI clients (
emacsclient -c). You might also want to create some desktop icon that runs
emacsclient -c, instead of
emacs. You might also want to set both
export EDITOR='emacsclient -t' export VISUAL='emacsclient -t'
I typically add two more aliases just to be on the safe side:1
alias vi='emacsclient -t' alias vim='emacsclient -t'
One thing to keep in mind is that when you’re running Emacs in this manner it won’t read your user environment variables (at least not those coming from your
.bashrc). That’s why it’s a good idea to install the popular package exec-path-from-shell.
Alternatively you can use one of
systemd’s own mechanisms for setting environment variables - e.g. environment.d. The Arch Linux Wiki has a few good examples of using
environment.dand also mentions other approaches that you can consider.
That’s all I have for you today. I hope you’ve learned something useful. In parentheses we trust!
Old habits die hard. ↩
Note: Check out my original article from 2013 about the rationale behind this remapping.
Recently I’ve switched back from macOS to GNU/Linux, as my primary development environment, and I found out that my old article on remapping
Controlwas no longer the optimal way to achieve this (e.g. -
xcapeoperates at the X level, which means it doesn’t work with Wayland or without a GUI). It took me a bit of digging, but eventually I found dual-function-keys (a plugin for the interception framework), which does exactly what I needed and it does it splendidly.
Unfortunately, the tool is not packaged for most GNU/Linux distros1, but setting it up from source is not that complex. In this article I’ll share instructions that are specific to Ubuntu, but they should be easy to modify for other Linux distros.
Let’s kick it off by downloading and installing the
# install build deps $ sudo apt install libudev-dev libyaml-cpp-dev libevdev-dev cmake # create a folder where to clone the source code $ mkdir src && cd src # clone the necessary code $ git clone https://gitlab.com/interception/linux/tools $ git clone https://gitlab.com/interception/linux/plugins/dual-function-keys # build and install the interception framework $ cd tools $ mkdir build $ cd build $ cmake .. $ make $ sudo make install $ cd ../.. # build the dual-function-keys plugin $ cd dual-functions-keys $ make && sudo make install
That wasn’t so hard, right? Now we have to create a couple of configuration files and we’re ready for action. The first one is
.dual-function-keys.yaml(normally placed in your home folder):
# /home/username/.dual-function-keys.yaml TIMING: TAP_MILLISEC: 200 DOUBLE_TAP_MILLISEC: 150 MAPPINGS: - KEY: KEY_ENTER TAP: KEY_ENTER HOLD: KEY_RIGHTCTRL
That’s the main config for
dual-function-keys, where we’re specifying the duration of a tap and double tap and our remapping rules. In our case there’s a single rule -
Enteron tap (when pressed briefly) and as (right)
Controlwhen held down longer.
Then we need to create
# /etc/udevmon.yaml - JOB: "intercept -g $DEVNODE | dual-function-keys -c /home/bozhidar/.dual-function-keys.yaml | uinput -d $DEVNODE" DEVICE: EVENTS: EV_KEY: [KEY_ENTER]
Note: Update the path the
Finally we need to create a
systemdservice definition file for
udevmonand start the new service:
# /etc/systemd/system/udevmon.service [Unit] Description=udevmon Wants=systemd-udev-settle.service After=systemd-udev-settle.service [Service] ExecStart=/usr/bin/nice -n -20 /usr/local/bin/udevmon -c /etc/udevmon.yaml [Install] WantedBy=multi-user.target
Now we simply have to enable the
udevmonservice our remapping will kick in:
$ sudo systemctl enable --now udevmon
That’s all! Now you can start enjoying your beloved productivity boost!
You can achieve a lot more with
dual-function-keys, so I’d advice you to explore the tool further. Keep hacking!
If someone’s using another approach to achieve the same result I’d love to hear about it!
Seems currently it’s only packaged for Arch Linux and family (e.g. Manjaro). ↩