Skip to content

Commit

Permalink
Don't hide expanded items if defaults are provided
Browse files Browse the repository at this point in the history
  • Loading branch information
genlu committed Mar 10, 2023
1 parent f92394a commit 9e28522
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,9 @@ private static SegmentedList<VSCompletionItem> SortCompletionItems(AsyncCompleti
}
}

// Don't try to hide expanded items if filter text is reasonably long or the list is short.
// Don't try to hide expanded items if filter text length > 1 and defaults is not empty (which might suggest an expanded item).
var hideExpandedItems = sessionData.AttemptHidingExpandedItems
&& data.Defaults.IsEmpty
&& session.ApplicableToSpan.GetText(data.Snapshot).Length <= MaximumFilterTextLengthToExcludeExpandedItems;

// Don't hide expanded items in the session once it's included
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Imports System.Threading
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.Completion.Providers
Imports Microsoft.CodeAnalysis.CSharp
Imports Microsoft.CodeAnalysis.CSharp.Completion
Imports Microsoft.CodeAnalysis.CSharp.ExternalAccess.Pythia.Api
Imports Microsoft.CodeAnalysis.CSharp.Formatting
Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion
Expand All @@ -18,15 +17,13 @@ Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Shared.TestHooks
Imports Microsoft.CodeAnalysis.Tags
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.VisualStudio.Language.Intellisense.AsyncCompletion
Imports Microsoft.VisualStudio.Text
Imports Microsoft.VisualStudio.Text.Editor
Imports Microsoft.VisualStudio.Text.Operations
Imports Microsoft.VisualStudio.Text.Projection
Imports Roslyn.Utilities

Namespace Microsoft.CodeAnalysis.Editor.UnitTests.IntelliSense
<UseExportProvider>
Expand Down Expand Up @@ -11261,172 +11258,6 @@ class Program
End Using
End Function

<WpfTheory, CombinatorialData>
Public Async Function TestAutoHidingExpandedItems(responsiveTypingEnabled As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
<Document>
$$
</Document>,
excludedTypes:={GetType(CSharpCompletionService.Factory)}.ToList(),
extraExportedTypes:={GetType(MockCompletionServiceFactory)}.ToList())

Dim workspace = state.Workspace
workspace.GlobalOptions.SetGlobalOption(CompletionOptionsStorage.ShowItemsFromUnimportedNamespaces, LanguageNames.CSharp, True)

' we don't auto hide expanded item if responsive completion is disabled
state.TextView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, responsiveTypingEnabled)

Dim completionService = DirectCast(workspace.Services.GetLanguageServices(LanguageNames.CSharp).GetRequiredService(Of CompletionService)(), MockCompletionServiceFactory.Service)

If responsiveTypingEnabled Then
' we blocked the expanded item task, so only regular items in the list
Await state.SendInvokeCompletionListAndWaitForUiRenderAsync()
state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=False)
Dim items = state.GetCompletionItems()
Assert.Equal(completionService.RegularCount, items.Count)
Assert.False(items.Any(Function(i) i.Flags.IsExpanded()))

' make sure expanded item task completes
completionService.ExpandedItemsCheckpoint.Release()
Dim session = Await state.GetCompletionSession()
Dim sessionData = CompletionSessionData.GetOrCreateSessionData(session)
Assert.NotNull(sessionData.ExpandedItemsTask)
Await sessionData.ExpandedItemsTask
Else
' we don't try to separate regular and expanded items when responsive completion is enabled,
' so we expect everything to be provided
completionService.ExpandedItemsCheckpoint.Release()

Await state.SendInvokeCompletionListAndWaitForUiRenderAsync()
state.AssertCompletionItemExpander(isAvailable:=True, isSelected:=True)
Dim items = state.GetCompletionItems()
Assert.Equal(completionService.RegularCount + completionService.ExpandedCount, items.Count)
Assert.Equal(completionService.ExpandedCount, items.Where(Function(x) x.Flags.IsExpanded()).Count())
End If

Dim typedChars = "Item"
For i = 0 To typedChars.Length - 1
Await state.SendTypeCharsAndWaitForUiRenderAsync(typedChars(i))
Dim items = state.GetCompletionItems()
Dim expandedCount As Integer

If (responsiveTypingEnabled And i <= ItemManager.MaximumFilterTextLengthToExcludeExpandedItems - 1) Then
expandedCount = 0
Else
expandedCount = completionService.ExpandedCount
End If

Assert.True((completionService.RegularCount + expandedCount) = items.Count, $"Typed char: '{typedChars(i)}', expected: {completionService.RegularCount + expandedCount}, actual: {items.Count} ")
Assert.Equal(expandedCount, items.Where(Function(x) x.Flags.IsExpanded()).Count())
Next

