/chemacs2

Emacs version switcher, improved

Primary LanguageEmacs Lisp

     ___           ___           ___           ___           ___           ___           ___
    /  /\         /__/\         /  /\         /__/\         /  /\         /  /\         /  /\
   /  /:/         \  \:\       /  /:/_       |  |::\       /  /::\       /  /:/        /  /:/_
  /  /:/           \__\:\     /  /:/ /\      |  |:|:\     /  /:/\:\     /  /:/        /  /:/ /\
 /  /:/  ___   ___ /  /::\   /  /:/ /:/_   __|__|:|\:\   /  /:/~/::\   /  /:/  ___   /  /:/ /::\
/__/:/  /  /\ /__/\  /:/\:\ /__/:/ /:/ /\ /__/::::| \:\ /__/:/ /:/\:\ /__/:/  /  /\ /__/:/ /:/\:\
\  \:\ /  /:/ \  \:\/:/__\/ \  \:\/:/ /:/ \  \:\~~\__\/ \  \:\/:/__\/ \  \:\ /  /:/ \  \:\/:/~/:/
 \  \:\  /:/   \  \::/       \  \::/ /:/   \  \:\        \  \::/       \  \:\  /:/   \  \2.0 /:/
  \  \:\/:/     \  \:\        \  \:\/:/     \  \:\        \  \:\        \  \:\/:/     \__\/ /:/
   \  \::/       \  \:\        \  \::/       \  \:\        \  \:\        \  \::/        /__/:/
    \__\/         \__\/         \__\/         \__\/         \__\/         \__\/         \__\/

                                        222222222222222
                                       2:::::::::::::::22
                                       2::::::222222:::::2
                                       2222222     2:::::2
                                                   2:::::2
                                                   2:::::2
                                                2222::::2
                                           22222::::::22
                                         22::::::::222
                                        2:::::22222
                                       2:::::2
                                       2:::::2
                                       2:::::2       222222
                                       2::::::2222222:::::2
                                       2::::::::::::::::::2
                                       22222222222222222222

Chemacs

Chemacs 2 is an Emacs profile switcher, it makes it easy to run multiple Emacs configurations side by side.

Think of it as a bootloader for Emacs.

Differences from Chemacs 1

Emacs intialization used to have a single entry point, either ~/.emacs or ~/.emacs.d/init.el. More recent Emacsen have introduced a second startup script, ~/.emacs.d/early-init.el, which runs earlier in the boot process, and can be used for things that should happen very early on, like tweaking the GC, or disabling UI elements.

Chemacs 2 supports early-init.el, Chemacs 1 does not. This does also imply that Chemacs 2 needs to be installed as ~/.emacs.d (a directory), rather than simply linking it to ~/.emacs (a single file).

Rationale

Emacs configuration is either kept in a ~/.emacs file or, more commonly, in a ~/.emacs.d directory. These paths are hard-coded. If you want to try out someone else’s configuration, or run different distributions like Prelude or Spacemacs, then you either need to swap out ~/.emacs.d, or run Emacs with a different $HOME directory set.

This last approach is quite common, but has some real drawbacks, since now packages will no longer know where your actual home directory is.

All of these makes trying out different Emacs configurations and distributions needlessly cumbersome.

Various approaches to solving this have been floated over the years. There’s an Emacs patch around that adds an extra command line option, and various examples of how to add a command line option in userspace from Emacs Lisp.

Chemacs tries to implement this idea in a user-friendly way, taking care of the various edge cases and use cases that come up.

Alternatives

Installation

Clone the Chemacs 2 repository as $HOME/.emacs.d. Note that if you already have an Emacs setup in ~/.emacs.d you need to move it out of the way first. If you have an ~/.emacs startup script then move that out of the way as well.

[ -f ~/.emacs ] && mv ~/.emacs ~/.emacs.bak
[ -d ~/.emacs.d ] && mv ~/.emacs.d ~/.emacs.default
git clone https://github.com/plexus/chemacs2.git ~/.emacs.d

Note that this is different from Chemacs 1. Before Chemacs installed itself as ~/.emacs and you could have your own default setup in ~/.emacs.d. This approach no longer works because of ~/.emacs.d/early-init.el, so Chemacs 2 needs to be installed as ~/.emacs.d.

Next you will need to create a ~/.emacs-profiles.el file, for details see below.

(("default" . ((user-emacs-directory . "~/.emacs.default"))))

Usage

Chemacs adds an extra command line option to Emacs, --with-profile. Profiles are configured in ~/.emacs-profiles.el.

If no profile is given at the command line then the environment variable CHEMACS_PROFILE is used. If this environment variables isn’t set then the default profile is used.

$ emacs --with-profile my-profile

There is an option for using profile that is not preconfigured in ~/.emacs-profiles.el. To accomplish that you can directly provide the profile via the command line, like so

$ emacs --with-profile '((user-emacs-directory . "/path/to/config"))'

This method supports all the profile options given below.

.emacs-profiles.el

This file contains an association list, with the keys/cars being the profile names, and the values/cdrs their configuration.

The main thing to configure is the user-emacs-directory

(("default" . ((user-emacs-directory . "~/.emacs.default")))
 ("spacemacs" . ((user-emacs-directory . "~/spacemacs"))))

Chemacs will set this to be the user-emacs-directory in use, and load init.el from that directory.

