Emacs “Global Face Scaling”

Volume 4, Issue 3; 08 Jan 2020

An Emacs customization to scale all of the faces at the same time.

To be honest, I don’t need to scale fonts facesEmacs calls the collection of attributes (size, shape, color, font, etc.) associated with a bit of displayed text a “face”. I’m trying to use that term consistently in this post, even though the font height is the only thing I’m actually changing. in Emacs very often. I have very occasionally projected an Emacs buffer during a conference or presentation and wished to change the face height.

I usually got by with Options→Set Default Font. Eventually, I learned about text-scale mode and bound the predictable keys, C-+ and C--​, to increase and decrease the face height in steps. As far as I can tell, text-scale mode only changes the height of the default face. Back in the day, when most of my emacs buffers were a single, fixed-width face, that would have been fine.

Today, many of my important buffers have several faces at different sizes. In fact, it was a brief investigation of org-tree-slide over the weekend that started me down this road. I’m intrigued by the idea of just using Emacs to make presentations.

It seems like the limitations of the built-in text scaling would be problematic to lots of people, so I did a little web searching for a workaround. I found a stack overflow question that seemed relevant, and indeed it works for just a face or two, but I wasn’t pleased with the results of my efforts to apply it to an arbitrarily large set of faces.

It’s quite possible that someone else has done a better job of this, but I didn’t find it before solving the problem myselfNo, it’s not a displacement activity. Shut up. seemed more amusing that continued searching.

Thus, emacs-gfs was born.

Here’s how it works. First, find all the faces that have a defined height (an integer). Faces can inherit from one another, so they don’t all have a defined height, and the height can be a floating point scaling factor or a function. I’m assuming if I scale the ones that have a fixed height, inheritance, scaling, and functions will “do the right thing”.

One complication: I don’t necessarily want to scale the mode line or the minibuffer. To avoid scaling these, I added a list of faces that are ignored for scaling.

One more complication: to avoid scaling these faces, I have to fix their height so that, for example, scaling a face they inherit from doesn’t cause them to be scaled. I attempt to do this by following the inheritance chain until I find a heightKnown limitation: if any of them have a height that’s defined with a scaling factor or a function, that’s going to get overwritten by the default height. and the fixing them to have that height. Some faces bottom out without having any defined height at all. (I have no idea how Emacs decides what height the should be.) If that happens, I assign them a default height.

Right. Now there’s a list of faces to scale. If you run gfs/magnify-faces, they’re all scaled up by gfs/magnify-factor. If you run gfs/shrink-faces, they’re all scaled down by that factor. Bind those functions to C-+ and C-- and you can easily scale all the faces in the display up or down.

There are minimum and maximum scaling sizes. I gather that if you scale a face down to less than 1 pixel in height, or larger than 0xffff pixels, bad will happen. If you scale past either of these limits (gfs/face-min-height and gfs/face-max-height), the relative height of faces will be lost.