Posts
Customizing Color Themes
Every now and then you’d be trying out a new color theme, that you really like overall, but you’d like to tweak a bit here and there to make it perfect. After all, that’s what Emacs is all about - creating the perfect editor for yourself.
Sometimes you might be dealing with missing face definitions or configuration options that you might want to submit upstream, but most of the time the changes you’d like to see are probably quite subjective and belong in your personal config. So, how do you make those changes?
There are 3 common ways to adjust font faces in Emacs and I’ll briefly cover all of them. Option number 1 is the tried and true classic
custom-set-faces
:(custom-set-faces '(region ((t (:inherit nil :background "RoyalBlue4")))) '(highlight ((t (:inherit region :background "dark olive green")))) '(hl-line ((t (:inherit highlight)))))
That’s what gets generate if you’re adjusting faces with something like
M-x customize-face
. The bad thing about this approach is that those customizations will active regardless of your currently selected color theme and if you like to switch themes that’s not cool. Fortunately, it’s easily to narrow customizations to a particular theme withcustom-theme-set-faces
:(custom-theme-set-faces 'zenburn '(region ((t (:inherit nil :background "RoyalBlue4")))) '(highlight ((t (:inherit region :background "dark olive green")))) '(hl-line ((t (:inherit highlight)))))
Looking good!
Note:
custom-set-faces
works by callingcustom-theme-set-faces
for theuser
theme, a special theme referring to settings made via Customize.Finally, you can just set a specific face using
set-face-attribute
like this:(set-face-attribute 'font-lock-builtin-face nil :weight 'bold)
I’d suggest perusing the documentation of
set-face-attribute
(e.g. withC-h f
) as it explains in great detail all the possible attributes you can configure for a font face. The number of properties you can set is truly epic, but most of the time you’ll need to tweak only a couple of them. (e.g.:foreground
,:background
, etc)Technically speaking, you can go a step further than that and define your own theme that extends the color theme you want to modify1, but that’s an overkill unless you plan to distribute this theme as a package.
All the examples above are kind of random, so I’ll conclude here with some real modifications I do in my config to the popular Catppuccin theme:
(use-package catppuccin-theme :config ;; or 'latte, 'macchiato, or 'mocha (setq catppuccin-flavor 'macchiato) (load-theme 'catppuccin t) (custom-theme-set-faces 'catppuccin ;; by default the theme uses the same face as for comments, which is wrong IMO '(font-lock-doc-face ((t (:foreground (catppuccin-color 'green))))) ;; font-lock variable definitions like function definitions '(font-lock-variable-face ((t (:inherit font-lock-function-face))))))
The example above also shows how to access the colors from the palette of some color theme outside of its definition. Usually themes provide some API like
theme-name-color
to get able to get the color codes easily.Funny enough, as I’m writing this I realized that
use-package
actually has built-in support for customizing faces that I could have used instead. Here’s an example of that in action:(use-package zenburn-theme :preface (setq my/zenburn-colors-alist '((fg . "#DCDCCC") (bg . "#1C1C1C") (cyan . "#93E0E3"))) :custom-face (region ((t (:background ,(alist-get my/zenburn-colors-alist 'cyan))))) :config (load-theme 'zenburn t))
This example also reminded me that I should expose the Zenburn colors via functions.
So, to summarize:
- If you’re using
use-package
it’s probably best to use it’s:custom-face
functionality. - The rest of the time you most likely need
custom-theme-set-faces
.
One thing is certain - with Emacs there always numerous ways to achieve something!
Note: To see the new font faces in action you’ll either have to restart Emacs or evaluate Elisp code that sets them. (e.g. with
C-x C-e
)One final tip - if you’re wondering what’s the face used by some text, the best way to figure it out is with the
M-x describe-char
command. It will give you a ton of information, including something like this near the end:There are text properties here: face (font-lock-keyword-face markdown-code-face) font-lock-fontified t font-lock-multiline t fontified t markdown-gfm-code (2617 3092)
I had placed my cursor over the word “use-package” in the code snippet above, while writing this article in
markdown-mode
, therefore the facesfont-lock-keyword-face
(coming fromelisp-mode
) andmarkdown-code-face
(frommarkdown-mode
).Do you have any tips on customizing color themes that you’d like share?
That’s all I have for you today. Keep hacking!
-
Remember that Emacs allows you load multiple themes with them stacking one upon another. ↩
- If you’re using
Clean Unloading of Emacs Themes
If you’re like me, you probably like playing with new Emacs color themes from time to time. Sure, I’m the person behind the Emacs ports of Zenburn and Solarized, but as much as I like them, even I get bored with them occasionally.1
What I often do is to install a bunch of themes (e.g. using
M-x package-install
) and to quickly try them out by evaluating snippets like the ones below in Emacs:(load-theme 'catppuccin t) (load-theme 'dracula t) (load-theme 'gruvbox t)
One small problem with this, though, is that Emacs themes were designed in such a way that one theme can be applied on top of another one. (loading a new theme doesn’t unload the previusly loaded one) In practice this often means that if you load a few themes one after another they’ll start to mess each other up. There are several ways to address this, the simplest being to call
disable-theme
every time before loading a new theme:(load-theme 'catppuccin t) (disable-theme 'catppuccin) (load-theme 'dracula t) (disable-theme 'dracula) (load-theme 'gruvbox t)
Or you can get more adventurous and create a small command that unloads all loaded themes, effectively resetting the theme to Emacs’s default one:
(defun er-disable-all-active-themes () "Disable all currently active themes." (interactive) (dolist (theme custom-enabled-themes) (disable-theme theme)))
Now, you can simply do
M-x disable-all-active-themes
when you see fit. Finally, you can consider creating a function complementary toload-theme
that unloads all active themes before loading the new one:(defun er-load-theme (theme) (er-disable-all-active-themes) (load-theme theme t)) (er-load-theme 'catppuccin t) (er-load-theme 'dracula t) (er-load-theme 'gruvbox t)
Pretty neat!
That’s all I have for you on this subject. Keep hacking!
P.S. If you’re afraid of Elisp there are a couple of alternative approaches you might consider:
- The built-in command
M-x customize-themes
- The
consult-theme
from the popular consult package
Both are also great options for previewing themes!
-
Zenburn is to this day my all time favorite theme, though. I rarely manage to spend more than a few days away from it. ↩
- The built-in command
Debugging Emacs Commands
If you’re using Emacs long enough sooner or later you’ll run into some Emacs command that’s misbehaving and you’ll need to debug it somehow.1
If the command is just blowing up, probably you’ll be able to figure out what’s going on by looking at its backtrace. To get meaningful backtraces you can either run
M-x toggle-debug-on-error
or add this to your Emacs config:(setq debug-on-error t)
Sometimes that will be enough, but other times you’ll need to dig deeper… Fortunately for us Emacs features a super powerful built-in Emacs Lisp debugger and using it is the best way to diagnose problems of any kind.2
To debug some command you need to do the following:
- Figure out the name of the command you want to debug (e.g. by using
C-h k
to see which command is associated with some keybinding) - Find the source of the command (e.g. by using
M-x find-function RET function-name
) - Press
C-u C-M-x
while in the body of the function - Run the command again
At this point you’ll be dropped in the debugger and you can step forward (by pressing
n
) until you find the problem.I use this approach all time and it’s very efficient. It’s also not specific to commands and works great for all Emacs Lisp code. Every Emacs user will do well to invest a bit of time into learning the basics of debugging Emacs Lisp code.
That’s all I have for you today. Keep hacking!
-
Emacs commands are simply Emacs Lisp functions that can be invoked interactively with
M-x
. ↩ -
Here’s a great crash course on using the debugger. ↩
- Figure out the name of the command you want to debug (e.g. by using
Emacs and XDG sitting on a tree
Where to place my Emacs configuration? That is the question!
This fairly simple question has surprisingly many answers, as it often happens with projects as old as Emacs:
- Historically Emacs’s user config was a file called
.emacs
, placed in your home directory - Later you could use the name
init.el
as an alias to.emacs
- And then there’s the option that’s probably most common today - placing your configuration
under the
.emacs.d
folder, where you usually have aninit.el
that potentially refers to other Emacs Lisp libraries
But wait, there’s more! Emacs 27.1 introduced
XDG_CONFIG_HOME
support, and Emacs 29.1 extended the level of XDG base directory specification support in Emacs.XDG, which stands for X Desktop Group, is a set of standards and specifications developed by freedesktop.org to promote interoperability among different desktop environments, primarily in Unix-like operating systems. The group focuses on ensuring that applications can work seamlessly across various desktop environments by adhering to common guidelines.
Their most notable work to date is the XDG base directory specification. In a nutshell this specification outlines the environment variables that define where user-specific data files, configuration files, and cache files should be stored. For instance, it specifies directories like
$XDG_CONFIG_HOME
for configuration files and$XDG_DATA_HOME
for data files.1Most of the time the XDG config home would be
~/.config
and there would be a subfolder there for the configuration of each application. In Emacs’s case that would be~/.config/emacs
. I hope it’s clear that the idea here is to reduce the clutter at the top-level and to make sure that each application stores its configuration in a predictable place.I think it’s really great that Emacs is (slowly) adopting the industry standards and I believe that over the course of time the XDG config folder will become the preferred place to store your Emacs configuration. That’s why I encourage everyone to move in this direction and unclutter their home folder a bit.
Just keep in mind a couple of things:
- You’ll have to make sure that folders like
~/.emacs.d
don’t exist anymore, as they’d have precedence over the XDG config folder. The configuration resolution happens like this:
Emacs looks for your init file using the filenames
~/.emacs.el
,~/.emacs
, or~/.emacs.d/init.el
in that order; you can choose to use any one of these names. (Note that only the locations directly in your home directory have a leading dot in the location’s basename.)Emacs can also look in an XDG-compatible location for init.el, the default is the directory
~/.config/emacs
. This can be overridden by settingXDG_CONFIG_HOME
in your environment, its value replaces~/.config
in the name of the default XDG init file. However~/.emacs.d
,~/.emacs
, and~/.emacs.el
are always preferred if they exist, which means that you must delete or rename them in order to use the XDG location.Note also that if neither the XDG location nor
~/.emacs.d
exist, then Emacs will create~/.emacs.d
(and therefore use it during subsequent invocations).Emacs will set user-emacs-directory to the directory it decides to use.
Not the best defaults IMO (especially falling back to creating
.emacs.d
), but you can’t fight tradition! Or rather - fighting tradition is pretty hard…- Some packages might have hardcoded the path in which they store their own configuration. In general they should be relying on
user-emacs-directory
, which will be auto-set to whatever directory Emacs discovered its configuration in, but there will always be some packages that probably didn’t do “the right thing”.
I’m guessing that we’re not really getting rid of
~/.emacs.d
any time soon (or ever), but I’m hoping that article like this one might speed up a bit the process. Time will tell.macOS users should keep in mind that unfortunately macOS doesn’t set the standard XDG environment variables, as it has its own notion of where things like configuration files, application cache, etc should be stored. Still, it’s fairly easy to just set the missing variables yourself (e.g. in your
.zshrc
):export XDG_CONFIG_HOME = $HOME/.config export XDG_DATA_HOME = $HOME/.local/share export XDG_STATE_HOME = $HOME/.local/state export XDG_CACHE_HOME = $HOME/.cache
So, has anyone moved their Emacs config to respect the XDG conventions already? How smooth was the process for you?
P.S. If you’re curious to learn more about how Emacs’s configuration discover process I’d suggest reading this chapter of the Emacs Manual. Good stuff!
-
Check out the XDG base directory specification for more details. ↩
- Historically Emacs’s user config was a file called
Ensure all packages are installed by default with use-package
I’m quite fond of
use-package
and I’ve organized my personal Emacs setup around it for a while now. One thing that I don’t like very much is that by default almost I have to add:ensure t
to almost everyuse-package
block, as I want all external packages to be installed if they are not present. That’s quite handy when I’m setting up Emacs on a new computer.1 Think something like:(use-package zenburn-theme :ensure t :config (load-theme 'zenburn t))
Not a big deal for a few packages, but kind of annoying if you have 50+ packages in your
init.el
. There’s a pretty simple solution to this problem, though. Just add the following bit of configuration to your Emacs setup:(setq use-package-always-ensure t)
Now instead of specifying
:ensure t
you can specify:ensure nil
for the packages you don’t want to install automatically. Note that for built-packages (e.g.dired
) it doesn’t really matter if a package is using:ensure t
or:ensure nil
.2Which approach do you prefer? Are you the type of person who ensures every package is installed when absent or not? Why do you prefer one approach over the other?
-
I know that a lot of people object to this approach, as you’re not sure what versions of the packages you’d get as
package.el
is a bit primitive compared to something like Ruby’s Bundler or Node’snpm
, but in practice I’ve rarely had issues with my approach and it has saved me a great deal of time. ↩ -
package-installed-p
will returnt
for those. ↩
-
Subscribe via RSS | View Older Posts