Other things you can configure

  • custom-file : The file where Customize stores its customizations. If this isn’t configured, and the custom-file variable is still unset after loading the profile’s init.el, then this will get set to the profile’s init.el
  • server-name : Sets the server-name variable, so you can distinguish multiple instances with emacsclient -s <server-name>.
  • env An association list of environment variables. These will get set before loading the profile, so they can influence the initialization, and they are visible to any subprocesses spawned from Emacs.
  • straight-p Enable the Straight functional package manager.
  • nix-elisp-bundle A directory containing elisp dependencies bundled by the nix package manager. The bundle path can be produced by nix using an expression like (emacs.pkgs.withPackages (p: [ p.avy … ])).deps. Because the bundle path is in the nix store, if it is specified in .emacs-profiles.el then that file should also be maintained by nix, to prevent the path from being garbage-collected. Alternatively, a nix-generated script or alias could specify nix-elisp-bundle as a command-line argument.

Store .emacs-profiles.el together with your dotfiles. If you’re not yet keeping a version controlled directory of dotfiles, then check out connect-the-dots for a helpful script to do that.

Changing the default profile (e.g. for GUI editors)

Where it is not possible to use the --with-profile flag or the CHEMACS_PROFILE environment variable, the default profile can be set using a ~/.emacs-profile file.

If your ~/.emacs-profiles.el file contains the following:

(("default" . ((user-emacs-directory . "~/.emacs.default")))
 ("spacemacs" . ((user-emacs-directory . "~/spacemacs")))
 ("prelude" . ((user-emacs-directory . "~/prelude"))))

you can create a file called ~/.emacs-profile, containing the name of the profile you’d like to be used when none is given on the command line:

$ echo 'spacemacs' > ~/.emacs-profile

This will set the default profile to be the “spacemacs” profile, instead of “default”. You can change the default by simply changing the contents of this file:

$ echo 'prelude' > ~/.emacs-profile

If this file doesn’t exist, then “default” will be used, as before.

Spacemacs

Spacemacs is typically installed by cloning the Spacemacs repo to ~/.emacs.d, and doing extra customization from ~/.spacemacs or ~/.spacemacs.d/init.el. This makes it tedious to switch between version of Spacemacs, or between different Spacemacs configurations.

With Chemacs you can point your user-emacs-directory to wherever you have Spacemacs installed, and use the SPACEMACSDIR environment variable to point at a directory with customizations that are applied on top of the base install.

(("spacemacs" . ((user-emacs-directory . "~/spacemacs")
                 (env . (("SPACEMACSDIR" . "~/.spacemacs.d")))))

 ("spacemacs-develop" . ((user-emacs-directory . "~/spacemacs/develop")
                        (env . (("SPACEMACSDIR" . "~/.spacemacs.d")))))

 ("new-config" . ((user-emacs-directory . "~/spacemacs/develop")
                  (env . (("SPACEMACSDIR" . "~/my-spacemacs-config"))))))

DOOM emacs

You can add an entry similar to the following to your .emacs-profiles.el

In the following snippet ~/doom-emacs is where you have cloned doom emacs.

(Depending on when you read this) DOOMDIR support is only in develop branch of doom emacs. Check commit history of master branch of doom emacs

("doom" . ((user-emacs-directory . "~/doom-emacs")
           (env . (("DOOMDIR" . "~/doom-config")))))

Please refer to this discussion for details.

FreeDesktop Directories

Both ~/.emacs-profiles.el and ~/.emacs-profile can also be stored under $XDG_CONFIG_HOME/chemacs (typically ~/.config/chemacs) as $XGD_CONFIG_HOME/chemacs/profiles.el and $XDG_CONFIG_HOME/chemacs/profile respectively.

Further, as indicated by the Emacs 27.1 changelog, Emacs is now compatible with XDG Standards, looking for its configuration files in ${XDG_CONFIG_HOME}/emacs directory too (provided the traditional ~/.emacs.d and ~/.emacs does not exist). Therefore, it is perfectly viable to install Chemacs 2 in ${XDG_CONFIG_HOME}/emacs (usually ~/.config/emacs) directory - with the aforementioned caveat: the directory =~/.emacs.d”= and the file =”~/.emacs”= does not exist.

Example: emacs as daemon

  • Profiles

You can add an entry similar to the following to your .emacs-profiles.el

;; your custom or vanilla emacs profile
(("default" . ((user-emacs-directory . "~/.gnu-emacs")
	       (server-name . "gnu")
	       ))

;; emacs distribution: DOOM-emacs
("doom" . ((user-emacs-directory . "~/.doom-emacs")
	   (server-name . "doom")
	   (env . (("DOOMDIR" . "~/.doom.d")))
	     ))
  )
  • daemon

Set emacs daemon to always run in background

# vanilla
emacs --daemon &
# Doom emacs
emacs --with-profile doom --daemon &
  • emacsclient

create a new frame, connect to the socket and use vanilla emacs as fallback

emacsclient -c -s gnu -a emacs
emacsclient -c -s doom -a emacs

Troubleshooting

Emacs cannot find packages installed by straight

Some users have reported issues where packages installed by `straight.el` can no longer be found after switching to using `chemacs`.

First, make sure you haven’t hardcoded filepaths to “emacs.d” in your configuration. You should reference files inside a profile-specific emacs folder like this:

(setq some-var (expand-file-name "path/to/file" user-emacs-directory))

Second, if the issue persists you should delete the `build` folder in your `straight` directory and rebuild your dependencies.

If the issue persists please comment on the issue, because we are still trying to figure out the exact source of this problem, but this has solved the problem for some users.

LICENSE

Copyright © Arne Brasseur and contributors, 2018-2022

Distributed under the terms of the GPL v3.