26

TL;DR: What's a simple way to reliably say: use Consolas as the default font, FreeMono for the characters unsupported by Consolas, and Symbola for characters unsupported by both?

Since my main programming font does not cover all the mathematical symbols I need, I initially set up font fallback as shown below:

(set-fontset-font t 'unicode (font-spec :name "FreeMono") nil 'append)
(set-fontset-font t 'unicode (font-spec :name "Symbola") nil 'append)

Unfortunately this also changed the font for some of the character that my main font supports, so I changed it to

(set-fontset-font t 'unicode (font-spec :name "Consolas") nil)
(set-fontset-font t 'unicode (font-spec :name "FreeMono") nil 'append)
(set-fontset-font t 'unicode (font-spec :name "Symbola") nil 'append)

If my understanding is correct, this should ensure that characters that Consolas cannot handle are handled by FreeMono, unless FreeMono doesn't have them, in which case they should be displayed using Symbola. It is also my understanding that t does the same as "fontset-default" above.

Unfortunately, there were still cases where the right font wasn't selected; I found that changing to

(set-fontset-font t 'unicode (font-spec :name "Consolas") nil)
(set-fontset-font t 'unicode (font-spec :name "FreeMono") nil 'append)
(set-fontset-font t 'unicode (font-spec :name "Symbola") nil 'append)
(set-fontset-font "fontset-startup" 'unicode (font-spec :name "Consolas") nil)
(set-fontset-font "fontset-startup" 'unicode (font-spec :name "FreeMono") nil 'append)
(set-fontset-font "fontset-startup" 'unicode (font-spec :name "Symbola") nil 'append)

worked better, but not always: changing the font size using

(set-face-attribute 'default nil :height some-size)

caused the fallbacks to be ignored, due to new fontsets being created.

My current solution is to do

(set-fontset-font fontset 'unicode (font-spec :name "Consolas") nil)
(set-fontset-font fontset 'unicode (font-spec :name "FreeMono") nil 'append)
(set-fontset-font fontset 'unicode (font-spec :name "Symbola") nil 'append)

on each fontset (fontset-list), after each font size change.

What's the proper way to set font fallback?

Note: for testing purposes, here are a few math characters: ℕ𝓟⧺×≠≥≤±¬∨∧∃∀λ⟿⟹⊥⊤⊢
References: Emacs manual on fontsets and on modifying fontsets

6
  • 2
    I have a thought which not really solves your problem, but –– if you need the mathematical etc. symbols for theoremes and scientific documents, why don't you use TeX and AucTeX for that? It would make hassling with X (or Mac or Windows, depending on what you run) font fallbacks unnecessary and provide you with high quality documents and snippets (eg. for org mode).
    – user17303
    Oct 25, 2017 at 5:28
  • afterthought: a UTF-8 font with a full character set should remove your problem entirely (eg. GNU Unifont), and when there's the choice between fancy font and the glyphs required, I'd choose the latter.
    – user17303
    Oct 25, 2017 at 13:02
  • 2
    @kuli You are too pessimistic. See github.com/cpitclaudel/monospacifier
    – Ista
    Oct 30, 2017 at 12:50
  • 1
    I cannot remember where I read it, but I believe Eli Zaretskii responded to a similar question somewhere. You are thinking about fontset in the wrong way. Emacs does not actually check for every character it displays whether a font knows how to display it or not. That would be too computationally intensive. So there is no "fallback" mechanism per se. You should set your default font and then modify the default fontset manually in certain ranges to display using different fonts. This procedure is manual or maybe the package unicode can help.
    – GenaU
    Jan 8, 2020 at 10:57
  • 1
    @GenaU I may be misunderstanding, but Emacs does check; just not every font, only the ones that appear in a fontset.
    – Clément
    Jan 10, 2020 at 20:35

1 Answer 1

0

M-x customize-variable face-font-family-alternatives

There's a list that looks something like:

(("Monospace" "courier" "fixed")
 ("Monospace Serif" "Courier 10 Pitch" "Consolas" "Courier Std" "FreeMono" "courier" "fixed")
 ("courier" "CMU Typewriter Text" "fixed")
 ("Sans Serif" "helv" "helvetica" "arial" "fixed")
 ("helv" "helvetica" "arial" "fixed"))

Add your sequence in customize buffer interface:

("Consolas" "FreeMono" "Symbola")

If a given family is specified but does not exist, this variable specifies alternative font families to try. Each element should have this form:

 (FAMILY ALTERNATE-FAMILIES...)

If FAMILY is specified but not available, Emacs will try the other families given in ALTERNATE-FAMILIES, one by one, until it finds a family that does exist.

How to use face-font-family-alternatives:

In you buffer: M-x set-frame-font

Choose a font from the list. Chosen font will define what font search sequence from face-font-family-alternatives to use. In this example Consolas.

To check what font family was used to display a character: M-x describe-char

2
  • Thanks! But I don't think this answers the question. AFAICT, the configuration you suggested will use FreeMono if the Consolas font is not available, but it won't fallback to FreeMono for characters not supported by Consolas.
    – Clément
    Jan 16, 2019 at 21:21
  • 1
    This works for me: the alternatives seem to be applied to individual glyphs despite the documentation being phrased in a way that suggests that the alternatives are only considered if an entire font is unavailable.
    – Zoltan
    Jul 10, 2023 at 6:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.