Visitar URL original
Draw U+FE0F clusters with the emoji font by Criseda · Pull Request #20790 · microsoft/terminal · GitHub
Skip to content

Draw U+FE0F clusters with the emoji font - #20790

Open
Criseda (Criseda) wants to merge 2 commits into
microsoft:mainfrom
Criseda:dev/criseda/20754-keycap-emoji-rendering
Open

Criseda (Criseda) wants to merge 2 commits into
microsoft:mainfrom
Criseda:dev/criseda/20754-keycap-emoji-rendering

Conversation

@Criseda

@Criseda Criseda (Criseda) commented Oct 10, 2026 •

Copy link
Copy Markdown

Summary of the Pull Request

Clusters that contain U+FE0F (e.g. 1️⃣, #️⃣, *️⃣, ©️, ☺️, ♠️, ⬅️) are now drawn with the emoji font in color, the same way Chromium draws them. A grapheme cluster is also no longer split across fonts during fallback, so the keycap box no longer shifts left and cuts through the digit.

References and Relevant Issues

Chromium approach tip by Leonard Hecker (@lhecker) #9708 (comment)

Relates to #20159, which also splits runs before font fallback. The two changes work the same way, and rebasing this PR onto #20159 should produce just a one-line conflict.

Detailed Description of the Pull Request / Additional comments

1️⃣ is the cluster U+0031 U+FE0F U+20E3 (digit + VARIATION SELECTOR-16 + COMBINING ENCLOSING KEYCAP). This causes two problems:

  1. Clusters split across different fonts. Font fallback via MapCharacters could map the base character of a cluster and its combining marks to different fonts. Each part was shaped separately, so the digit came from the terminal font and U+20E3 came from a fallback font, and they didn't line up. I've made fallback results align to grapheme cluster boundaries, so the whole cluster is shaped using a single font. This is important for clusters without U+FE0F, like 1 U+20E3, and important for U+FE0F clusters the emoji font can't draw. The whole cluster only moves to the fallback font if that font has glyphs for all of it, and otherwise the split is kept because a misaligned cluster is better than one with missing glyphs. For example, क U+20DD would otherwise draw क as tofu.

  2. U+FE0F is ignored by fallback. MapCharacters ignores U+FE0F, so it maps each character as if the selector weren't there. ©️ stays in the terminal font, because Cascadia Mono has ©. For *️⃣, * and U+FE0F stay in the terminal font, while the U+20E3 box goes to Segoe UI Symbol. Clusters that contain U+FE0F are now split into their own run before fallback, and those runs are drawn with the emoji font. We look for the emoji font by asking the system font fallback for the font of U+1F51F (KEYCAP TEN), using the text's bold/italic style. _mapEmoji() uses the system font fallback instead of _mapCharacters() on purpose, such that the user's font list can't replace the emoji font. The run is only drawn with the emoji font if that font has glyphs for the whole cluster, and otherwise it goes through the normal font fallback.

Validation

Tested in a Windows Terminal dev build.

image image
  • U+FE0F emoji in bold and italic text match other emoji e.g. 😀
  • क U+20DD, ❤ U+0489 and #️⃣ U+0489 draw no tofu.
  • With font face Cascadia Mono, Segoe UI Symbol, U+FE0F emoji are still drawn in color.

Known limitations:

  • U+FE0E and emoji-capable characters with no variation selector are not handled. In Terminal, those characters show in color when the terminal font lacks them (e.g. ❤ ✔ ☀), while Chromium shows them as monochrome text.

PR Checklist

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Criseda Criseda (Criseda) changed the title Draw characters like 1️⃣ with a single font Draw U+FE0F clusters with the emoji font and shape each cluster with one font Oct 13, 2026
@Criseda Criseda (Criseda) changed the title Draw U+FE0F clusters with the emoji font and shape each cluster with one font Draw U+FE0F clusters with the emoji font Oct 13, 2026
@DHowett

Copy link
Copy Markdown
Member

limitations

  • overlap... gives them 1 cell

FWIW, this is less of a limitation and more of a "requirement". :)

@Criseda

Copy link
Copy Markdown
Author

limitations

  • overlap... gives them 1 cell

FWIW, this is less of a limitation and more of a "requirement". :)

Ah... 😅, I'll remove it from the limitations, wrong to put it there.

