25

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

Clément
  • 3,924
  • 1
  • 22
  • 37
  • 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). –  Oct 25 '17 at 05: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. –  Oct 25 '17 at 13:02
  • 2
    @kuli You are too pessimistic. See https://github.com/cpitclaudel/monospacifier – Ista Oct 30 '17 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 08 '20 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 '20 at 20:35
  • Have you got `(set-language-environment "UTF-8")` in your config? That makes my Emacs not use available glyphs when `use-default-font-for-symbols` is nil. – Arch Stanton Dec 06 '21 at 09:42

1 Answers1

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

  • 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 '19 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 '23 at 06:06