Skip to content

Conversation

jjspace
Copy link
Contributor

@jjspace jjspace commented Sep 24, 2025

Description

This is an attempt to fix the highlighting issue shown below from the feedback thread comment

Image

I can't reproduce this myself as it seems specific to Windows + Chrome. Some investigation has pointed to potentially the ligature setting affecting this so this PR is to test that. More investigation showed this was a problem with loading fonts after Monaco tried to measure them.

Issue number and link

part of #12857

Testing plan

  • Run npm run dev from the sandcastle package or npm run build-sandcastle and npm start from the project root
  • Open the editor and do some text selection
  • Click single tokens so the highlight shows up for them
  • Confirm all highlights and cursors appear where you'd expect
  • Test with multiple font and ligature enabled options in the settings

These steps reproduced the issue for me even on Linux:

  • Set settings to a larger font size to make it more obvious
  • Set font to Droid Sans, Ligatures OFF
  • REFRESH
  • Click Cesium in the editor to show the highlight in the background
  • Switch to Cascadia Code font, observe offset (however small it is)

Same works for me from
Cascadia -> Fira
Droid -> Cascadia
Jetbrains -> Cascadia

Toggling Ligatures on the selected font also usually fixed it for me

Example on Linux:
2025-09-25_12-37

Author checklist

  • I have submitted a Contributor License Agreement
  • I have added my name to CONTRIBUTORS.md
  • I have updated CHANGES.md with a short summary of my change
  • I have added or updated unit tests to ensure consistent code coverage
  • I have updated the inline documentation, and included code examples where relevant
  • I have performed a self-review of my code

Copy link

Thank you for the pull request, @jjspace!

✅ We can confirm we have a CLA on file for you.

@javagl
Copy link
Contributor

javagl commented Sep 25, 2025

Disclaimer: It's surprisingly hard to systematically test this. The behavior seems to change randomly. Building and reloading (with cache disabled) sometimes seems to pick up modified code, but sometimes not, and sometimes changing the 'Settings' seems to have an effect, and sometimes not, and sometimes only after reloading the page (not once but) multiple times. The settings appear to be stored in cookies (?). Maybe it's necessary to systematically delete them at certain points in the test procedure...?

However, I tried it out, and it didn't resolve it for me.

My strong recommendation for resolving this issue is:

Remove that "Droid Sans Mono" option, remove the "Font ligatures" toggle, and call it a day.

(If somebody cares, the response should be "Pull requests welcome!". How many substantially different forms of a "monospaced font" are there, after all ... ?)


Rant:

I'm recommending that after zooming a bit into that (with another disclaimer: I'm not a CSS/React expert, and I proudly refuse to become one). Apparently, fontLigatures can be a boolean or a string. And I tried to find out what the apparent string values are for fontLigatures are, but didn't find anything. Zero. Nothing. I randomly tried inserting the "" empty string or the string "false" and "off" at different places, but it didn't have any effect. Why did I try "off"? Well, the CSS seems to contain
--vscode-editorCodeLens-fontFeatureSettings: "liga" off
or
font-feature-settings: "liga" 0, "calt" 0;
at different places, so... why not?

My sincere condolences to everybody who has to deal with ... things ... like this:

NotCesium Font


Back on topic: It looks like the Settings defines fontLigatures to be boolean, which might have to be adjusted to inlcude string for this change anyhow.

@jjspace jjspace force-pushed the monaco-highlight-fix branch from f1342eb to 0010d7a Compare September 25, 2025 14:04
@jjspace
Copy link
Contributor Author

jjspace commented Sep 25, 2025

I did some more digging into this this morning. I'm more confident now saying this is an async issue with the font's loading after Monaco tries to measure them as mentioned in this issue microsoft/monaco-editor#392. This was linked from a few other alignment related issues too.

I've updated the code to revert the original ligature change but also delay setting the monaco font until it's loaded. The font loading API is not perfect and there might still be a better way of doing this. However, I have confirmed the issue is gone on my windows machine using the CI branch. @javagl can you please re-test this?

Other solutions might be to try and pre-load the font files but I wanted to avoid loading unnecessary fonts that people aren't using.

@javagl
Copy link
Contributor

javagl commented Sep 26, 2025

I tried it out, and despite all evil efforts of switching the fonts and toggling the ligatures, I could no longer reproduce the issue.

So this seems to fix it.

(Given that this apparently was some "synchronization/race-condition" thingy, it's hard to say for sure, but it seems to be fixed).


I looked at the code change, and cannot say anything about that. But in the future, when someone asks "Why do IT projects often take so much longer and cost so much more than originally planned?", I can say: "This 👉".
(Back in the days, I used to set a font for a component with component.setFont(new Font("Monospaced", PLAIN, 10)); 👴 )

@jjspace jjspace requested a review from ggetz September 26, 2025 15:45
const fontFace = [...documentRef.current.fonts.values()].find(
(font) => font.family === cssName && font.weight === "400",
);
if (fontFace?.status !== "loaded") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For simplicity, could we instead just wait on document.fonts.ready and then call monaco.editor.remeasureFonts()?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per MDN:

Note that the font.load() returns a promise, so we could have handled the completion of font loading by chaining then afterwards. Using document.fonts.ready can be better in some circumstances, as it is only called when all fonts in the document have been resolved and layout is complete.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ggetz Unfortunately not. That promise is a one time thing and it always returned instantly when I tried. On top of that, that promise and the other onfontloaded event handlers only trigger when the font is loaded using the fonts API and do not seem to trigger when a font is loaded because of styling changes (like how monaco updates it). I tried other arrangements of this and none worked so I settled on this as the best option.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, bummer.

@ggetz ggetz enabled auto-merge September 30, 2025 20:41
@jjspace
Copy link
Contributor Author

jjspace commented Sep 30, 2025

Auto merge won't go until it has an approve. CI passed on the last commit so I'm going to just merge

@jjspace jjspace disabled auto-merge September 30, 2025 20:55
@jjspace jjspace merged commit ecf0050 into main Sep 30, 2025
9 checks passed
@jjspace jjspace deleted the monaco-highlight-fix branch September 30, 2025 20:55
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.

3 participants