' once we show expanded items, we will not hide it in the same session, even if filter text became shorter
For i = 1 To 4
state.SendBackspace()
Dim items = state.GetCompletionItems()
Assert.True((completionService.RegularCount + completionService.ExpandedCount) = items.Count, $"Backspace number: {i}expected: {completionService.RegularCount + completionService.ExpandedCount}, actual: {items.Count} ")
Assert.Equal(completionService.ExpandedCount, items.Where(Function(x) x.Flags.IsExpanded()).Count())
Next
End Using
End Function

<ExportLanguageServiceFactory(GetType(CompletionService), LanguageNames.CSharp), [Shared], PartNotDiscoverable>
Private Class MockCompletionServiceFactory
Implements ILanguageServiceFactory

Private ReadOnly _listenerProvider As IAsynchronousOperationListenerProvider

<ImportingConstructor>
<Obsolete(MefConstruction.ImportingConstructorMessage, True)>
Public Sub New(listenerProvider As IAsynchronousOperationListenerProvider)
_listenerProvider = listenerProvider
End Sub

Public Function CreateLanguageService(languageServices As CodeAnalysis.Host.HostLanguageServices) As CodeAnalysis.Host.ILanguageService Implements ILanguageServiceFactory.CreateLanguageService
Return New Service(languageServices.LanguageServices.SolutionServices, _listenerProvider)
End Function

Public Class Service
Inherits CompletionService

Public Property RegularCount As Integer = 10
Public Property ExpandedCount As Integer = 10

Public ExpandedItemsCheckpoint As New Checkpoint()

Public Sub New(services As CodeAnalysis.Host.SolutionServices, listenerProvider As IAsynchronousOperationListenerProvider)
MyBase.New(services, listenerProvider)
End Sub

Public Overrides ReadOnly Property Language As String
Get
Return LanguageNames.CSharp
End Get
End Property

Friend Overrides Function GetRules(options As CompletionOptions) As CompletionRules
Return CompletionRules.Default
End Function

Friend Overrides Async Function GetCompletionsAsync(document As Document,
caretPosition As Integer,
options As CompletionOptions,
passThroughOptions As OptionSet,
Optional trigger As CompletionTrigger = Nothing,
Optional roles As ImmutableHashSet(Of String) = Nothing,
Optional cancellationToken As CancellationToken = Nothing) As Task(Of CompletionList)

Dim text = Await document.GetTextAsync(cancellationToken).ConfigureAwait(False)
Dim defaultItemSpan = GetDefaultCompletionListSpan(text, caretPosition)

Dim builder = ArrayBuilder(Of CompletionItem).GetInstance(RegularCount + ExpandedCount)
If (options.ExpandedCompletionBehavior = ExpandedCompletionMode.AllItems) Then
CreateRegularItems(builder, RegularCount)
Await CreateExpandedItems(builder, ExpandedCount)
ElseIf (options.ExpandedCompletionBehavior = ExpandedCompletionMode.ExpandedItemsOnly) Then
Await CreateExpandedItems(builder, ExpandedCount)
Else
CreateRegularItems(builder, RegularCount)
End If

Return CompletionList.Create(defaultItemSpan, builder.ToImmutableAndFree())
End Function

Friend Overrides Function ShouldTriggerCompletion(project As Project,
languageServices As CodeAnalysis.Host.LanguageServices,
text As SourceText,
caretPosition As Integer,
trigger As CompletionTrigger,
options As CompletionOptions,
passThroughOptions As OptionSet,
Optional roles As ImmutableHashSet(Of String) = Nothing) As Boolean
Return True
End Function

Private Async Function CreateExpandedItems(builder As ArrayBuilder(Of CompletionItem), count As Integer) As Task
Await ExpandedItemsCheckpoint.Task
For i = 1 To count
Dim item = ImportCompletionItem.Create(
$"ItemExpanded{i}",
arity:=0,
containingNamespace:="NS",
glyph:=Glyph.ClassPublic,
genericTypeSuffix:=String.Empty,
flags:=CompletionItemFlags.Expanded,
extensionMethodData:=Nothing,
includedInTargetTypeCompletion:=True)
builder.Add(item)
Next
End Function

Private Shared Sub CreateRegularItems(builder As ArrayBuilder(Of CompletionItem), count As Integer)
For i = 1 To count
builder.Add(CompletionItem.Create($"ItemRegular{i}"))
Next
End Sub
End Class
End Class

<WpfTheory, CombinatorialData, WorkItem("https://github.com/dotnet/roslyn/issues/42910")>
Public Async Function CompletionOffOfNullableLambdaParameter(showCompletionInArgumentLists As Boolean) As Task
Using state = TestStateFactory.CreateCSharpTestState(
Expand Down
Loading

0 comments on commit 9e28522

Please sign in to comment.