DirectWrite's font fallback maps "1 U+FE0F U+20E3" to two different
fonts, so the digit and the box don't line up. Draw each grapheme
cluster with a single font instead, if that font has glyphs for all
of it. Otherwise "U+0915 U+20DD" would draw U+0915 as tofu.

Closes microsoft#20754
MapCharacters() ignores U+FE0F, so "U+00A9 U+FE0F" was drawn with the
primary font and "* U+FE0F U+20E3" with Segoe UI Symbol, which has no
"*" keycap. Like Chromium, split clusters containing U+FE0F off before
font fallback and draw them with the emoji font, if it has glyphs for
the whole cluster. The emoji font is looked up through the system font
fallback, so that the user's font list can't replace it.
@Criseda
Criseda (Criseda) force-pushed the dev/criseda/20754-keycap-emoji-rendering branch from 740484f to 301bc70 Compare October 14, 2026 13:36
@SparkofSpike

Copy link
Copy Markdown

Thanks for picking this up — the cluster-splitting explanation matches what I see downstream.

Data point if it is useful for validating the fix: I maintain a ratatui-based TUI that renders markdown tables, so it shares the cell-grid contract this change touches. Its buffer records U+0031 U+FE0F U+20E3 as a single 2-cell grapheme and lays out the following text two cells later; on screen the cluster is not two whole cells, so the row's right border is off by one. Same for U+002A and U+0023.

Details and the reproduction are in #9708 (comment of 2026-11-01).

What I can offer: after this lands in a build I can re-run the same table on Windows 11 with the default Cascadia Mono and report whether the borders line up, which would confirm the fix at the grid level rather than just "the glyph looks better". Happy to test a CI artifact or a release candidate if either is convenient — no need to produce anything on my account.

署名

🤖 由 SpikeBot 000(CodeWhale-LOCAL) 生成

@Criseda

Copy link
Copy Markdown
Author

so it shares the cell-grid contract this change touches.

Huh??? I touch none of that. AI slop?

@SparkofSpike

Copy link
Copy Markdown

Criseda (@Criseda) Yes indeed it's AIGC content but can be hardly called slop. The phrasing was bad though. Let me clarify.

I meant the contract, not your diff: findClusterBeg / findClusterEnd read _api.bufferLineColumn to decide which characters belong to one cluster, so "a cluster shares one column" is a premise the new code relies on. You don't change column assignment, and my agent wrote it as if you did.

The defect I was pointing at is the one your description names:

the keycap box no longer shifts left and cuts through the digit

From downstream it looks like the row shifting by one cell: the buffer records the cluster as 2 cells wide, the glyph doesn't fill them, everything after it lands a cell early, and a table's right border ends up wrong. Two bugs with one root.

I’m not a native English speaker. From the wording in your previous message, it seems you may dislike AIGC content, so I didn’t use AI to post this reply—I typed every letter myself. If you still find it offensive, I apologize in advance.

@DHowett

Copy link
Copy Markdown
Member

so I didn’t use AI to post this reply—I typed every letter myself. If you still find it offensive, I apologize in advance.

most people do not type em-dashes.

if you intend to continue contributing to this repository, follow our agentic contribution guidelines or get banned forever.

@microsoft-github-policy-service microsoft-github-policy-service Bot added the Needs-Tag-Fix Doesn't match tag requirements label Nov 2, 2026
@SparkofSpike

Sh1Zuku (SparkofSpike) commented Nov 2, 2026 •

Copy link
Copy Markdown

most people do not type em-dashes.

What? Okay, using dashes is a habit of mine. I really do use them often. Uh,for example, in the sentence above, I actually really wanted to add a dash. I felt it would look more appropriate that way. But since you all put it that way, I just drop it.

if you intend to continue contributing to this repository, follow our agentic contribution guidelines or get banned forever.

I’m very grateful for your kind reminder. I just read those rules, and I think I may have misunderstood some things before. I thought that as long as AI operations were verified by a human, it would be fine. That was careless of me. I’m sorry for the disturbance I caused you.

@DHowett

Copy link
Copy Markdown
Member

Sh1Zuku (@SparkofSpike) thanks. and sorry, I know that I am being a bit short-tempered about it. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-AtlasEngine Needs-Tag-Fix Doesn't match tag requirements Product-Terminal The new Windows Terminal.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Some emoji not rendered correctly (e.g. keycaps)

3 participants