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

Async CompletionItemProvider #124

Closed
b12-144 opened this issue Feb 28, 2024 · 3 comments
Closed

Async CompletionItemProvider #124

b12-144 opened this issue Feb 28, 2024 · 3 comments

Comments

@b12-144
Copy link

b12-144 commented Feb 28, 2024

Hi, thank you for this awesome project.
How can I register an async CompletionItemProvider in order to be able to await editor.GetValue() ?
The idea is to get the editor value, parse it and then calculate the suggestions to be presented to the User, but how to do it on a Blazor Server since GetValue() needs to be awaited and editor.GetValue().Result does not work? Follow the code I'm trying to use below:

await BlazorMonaco.Languages.Global.RegisterCompletionItemProvider(JSRuntime, "csharp", 
            async (modelUri, position, context) => { //async is not valid here 
                //trying to get the editor content to calculate what should be displayed as suggestions.  
                var editorContent= await codeEditor.GetValue();
                var completionList = new CompletionList() {
                    Suggestions = [
                        new BlazorMonaco.Languages.CompletionItem {
                            LabelAsString = "Replace by THIS",
                            Kind = CompletionItemKind.Variable,
                            Detail = "this -> THIS",
                            InsertText = "THIS",
                            Preselect = true,
                            RangeAsObject = new BlazorMonaco.Range {
                                StartLineNumber = position.LineNumber,
                                StartColumn = position.Column,
                                EndLineNumber = position.LineNumber,
                                EndColumn = position.Column + 10
                            }
                        }
                    ]
                };
                return completionList;
            });

Thanks,
Bruno.

@DJSures
Copy link

DJSures commented Mar 1, 2024

The problem is that you can't await a Task in the delegate because it isn't a matching return type.

The delegate for the completion provider is (CompletionList)

  public delegate CompletionList ProvideCompletionItemsDelegate(string modelUri, Position position, CompletionContext context);

So you will not be able to await any asynchronous calls in the delegate method. The solution would be for the author to modify the CompletionItemProvider to have a ...

  public delegate Task<CompletionList> ProvideCompletionItemsDelegate(string modelUri, Position position, CompletionContext context);

@DJSures
Copy link

DJSures commented Mar 1, 2024

Here is a temporary solution. This is a CompletionItemProviderAsync to use instead...

using BlazorMonaco;
using BlazorMonaco.Languages;
using Microsoft.JSInterop;

namespace Core.MonacoEx {

  public class CompletionItemProviderAsync {

    public delegate Task<CompletionList> ProvideCompletionItemsDelegate(string modelUri, Position position, CompletionContext context);

    public delegate Task<CompletionItem> ResolveCompletionItemDelegate(CompletionItem completionItem);

    public List<string> TriggerCharacters { get; set; }

    public ProvideCompletionItemsDelegate ProvideCompletionItemsFunc { get; set; }

    public ResolveCompletionItemDelegate ResolveCompletionItemFunc { get; set; }

    [JSInvokable]
    public Task<CompletionList> ProvideCompletionItems(string modelUri, Position position, CompletionContext context) {
      return ProvideCompletionItemsFunc(modelUri, position, context);
    }

    [JSInvokable]
    async public Task<CompletionItem> ResolveCompletionItem(CompletionItem completionItem) {
      return await ResolveCompletionItemFunc?.Invoke(completionItem);
    }

    public CompletionItemProviderAsync(ProvideCompletionItemsDelegate provideCompletionItems, ResolveCompletionItemDelegate resolveCompletionItem = null) {
      ProvideCompletionItemsFunc = provideCompletionItems;
      ResolveCompletionItemFunc = resolveCompletionItem;
    }
  }
}

And you can register it with...

    public Task RegisterCompletionItemProvider(IJSRuntime jsRuntime, LanguageSelector language, CompletionItemProviderAsync.ProvideCompletionItemsDelegate provideCompletionItems, CompletionItemProviderAsync.ResolveCompletionItemDelegate resolveCompletionItem = null) {

      return RegisterCompletionItemProvider(jsRuntime, language, new CompletionItemProviderAsync(provideCompletionItems, resolveCompletionItem));
    }

And you can AWAIT all you want in the delegate method :)

@b12-144
Copy link
Author

b12-144 commented Mar 1, 2024

Hi @DJSures , thank you so much for the help!

@b12-144 b12-144 closed this as completed Mar 1, 2024
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

2 participants