Skip to content
A "global face scaling" library for Emacs
Emacs Lisp
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Global face scaling


The standard text-scale mode provides functions to increase and decrease font sizes. But as near as I can tell, it only works on the default font. I often have buffers with several faces and find it annoying that the standard functions don’t change all the faces.

It’s quite possible that someone else has done a better job of this. I found a stack overflow question that seemed relevant, but after playing with it for a bit, I couldn’t see how to apply it to an arbitrarily large set of faces.

This README file is a literate programming version of emacs-gfs.el. Do not edit the emacs lisp file directly.

Resizeable faces

So as an amusement this evening, I decided to write some functions that would “brute force” it. First, I work out a list of all the fonts that should be scaled: that’s all fonts that have an explicit height except the ones explicitly excluded.

(defun gfs/resizeable-faces ()
  "Return the set of faces that can be resized.
A face can be resized if it is not in the list of ignorable
faces and has an explicit height."
  (let ((faces (face-list))
        (resize '()))
    (while faces
      (if (and (not (member (car faces) gfs/resizeable-ignore-faces))
               (integerp (face-attribute (car faces) :height)))
          (setq resize (append resize (list (car faces)))))
      (setq faces (cdr faces)))

Ignored faces

I added a list of excluded fonts in an effort to avoid scaling the mode line and the minibuffer. It’s only been a partial success because I haven’t yet worked out what face is used for the minibuffer.

(defvar gfs/resizeable-ignore-faces
"Faces named in this list will not be scaled.")

Because faces inherit, if we want to avoid scaling some faces, we have to make sure that they have a fixed size. Generally, this means following the inheritance chain until we find a face with a specified size.

If we bottom out and don’t find any size, we have to have a default, so here it is:

(defvar gfs/default-face-height 180
"Default height for faces with no explicit height.")

I have no idea how generally useful “180” is. It works for me, but YMMV.

Scaling factor

The gfs/magnify-factor controls how much scaling is applied.

(defvar gfs/magnify-factor 1.2
  "The scaling factor.
Scaling is accomplished by multiplying (or dividing) the face
:height by this factor.")

Scaling limits

The gfs/face-min-height and gfs/face-max-height control the magnification limits. These are aribrary values. The face-remap.el library attempts to compute practical limits from the font and display size, but I haven’t bothered.

(defvar gfs/face-min-height 100
  "The minimum face :height.
If an attempt is made to scale the face height below this
threshold, this value will be used.")
(defvar gfs/face-max-height 1000
  "The maximum face :height.
If an attempt is made to scale the face height above this
threshold, this value will be used.")

There’s a practical consideration in the scaling limits. Scaling by a common factor preserves the relative sizes of the faces until the limits are reached. Crossing either of the limits, normalizes faces to the same size and the relative scale is irretrievably lost.

Interactive functions

(defun gfs/shrink-faces ()
  "Shrink all applicable faces by the magnification factor."
  (gfs--/magnify-faces (- gfs/magnify-factor)))
(defun gfs/magnify-faces ()
  "Magnify all applicable faces by the magnification factor."
  (gfs--/magnify-faces gfs/magnify-factor))

Assembled library

This code is assembled together with some boilerplate and private functions to build the final library.

You can’t perform that action at this time.