Using Fontsets in Emacs
Fontset?
Fontset is a feature of Emacs that allows you to bundle together multiple fonts and use them as a single font, such that it covers more characters than a single font could have. For example, you can combine a Latin font, a Greek font and a Chinese font together.
With fontsets, we can use different Unicode fonts for different faces. For example, serif Latin and Chinese font for a “serif” face, and sans serif Latin and Chinese font for a “sans” face. Without fontsets, we can only set different Latin fonts to faces and use a single fall-back Chinese font.
Create a fontset
A fontset is recognized by its name. Each fontset has two names, one
short and one long. The short name looks like fontset-xxx
.
The long name is a X Logical
Font Description with last two fields being fontset
and
xxx
. For example,
-*-ibm plex mono-medium-*-*-*-13-*-*-*-*-*-fontset-my fontset
Emacs come with three fontsets by default:
fontset-startup
, fontset-standard
and
fontset-default
. We only care about
fontset-default
; it is the ultimate fall-back when Emacs
cannot find a font to display a character. But more on that later.
To create a fontset, you can use
create-fontset-from-fontset-spec
and pass it a bunch of X
Logical Font Descriptions, each for a font you want to include. I find
that tedious. Instead, I like to create a fontset with a single ASCII
font and use set-fontset-font
to add other fonts later, like
this:
(create-fontset-from-fontset-spec (font-xlfd-name (font-spec :family "IBM Plex Mono" :size 13 :registry "fontset-my fontset")))
Make sure you put the short fontset name under the
:registry
spec. The code above creates the fontset, and
returns its long name,
-*-ibm plex mono-*-*-*-*-13-*-*-*-*-*-fontset-my fontset
Now we can add a Chinese font and a Greek font:
(set-fontset-font "fontset-my fontset" 'han (font-spec :family "Source Han Serif" :size 12)) (set-fontset-font "fontset-my fontset" 'greek (font-spec :family "Academica"))
If you are not familiar with set-fontset-font
, Emacs, fonts and
fontsets is a good read.
Apply a fonset
Although the manual says we can use a fontset wherever a font is
appropriate, it is not entirely true. If you pass your fontset through
the :font
attribute in set-face-attribute
,
Emacs takes
the ASCII font from the fontset and only uses the ASCII font for the
face1. The real way to do it is to
use the undocumented :fontset
attribute:
(set-face-attribute 'some-face nil :fontset "fontset-my fontset")
That’s not all. While the above code works for most faces, setting
:fontset
for default
will not work as you
expected, because Emacs again only takes the ASCII font, even if you use the
fontset
attribute2. So
don’t set the fontset for the default
face; instead, just
modify fontset-default
(it’s the ultimate fall-back fontset
we mentioned earlier) for Unicode fonts, and use whatever method you like
for ASCII font. If you read Emacs, fonts and
fontsets, you’ll know we can modify fontset-default
by either
(set-fontset-font "fontset-default" ...)
or
(set-fontset-font t ...)
Technically you could set the font
attribute of a frame
to a fontset by set-frame-font
and it works fine. But as
soon as you change any font-related attributes in default
face, like font size, your fontset in the frame attribute will be
overwritten by the font derived from default
face. So the
best way is still to just modify fontset-default
.
Further reading
- Command
list-fontsets
lists all the defined fontsets. - Command
describe-fontset
shows which font is each character assigned to in a fontset. - Manual page: Fontsets, Emacs User Manual
- Another manual page: Fontsets, Emacs Lisp Manual