microsoft / monaco-editor

A browser based code editor
https://microsoft.github.io/monaco-editor/
MIT License
40.48k stars 3.6k forks source link

[Bug] Guidelines not rendering in correct positions #4695

Open bananensplit opened 1 month ago

bananensplit commented 1 month ago

Reproducible in vscode.dev or in VS Code Desktop?

Reproducible in the monaco editor playground?

Monaco Editor Playground Link

No response

Monaco Editor Playground Code

No response

Reproduction Steps

  1. Get the latest source from the repository. The follwing will download the package as a .tgz file into your working directory and extract it:

    npm pack monaco-editor
    tar xvf monaco-editor-0.52.0.tgz
  2. Paste the code below into an index.html file in the same directory where you downloaded the code to:

    <!DOCTYPE html>
    <html>
    <head>
    <title>Monaco Test</title>
    <link rel="stylesheet" type="text/css" data-name="vs/editor/editor.main" href="package/min/vs/editor/editor.main.css">
    
    <style>
        /* In our codebase this is set globally and cannot be changed */
        * {
            font-family: arial, serif;
            font-size: 14px;
        }
    
        /* I used this to reset all styles that might colide with editor.main.css. This worked beautifully. */
        .monaco-editor, .monaco-editor *, .monaco-diff-editor, .monaco-diff-editor * {
            all: revert;
        }
    </style>
    </head>
    <body>
    <div id="container" style="width: 800px; height: 600px; border: 1px solid grey"></div>
    
    <script> var require = {"paths": {"vs": window.location.origin + "/monaco-editor-0.52.0/dev/vs"}};</script>
    <script src="package/min/vs/loader.js" language="javascript" type="text/javascript"></script>
    <script src="package/min/vs/editor/editor.main.js" language="javascript" type="text/javascript"></script>
    
    <script>
        var editor = monaco.editor.create(document.getElementById('container'), {
            value: ['function x() {', '\tconsole.log("Hello world!");', '\t{', '\t\tconsole.log("Indentedline");', '\t}', '}'].join('\n'),
            language: 'javascript',
        });
    </script>
    </body>
    </html>
  3. Open the index.html file using VSCode LiveServer.

  4. Then the problem should already be appearent.

Actual (Problematic) Behavior

The guideline is drawn in the wrong spot: image

Expected Behavior

The guideline should be drawn like this: image

Additional Context

No response

bananensplit commented 1 month ago

I have already looked into this and I think the problem is the way the character widths in charWidthReader.ts are calculated.

The DomCharWidthReader uses the _createDomElements Method to create some test elements. It creates three div-elements (one for each font-style: bold, italic and normal), which then are filled with a bunch of span-elements that each contain a different character of which the width is to be measured. The configured font-style (fontFamily, fontSize, etc.) is applied to the three div-elements, which are then all wrapped into another div and appended to the body.

The created test element (stored in this._container) looks something like this:

<div style="position: absolute; top: -50000px; width: 50000px;">
    <div
        style="font-family: Consolas, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; font-variation-settings: normal; line-height: 16px; letter-spacing: 0px;">
        <br>
        <span>iiiiiiiiiiiiiiiiiiiiii</span>
        <!-- a bunch more <br><span>...</span> -->
    </div>
    <div
        style="font-family: Consolas, &quot;Courier New&quot;, monospace; font-weight: bold; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; font-variation-settings: normal; line-height: 16px; letter-spacing: 0px;">
        <br>
        <span>|||||||||||||||||||||||<span>
        <!-- a bunch more <br><span>...</span> -->
    </div>
    <div
        style="font-family: Consolas, &quot;Courier New&quot;, monospace; font-weight: normal; font-size: 12px; font-feature-settings: &quot;liga&quot; 0, &quot;calt&quot; 0; font-variation-settings: normal; line-height: 16px; letter-spacing: 0px; font-style: italic;">
        <br>
        <span>|||||||||||||||||||</span>
        <!-- a bunch more <br><span>...</span> -->
    </div>
</div>

You will notice that the three div-elements have the styles applied, which the span-elements in them should inherit. And here is the problem: When somebody uses the * CSS-Selector to apply global styles it takes precedence to the inherited style of the parent. This means that even though the div-elements have the correct styles applied, the span-elements, which are actually used to measure the characters, don't inherit them.

This is also visible in the DevTools of the browser when you select one of the span-elements: image.

Potential Solutions

I am very open to a discussion and am also very motivated to implement the change. Thanks for reading :)