5

I am using Roslyn to create a C# scripting control with IntelliSense.

I am generally very happy with the results I am getting, however, the recommended symbols don't include keywords such as for and if et cetera and also don't contain type aliases such as int, when it includes Int32.

More specifically, I am using Microsoft.CodeAnalysis.Recommendations, that is:

Recommender.GetRecommendedSymbolsAtPositionAsync(mySemanticModel, scriptPosition, myAdhocWorkspace);

My SemanticModel object is obtained from a C# compilation which always has a reference to mscorlib.dll at the very least.

At all positions in my script, the recommended completions are always correct. However, I would argue that they are incomplete if they are missing keywords such as if, else and for etc.

I can see that it would be easy for me to include common type aliases in my IntelliSense manually. That is, if Int32 is a possible completion, then I could manually add int.

However, it is less obvious when an if statement or a for statement or even is/as would be appropriate in the given scope.

Is there a way to include these keywords when getting the recommended symbols this way?

Is there also a way to automatically include type aliases?

rbren
  • 73
  • 7

1 Answers1

3

It seems that Recommender.GetRecommendedSymbolsAtPositionAsync provides only symbols completion. That mean, Methods, Types etc (ISymbol implementations).

If you want keywords or snippets completion, you can use Microsoft.CodeAnalysis.Completion.CompletionService

void CompletionExample()
{
    var code = @"using System;

namespace NewConsoleApp
{
class NewClass
{
    void Method()
    {
fo // I want to get 'for' completion for this
    }
}
}";

    var completionIndex = code.LastIndexOf("fo") + 2;
    // Assume you have a method that create a workspace for you
    var workspace = CreateWorkspace("newSln", "newProj", code);
    var doc = workspace.CurrentSolution.Projects.First().Documents.First();

    var service = CompletionService.GetService(doc);
    var completionItems = service.GetCompletionsAsync(doc, completionIndex).Result.Items;

    foreach (var result in completionItems)
    {
        Console.WriteLine(result.DisplayText);
        Console.WriteLine(string.Join(",", result.Tags));
        Console.WriteLine();
    }
}

You can play around to figure it out how to customize it for your needs (rules, filters).

Notice that each result comes from a specific completion provider (item.Properties["Provider"]) and you can create a custom CompletionProvider (at least you should be able).

You can also take a look at C# for VS code (that powered with OmniSharp) to see how they did the work.

Dudi Keleti
  • 2,946
  • 18
  • 33
  • Excellent, thanks very much! This did exactly what I wanted. – rbren Feb 11 '19 at 13:49
  • This is great, but what do we do about Method parameters? When I use the completion service it brings back only the method names on methods, are we supposed to use Reflection to retrieve everything else based on the Tags and Properties of the completion item, or is this information contained elsewhere for ease of access? – John Ernest Dec 29 '20 at 21:38