Skip to content

Render bold and italic through customizable faces - #703

Merged
dakra merged 1 commit into
mainfrom
feat/bold-italic-faces
Sep 18, 2026
Merged

dakra merged 1 commit into
mainfrom
feat/bold-italic-faces

Conversation

@dakra

@dakra dakra commented Sep 18, 2026 •

Copy link
Copy Markdown
Owner

The face plist that the renderer and the comint filter put on terminal text
carried a literal :weight bold and :slant italic, so Emacs's own bold
and italic faces were never consulted. There was also nothing to customize
in their place: an anonymous plist cannot be face remapped, and setting a
weight on ghostel-default loses to the explicit attribute on the run.

Anyone whose default face is light, and who therefore softens bold to keep
the contrast bearable, got full-strength bold anyway.

Change

ghostel-bold and ghostel-italic inherit ansi-color-bold and
ansi-color-italic, the way the 16 color faces beside them inherit
ansi-color-* and the way term.el's term-bold and term-italic do. The
plist now carries :inherit ghostel-bold, :inherit ghostel-italic, or both
as a list. Customizing either those faces or bold and italic behind them
reaches terminal output.

:inherit is emitted first because Emacs merges a plist's :inherit at the
position it appears and lets later keys overwrite it. That keeps the
foreground ghostel-bold-color sets outranking anything the face carries. A
test pins that order, since a reorder would break bold coloring silently.

Faint still blends the foreground toward the background, matching Ghostty
rather than eat's :weight light. Underline, strike-through and overline keep
their literal attributes, since underline carries style and color variants
that a single inherited face cannot express.

Also corrects the README, which claimed the color faces inherit term-color-*
when they inherit ansi-color-*.

Emacs 28.2

Emacs defines ansi-color-bold with a quoted inherit, :inherit 'bold, until
29.1. Resolving that through face-attribute yields unspecified, which looks
like a broken chain, but the merge path that actually renders text properties
treats the quoted value as a face list, ignores the quote symbol and applies
bold. Checked against the 28.2 face form: setting bold to normal, light or
ultra-bold each reaches the rendered weight, and so does setting
ansi-color-bold directly.

Verification

Checked in a live graphical frame, on the font object actually chosen for the
glyphs rather than on the face plist:

  • With the default face light and bold set to normal weight, bold terminal
    text moved from the bold font face to the regular one.
  • Setting the face to semi-bold selected the semi-bold face exactly.
  • Text carrying the old literal plist still rendered bold in the same frame,
    which is the before and after side by side.
  • Italic behaves the same way.

Customizing the face updates already-rendered output on the next redisplay.
No redraw or cache clearing is needed.

make -j8 all passes. One unrelated failure,
ghostel-test-plain-link-detection-drains-in-chunks, reproduces on main
with pristine code whenever the checkout path is long enough, so it is not
from this change. It asserts that the final scan tick's requested start equals
point-min, but that start is computed before the scan widens to the logical
line start, so whether it lands exactly on point-min depends on line length,
and the test's lines embed the repository's absolute path.

Fixes #700.

@dakra
dakra force-pushed the feat/bold-italic-faces branch from c882824 to 671d9eb Compare September 18, 2026 09:01
The face plist that the renderer and the comint filter put on terminal
text carried a literal :weight bold and :slant italic, so Emacs's own
`bold' and `italic' faces were never consulted.  There was also nothing
to customize in their place, because an anonymous plist cannot be face
remapped.  Anyone whose default face is light, and who therefore softens
`bold' to keep the contrast bearable, got full-strength bold anyway.

Emit :inherit ghostel-bold and :inherit ghostel-italic instead, two new
faces inheriting `ansi-color-bold' and `ansi-color-italic' as the 16
color faces beside them inherit `ansi-color-*', and as term.el's
`term-bold' and `term-italic' do.  Customizing either those or `bold'
and `italic' behind them reaches terminal output.

:inherit comes first in the plist: Emacs merges it where it appears, so
the foreground `ghostel-bold-color' sets still outranks the inherited
face.

Faint keeps blending the foreground toward the background rather than
taking a face, matching Ghostty, and underline keeps its literal
attributes because it carries style and color variants.

Correct the README's claim that the color faces inherit `term-color-*'.

Fixes #700.
@dakra
dakra force-pushed the feat/bold-italic-faces branch from 671d9eb to d07e4bf Compare September 18, 2026 09:08
@dakra
dakra merged commit d07e4bf into main Sep 18, 2026
27 checks passed
@dakra
dakra deleted the feat/bold-italic-faces branch September 18, 2026 09:08

This branch was successfully deployed

1 active deployment
github-pages — d07e4bf0 Deployed Sep 18, 2026 by dakra via deploy #199
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Customizable font weight for bold?

1 participant