dotnet / roslyn

The Roslyn .NET compiler provides C# and Visual Basic languages with rich code analysis APIs.
https://docs.microsoft.com/dotnet/csharp/roslyn-sdk/
MIT License
19.04k stars 4.03k forks source link

Provide a contextual IntelliSense option #24226

Open kuhlenh opened 6 years ago

kuhlenh commented 6 years ago

We currently preselect an item in the completion list that matches the target type of the current location. Several developers have asked that we additionally offer a 'mode' that will filter the list to only items that match the target type of the current location and name matching.

We can even consider always scoping the list down to matching target types unless there are none, in which case it will revert to the normal completion list.

Dreamescaper commented 6 years ago

Maybe it would make sense to put all such items to the top of the list instead? I know that currently all the items are sorted alphabetically, but don't really get why.

justcla commented 6 years ago

@Dreamescaper, yes, it would make sense to sort by relevance, not alphabetically.

In this case, the request is for a filter on symbols of the matching type. So the only items in the list will be these such items. They will naturally be at the top (and bottom).

However, your comment would apply to the regular IntelliSense completion list sorting.

Dreamescaper commented 6 years ago

I understand, but i think that such request wouldn't appear at all if relevant items were shown on top.

justcla commented 6 years ago

To clarify, you're suggesting that for regular IntelliSense, we should sort the items with matching type at the top of the list. And then we won't need a special function/filter to show members of matching type. That's an interesting idea. However, for regular IntelliSense, type-matching might not always produce the best result - particularly if the user has entered CamelCaseCharacters that match another symbol better.

For those cases where we want to remove all elements that don't match, the type-matching filter is a useful tool.

ermish commented 6 years ago

bump! This feature would be extremely handy. This is one of the most desired missing pieces between standard .NET/Visual Studio and .net core/VS Code.

justcla commented 6 years ago

@AmadeusW has done the work on the platform end.

sharwell commented 6 years ago

@justcla keep in mind that sorting and selection are two independent operations in completion. The behavior of either one can be modified with no impact on the other.

justcla commented 6 years ago

Thanks @sharwell. Yes, of course. We currently have some level of selection that attempts to pick a variable of matching type. And in VS2017, sorting is done alphabetically. (Yuck!)

What we need is neither sorting, nor selection. We need Filtering. Ie. Show me a list that ONLY contains items of the matching type.

AmadeusW commented 6 years ago

I understand @sharwell's vision of very good sorting algorithm, for best experience writing code. The contextual mode of intellisense would be fantastic for exploration of the APIs, that is, reading code. At least, contextual mode may provide insightful telemetry needed to build the best sorting algorithm.

Building contextual completion comprises of three steps:

  1. VS command which can be bound to a keyboard shortcut, e.g. Ctrl+Shift+Space
  2. Command handler which invokes completion in contextual mode
  3. Sorting algorithm which takes under consideration the contextual mode

The following code accomplishes step 2. All steps may be built within Roslyn. Ultimately, we will consider moving steps 1 and 2 into the Editor to benefit all languages.

[Name("Contextual completion prototype")]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Interactive)]
[Export(typeof(ICommandHandler))]
class ContextualCompletion : ICommandHandler<InvokeContextualCompletionListCommandArgs>,
{
    [Import]
    private IAsyncCompletionBroker Broker;

    string INamed.DisplayName => "Contextual completion prototype";

    private CommandState GetCommandStateIfCompletionIsAvailable(IContentType contentType, ITextView textView)
    {
        return 
    }

    CommandState ICommandHandler<InvokeCompletionListCommandArgs>.GetCommandState(InvokeCompletionListCommandArgs args)
        => Broker.IsCompletionSupported(args.SubjectBuffer.ContentType, args.TextView.Roles) ? CommandState.Available : CommandState.Unspecified;

    bool ICommandHandler<InvokeCompletionListCommandArgs>.ExecuteCommand(InvokeCompletionListCommandArgs args, CommandExecutionContext executionContext)
    {
        if (!Broker.IsCompletionSupported(args.SubjectBuffer.ContentType, args.TextView.Roles))
            return false;

        var trigger = new CompletionTrigger(CompletionTriggerReason.InvokeMatchingType, args.TextView.TextSnapshot);
        var location = args.TextView.Caret.Position.BufferPosition;
        var session = Broker.TriggerCompletion(args.TextView, trigger, location, executionContext.OperationContext.UserCancellationToken);

        if (session is IAsyncCompletionSessionOperations sessionInternal)
        {
            // RealizeVirtualSpaceUpdateApplicableToSpan(sessionInternal, args.TextView); don't worry about this in prototype
            location = args.TextView.Caret.Position.BufferPosition; // Buffer may have changed. Update the location.
            session.OpenOrUpdate(trigger, location, executionContext.OperationContext.UserCancellationToken);
            return true;
        }
        return false;
    }
}
scottmcm commented 5 years ago

:+1:, this is the primary thing keeping me needing Resharper. I make sure I have good types in my code, and can as a result often write code by mashing Ctrl-Shift-Space.