Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LineNumber property #35

Open
albertoVieiraNeto opened this issue Mar 4, 2021 · 10 comments
Open

LineNumber property #35

albertoVieiraNeto opened this issue Mar 4, 2021 · 10 comments

Comments

@albertoVieiraNeto
Copy link

Hi, i'm trying to "bind" two editors together, this just means that the last "line number" of the first editor will become the first linenumber of the second editor, just to allow me to have a "read only" area on the "editor"

image
should this work? knowing that most of this will run as "interop"

image
a code very "similiar" will run on the "playground" without issues.

looking at the "create" function used in the JsInterop File, maybe that the function is being set as a "string".

am i doing something wrong?

@serdarciplak
Copy link
Owner

Currently, C# LineNumbers property is just a string, but it can be a function as well in JavaScript. I'll figure out a way to achieve the same thing in C# and publish a new version of BlazorMonaco this weekend.

@victorperez2911
Copy link

Hi @serdarciplak

Any news on this subject?

@serdarciplak
Copy link
Owner

Sorry. I couldn't find time for this yet. But I see this as a priority item for this repo. I'll solve it asap.

@serdarciplak
Copy link
Owner

I've added support for this in v2.1.0. Just set the LineNumbersLambda property of the construction options to a lambda and it will be called by the editor when needed.

@albertoVieiraNeto
Copy link
Author

albertoVieiraNeto commented Apr 15, 2021

Hi @serdarciplak and thanks for the attention.

I was testing, and when using the the new property LineNumbersLambda when the page loads the components, it throws the following:

image

image

My project runs on blazor-server-side, this functionality should be supported in this model?

@serdarciplak
Copy link
Owner

I haven't tested it on a server-side app. I'll check it out.

@serdarciplak serdarciplak reopened this Apr 16, 2021
@victorperez2911
Copy link

Hi @serdarciplak

Did you manage to take the test?

@psantosl
Copy link

psantosl commented Dec 4, 2024

Any news about this? I'm still seeing it running in server-side mode

@psantosl
Copy link

How to customize line numbers using Blazor server

Tried to patch BlazorMonaco

Ok, I first tried to simply setup a callback using Blazor Server, but it didn't work throwing an exception saying that the InvokeMethod must be invokeMethodAsync

https://github.com/serdarciplak/BlazorMonaco/blob/master/BlazorMonaco/wwwroot/jsInterop.js#L112

So I tried to fork and patch my own version modifying the code to do invokeMethodAsync.

Well, it creates a promise so you can wait it or do a "then" and then see your callback code in C# being invoked... but it is impossible to return the value to the callback because it doesn't allow any form of async code (you can put a "then" and log the result and see it works, but it is not possible to return it).

Of course, the invokeMethod is good for webassembly, but won't work in Blazor server.

I wasn't able to figure out a solution this way, even checked the Monaco code but making this "lineNumbers" callback async would imply tons of changes afaik.

Workaround using some Javascript code

Basically, pass an array of strings or whatever to javascript and set the callback there.

On my EditorOnDidInit I invoked this code:

await JSRuntime.InvokeVoidAsync("setLineNumbersEditorCallback", "resultEditor", new int[]{});

where 'resultEditor' is the Id of my component:

       <StandaloneCodeEditor 
            Id="resultEditor" 
            @ref="_resultEditor" 
            ConstructionOptions="ResultEditorOptions" 
            OnDidInit="EditorOnDidInit"
            OnMouseDown="ResultEditorOnMouseDown" />

Then I added this javascript code in my page:

<script>
  function setLineNumbersEditorCallback(editorName, lines) {

    const editorElement = document.getElementById(editorName);
    if (!editorElement) {
        console.error(`Editor with ID "${editorId}" not found`);
        return;
    }

    // Get the actual Monaco editor instance from the global editors
    const editorInstance = monaco.editor.getEditors().find(e => e.getContainerDomNode() === editorElement);
    if (editorInstance) {
        editorInstance.updateOptions({ lineNumbers: (num) => {
            return lines[num];
        } 
        });    
    } else {
        console.error('Editor instance not found');
    }
  }
</script>

Actually my code is different because I pass a list of deleted lines, but you get the idea.

Hope it helps.

@serdarciplak
Copy link
Owner

I finally had time to have a look at this and I think I have a fix. Here is an explanation of the new flow;

  • A new JS-side cache is added for the line numbers.
  • When MonacoEditor requests a line number for the first time, a dotnet call is initiated and an empty string is returned as the line number.
  • When an async dotnet call completes, it adds the returned value to the JS-side cache.
  • When all active dotnet calls complete, the line numbers are redrawn. In this redraw, the lineNumbers JS function returns the cached values and Monaco Editor displays these values as the line numbers.
  • Also, a new editor instance method named ReloadLineNumbers is added. It can be used if the dotnet side needs to reset the JS-side cache and provide new line numbers.

@psantosl It would be great if you can review the PR #147 as you already know the context here.

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

No branches or pull requests

4 participants