Skip to main content

10.4.1 Theming Faces

The default theme uses blue for local branches, green for remote branches, and goldenrod (brownish yellow) for tags. When creating a new theme, you should probably follow that example. If your theme already uses other colors, then stick to that.

In older releases these reference faces used to have a background color and a box around them. The basic default faces no longer do so, to make Magit buffers much less noisy, and you should follow that example at least with regards to boxes. (Boxes were used in the past to work around a conflict between the highlighting overlay and text property backgrounds. That’s no longer necessary because highlighting no longer causes other background colors to disappear.) Alternatively you can keep the background color and/or box, but then have to take special care to adjust magit-branch-current accordingly. By default it looks mostly like magit-branch-local, but with a box (by default the former is the only face that uses a box, exactly so that it sticks out). If the former also uses a box, then you have to make sure that it differs in some other way from the latter.

The most difficult faces to theme are those related to diffs, headings, highlighting, and the region. There are faces that fall into all four groups - expect to spend some time getting this right.

The region face in the default theme, in both the light and dark variants, as well as in many other themes, distributed with Emacs or by third-parties, is very ugly. It is common to use a background color that really sticks out, which is ugly but if that were the only problem then it would be acceptable. Unfortunately many themes also set the foreground color, which ensures that all text within the region is readable. Without doing that there might be cases where some foreground color is too close to the region background color to still be readable. But it also means that text within the region loses all syntax highlighting.

I consider the work that went into getting the region face right to be a good indicator for the general quality of a theme. My recommendation for the region face is this: use a background color slightly different from the background color of the default face, and do not set the foreground color at all. So for a light theme you might use a light (possibly tinted) gray as the background color of default and a somewhat darker gray for the background of region. That should usually be enough to not collide with the foreground color of any other face. But if some other faces also set a light gray as background color, then you should also make sure it doesn’t collide with those (in some cases it might be acceptable though).

Magit only uses the region face when the region is "invalid" by its own definition. In a Magit buffer the region is used to either select multiple sibling sections, so that commands which support it act on all of these sections instead of just the current section, or to select lines within a single hunk section. In all other cases, the section is considered invalid and Magit won’t act on it. But such invalid sections happen, either because the user has not moved point enough yet to make it valid or because she wants to use a non-magit command to act on the region, e.g. kill-region.

So using the regular region face for invalid sections is a feature. It tells the user that Magit won’t be able to act on it. It’s acceptable if that face looks a bit odd and even (but less so) if it collides with the background colors of section headings and other things that have a background color.

Magit highlights the current section. If a section has subsections, then all of them are highlighted. This is done using faces that have "highlight" in their names. For most sections, magit-section-highlight is used for both the body and the heading. Like the region face, it should only set the background color to something similar to that of default. The highlight background color must be different from both the region background color and the default background color.

For diff related sections Magit uses various faces to highlight different parts of the selected section(s). Note that hunk headings, unlike all other section headings, by default have a background color, because it is useful to have very visible separators between hunks. That face magit-diff-hunk-heading, should be different from both magit-diff-hunk-heading-highlight and magit-section-highlight, as well as from magit-diff-context and magit-diff-context-highlight. By default we do that by changing the foreground color. Changing the background color would lead to complications, and there are already enough we cannot get around. (Also note that it is generally a good idea for section headings to always be bold, but only for sections that have subsections).

When there is a valid region selecting diff-related sibling sections, i.e. multiple files or hunks, then the bodies of all these sections use the respective highlight faces, but additionally the headings instead use one of the faces magit-diff-file-heading-selection or magit-diff-hunk-heading-selection. These faces have to be different from the regular highlight variants to provide explicit visual indication that the region is active.

When theming diff related faces, start by setting the option magit-diff-refine-hunk to all. You might personally prefer to only refine the current hunk or not use hunk refinement at all, but some of the users of your theme want all hunks to be refined, so you have to cater to that.

(Also turn on magit-diff-highlight-indentation, magit-diff-highlight-trailing, and magit-diff-paint-whitespace; and insert some whitespace errors into the code you use for testing.)

For e.g. "added lines" you have to adjust three faces: magit-diff-added, magit-diff-added-highlight, and smerge-refined-added. Make sure that the latter works well with both of the former, as well as smerge-other and diff-added. Then do the same for the removed lines, context lines, lines added by us, and lines added by them. Also make sure the respective added, removed, and context faces use approximately the same saturation for both the highlighted and unhighlighted variants. Also make sure the file and diff headings work nicely with context lines (e.g. make them look different). Line faces should set both the foreground and the background color. For example, for added lines use two different greens.

It’s best if the foreground color of both the highlighted and the unhighlighted variants are the same, so you will need to have to find a color that works well on the highlight and unhighlighted background, the refine background, and the highlight context background. When there is an hunk internal region, then the added- and removed-lines background color is used only within that region. Outside the region the highlighted context background color is used. This makes it easier to see what is being staged. With an hunk internal region the hunk heading is shown using magit-diff-hunk-heading-selection, and so are the thin lines that are added around the lines that fall within the region. The background color of that has to be distinct enough from the various other involved background colors.

Nobody said this would be easy. If your theme restricts itself to a certain set of colors, then you should make an exception here. Otherwise it would be impossible to make the diffs look good in each and every variation. Actually you might want to just stick to the default definitions for these faces. You have been warned. Also please note that if you do not get this right, this will in some cases look to users like bugs in Magit - so please do it right or not at all.