emacs/var/elfeed/db/data/28/28435295fe0fe5c782df766f0377a9d1c10f57e5
2022-01-03 12:49:32 -06:00

100 lines
4.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p>In a recent entry on <a href="https://protesilaos.com/codelog/2020-07-17-emacs-mixed-fonts-org/">configuring mixed
fonts</a>,
I outlined how to specify your typefaces of choice by configuring the
<code>default</code>, <code>variable-pitch</code>, and <code>fixed-pitch</code> faces. This would allow
you to benefit from variegated typography, such as having paragraph text
rendered in a proportionately spaced font, while inline code is
displayed as monospaced.</p>
<p>The overall approach of controlling the three basic faces is fine, but
the code I shared had the unintended consequence of breaking the
built-in <code>text-scale-adjust</code> command (by default bound to <code>C-x C-+</code>,
<code>C-x C--</code>, <code>C-x C-0</code>). Here I issue a corrective to the technique that
was used before.</p>
<h2>The code that breaks text-scale-adjust</h2>
<p>This is the gist of what I was using for several months:</p>
<pre><code class="language-elisp">(set-face-attribute 'default nil :font "Hack-16")
(set-face-attribute 'fixed-pitch nil :font "Hack-16")
(set-face-attribute 'variable-pitch nil :font "FiraGO-16")
</code></pre>
<p>A variant of the above can be expressed as follows:</p>
<pre><code class="language-elisp">(set-face-attribute 'default nil :family "Hack" :height 160)
(set-face-attribute 'fixed-pitch nil :family "Hack" :height 160)
(set-face-attribute 'variable-pitch nil :family "FiraGO" :height 160)
</code></pre>
<p>If you set fonts this way and try to use <code>text-scale-adjust</code> in a buffer
with mixed fonts, you will notice that only the main text, affected by
the <code>default</code> face, gets scaled. The rest retain their height—not good.</p>
<p>This is because of a hard-wired assumption in the <code>text-scale-adjust</code>
command to only target the <code>default</code> face: <code>variable-pitch</code> and
<code>fixed-pitch</code> remain in tact, thus breaking our expectations.</p>
<p>The problem consists in the fact that we are specifying an absolute size
for each font family. Whereas we should be benefiting from relative
sizes that all have a single point of reference, which is easy to do.</p>
<h2>The recommended way to set font heights with faces</h2>
<p>Let us re-purpose the sample code from the previous section, in order to
get the behaviour we expect out of <code>text-scale-adjust</code>.</p>
<pre><code class="language-elisp">(set-face-attribute 'default nil :font "Hack-16")
(set-face-attribute 'fixed-pitch nil :family "Hack" :height 1.0)
(set-face-attribute 'variable-pitch nil :family "FiraGO" :height 1.0)
</code></pre>
<p>A alternative to the above is this:</p>
<pre><code class="language-elisp">(set-face-attribute 'default nil :family "Hack" :height 160)
(set-face-attribute 'fixed-pitch nil :family "Hack")
(set-face-attribute 'variable-pitch nil :family "FiraGO")
</code></pre>
<p>Notice that we set an absolute point size only for the <code>default</code> face.
While we instruct Emacs to interpret the height of <code>fixed-pitch</code> and
<code>variable-pitch</code> as relative to that constant. Therein lies the
difference between integer and floating point values for the <code>:height</code>
attribute (remember to consult <code>C-h f set-face-attribute</code>).</p>
<p>Strictly speaking, the <code>:height 1.0</code> is not necessary, unless you are
overriding a prior state. It is what applies when the specification is
omitted. Rendering it explicit here helps us spot the subtleties in
notation and be clear about what is at play.</p>
<h2>Details are tricky</h2>
<p>I was using the old technique for several months, adjusting fonts
through a bespoke function of mine that altered their absolute sizes.
What inspired me to investigate and eventually address this issue is a
particular statement in the doc string of <code>set-face-attribute</code>:</p>
<blockquote>
<p>Note that for the default face, you must specify an absolute height
(since there is nothing for it to be relative to).</p>
</blockquote>
<p>Which implied that if the <code>default</code> was a constant, all other faces
could simply have a relative height. This is because of the peculiar
nature of that face to serve as the foundation upon which all others are
established. As such, a <code>:height</code> with a floating point is a multiple
of the <code>default</code> font size. Simple and effective!</p>
<p>I am now happily using <code>text-scale-adjust</code> in tandem with the tools I
mentioned in my recent video about <a href="https://protesilaos.com/codelog/2020-07-16-emacs-focused-editing/">“Focused editing” for
Emacs</a>.</p>
<p>This information is also documented in the <a href="https://protesilaos.com/emacs/modus-themes/">official manual of the Modus
themes</a> because they are designed
to cope well with mixed font scenaria, such as when the user decides to
enable the built-in <code>variable-pitch-mode</code>.</p>