diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs index 02ac19eec86171a88105d81eae992cba691efc90..67ca2647824668f91877a3d9c486ee4a75e6e545 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/FilterResult.cs @@ -3,6 +3,7 @@ using System; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.PatternMatching; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.AsyncCompletion @@ -12,12 +13,14 @@ internal struct FilterResult : IComparable public readonly CompletionItem CompletionItem; public readonly bool MatchedFilterText; public readonly string FilterText; + public readonly PatternMatch? PatternMatch; - public FilterResult(CompletionItem completionItem, string filterText, bool matchedFilterText) + public FilterResult(CompletionItem completionItem, string filterText, bool matchedFilterText, PatternMatch? patternMatch) { CompletionItem = completionItem; MatchedFilterText = matchedFilterText; FilterText = filterText; + PatternMatch = patternMatch; } public int CompareTo(FilterResult other) diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs index 6a3e78289db0f4ef85ec7615fd9026d8e164bf42..ba870a7348b586ab24832ceec297715cda8de43d 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/AsyncCompletion/ItemManager.cs @@ -9,6 +9,8 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.PatternMatching; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.Text.Shared.Extensions; @@ -174,9 +176,9 @@ internal ItemManager(RecentItemsManager recentItemsManager) displayTextSuffix: item.Suffix); } - if (MatchesFilterText(completionHelper, roslynItem, filterText, initialRoslynTriggerKind, filterReason, _recentItemsManager.RecentItems)) + if (MatchesFilterText(completionHelper, roslynItem, filterText, initialRoslynTriggerKind, filterReason, _recentItemsManager.RecentItems, out var patternMatch)) { - initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: true))); + initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: true, patternMatch))); } else { @@ -193,7 +195,7 @@ internal ItemManager(RecentItemsManager recentItemsManager) initialRoslynTriggerKind == CompletionTriggerKind.Invoke || filterText.Length <= 1) { - initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: false))); + initialListOfItemsToBeIncluded.Add(new ExtendedFilterResult(item, new FilterResult(roslynItem, filterText, matchedFilterText: false, patternMatch))); } } } @@ -214,30 +216,33 @@ internal ItemManager(RecentItemsManager recentItemsManager) return HandleAllItemsFilteredOut(reason, data.SelectedFilters, completionRules); } + // todo: Add comment + var itemsToBeIncludedSortedByMatch = initialListOfItemsToBeIncluded.OrderBy(result => result.FilterResult.PatternMatch).ToImmutableArray(); + var options = document?.Project.Solution.Options; var highlightMatchingPortions = options?.GetOption(CompletionOptions.HighlightMatchingPortionsOfCompletionListItems, document.Project.Language) ?? true; var showCompletionItemFilters = options?.GetOption(CompletionOptions.ShowCompletionItemFilters, document.Project.Language) ?? true; var updatedFilters = showCompletionItemFilters - ? GetUpdatedFilters(initialListOfItemsToBeIncluded, data.SelectedFilters) + ? GetUpdatedFilters(itemsToBeIncludedSortedByMatch, data.SelectedFilters) : ImmutableArray.Empty; - var highlightedList = GetHighlightedList(initialListOfItemsToBeIncluded, filterText, completionHelper, highlightMatchingPortions).ToImmutableArray(); + var highlightedList = GetHighlightedList(itemsToBeIncludedSortedByMatch, filterText, completionHelper, highlightMatchingPortions); // If this was deletion, then we control the entire behavior of deletion ourselves. if (initialRoslynTriggerKind == CompletionTriggerKind.Deletion) { - return HandleDeletionTrigger(data.Trigger.Reason, initialListOfItemsToBeIncluded, filterText, updatedFilters, highlightedList); + return HandleDeletionTrigger(data.Trigger.Reason, itemsToBeIncludedSortedByMatch, filterText, updatedFilters, highlightedList); } - Func, string, ImmutableArray> filterMethod; + Func, string, ImmutableArray> filterMethod; if (completionService == null) { - filterMethod = (items, text) => CompletionService.FilterItems(completionHelper, items, text); + filterMethod = (itemsWithPatternMatches, text) => CompletionService.FilterItems(completionHelper, itemsWithPatternMatches); } else { - filterMethod = (items, text) => completionService.FilterItems(document, items, text); + filterMethod = (itemsWithPatternMatches, text) => completionService.FilterItems(document, itemsWithPatternMatches, text); } return HandleNormalFiltering( @@ -247,7 +252,7 @@ internal ItemManager(RecentItemsManager recentItemsManager) initialRoslynTriggerKind, filterReason, data.Trigger.Character, - initialListOfItemsToBeIncluded, + itemsToBeIncludedSortedByMatch, highlightedList, completionHelper, hasSuggestedItemOptions); @@ -284,6 +289,35 @@ static bool ShouldBeFilteredOutOfExpandedCompletionList(VSCompletionItem item, I // 2. or, all associated expanders are unselected, therefore should be excluded return associatedWithUnselectedExpander; } + + static ImmutableArray GetHighlightedList( + ImmutableArray filterResults, + string filterText, + CompletionHelper completionHelper, + bool highlightMatchingPortions) + { + if (!highlightMatchingPortions) + { + return filterResults.SelectAsArray(r => new CompletionItemWithHighlight(r.VSCompletionItem, ImmutableArray.Empty)); + } + + var highlightedItems = ArrayBuilder.GetInstance(filterResults.Length); + foreach (var extendedResult in filterResults) + { + // The PatternMatch in FilterResult is calculated based on Roslyn item's FilterText, + // which can be used to calculate highlighted span for VSCompletion item's DisplayText w/o doing the matching again. + // However, if the PatternMatch is null or the Roslyn item's FilterText is different from its DisplayText, + // we need to do the match against the display text of the VS item directly to get the highlighted spans. + var filterResult = extendedResult.FilterResult; + var highlightedSpans = filterResult.PatternMatch.HasValue && !filterResult.CompletionItem.HasDifferentFilterText + ? filterResult.PatternMatch.Value.MatchedSpans.SelectAsArray(s => s.ToSpan(filterResult.CompletionItem.DisplayTextPrefix?.Length ?? 0)) + : completionHelper.GetHighlightedSpans(extendedResult.VSCompletionItem.DisplayText, filterText, CultureInfo.CurrentCulture).SelectAsArray(s => s.ToSpan()); + + highlightedItems.Add(new CompletionItemWithHighlight(extendedResult.VSCompletionItem, highlightedSpans)); + } + + return highlightedItems.ToImmutableAndFree(); + } } private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableToSpan) @@ -293,13 +327,13 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT } private FilteredCompletionModel HandleNormalFiltering( - Func, string, ImmutableArray> filterMethod, + Func, string, ImmutableArray> filterMethod, string filterText, ImmutableArray filters, CompletionTriggerKind initialRoslynTriggerKind, CompletionFilterReason filterReason, char typeChar, - List itemsInList, + ImmutableArray itemsInList, ImmutableArray highlightedList, CompletionHelper completionHelper, bool hasSuggestedItemOptions) @@ -309,8 +343,7 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT // Ask the language to determine which of the *matched* items it wants to select. var matchingItems = itemsInList.Where(r => r.FilterResult.MatchedFilterText) - .Select(t => t.FilterResult.CompletionItem) - .AsImmutable(); + .SelectAsArray(t => (t.FilterResult.CompletionItem, t.FilterResult.PatternMatch)); var chosenItems = filterMethod(matchingItems, filterText); @@ -331,7 +364,7 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT if (bestItem != null) { selectedItemIndex = itemsInList.IndexOf(i => Equals(i.FilterResult.CompletionItem, bestItem)); - var deduplicatedListCount = matchingItems.Where(r => !r.IsPreferredItem()).Count(); + var deduplicatedListCount = matchingItems.Where(r => !r.CompletionItem.IsPreferredItem()).Count(); if (selectedItemIndex > -1 && deduplicatedListCount == 1 && filterText.Length > 0) @@ -376,12 +409,12 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT private FilteredCompletionModel HandleDeletionTrigger( CompletionTriggerReason filterTriggerKind, - List filterResults, + ImmutableArray filterResults, string filterText, ImmutableArray filters, ImmutableArray highlightedList) { - var matchingItems = filterResults.Where(r => r.FilterResult.MatchedFilterText).AsImmutable(); + var matchingItems = filterResults.WhereAsArray(r => r.FilterResult.MatchedFilterText); if (filterTriggerKind == CompletionTriggerReason.Insertion && !matchingItems.Any()) { @@ -479,26 +512,8 @@ private static bool IsAfterDot(ITextSnapshot snapshot, ITrackingSpan applicableT filters, selection, centerSelection: true, uniqueItem: default); } - private static IEnumerable GetHighlightedList( - IEnumerable filterResults, - string filterText, - CompletionHelper completionHelper, - bool highlightMatchingPortions) - { - var highlightedList = new List(); - foreach (var item in filterResults) - { - var highlightedSpans = highlightMatchingPortions - ? completionHelper.GetHighlightedSpans(item.VSCompletionItem.DisplayText, filterText, CultureInfo.CurrentCulture) - : ImmutableArray.Empty; - highlightedList.Add(new CompletionItemWithHighlight(item.VSCompletionItem, highlightedSpans.Select(s => s.ToSpan()).ToImmutableArray())); - } - - return highlightedList; - } - private static ImmutableArray GetUpdatedFilters( - List filteredList, + ImmutableArray filteredList, ImmutableArray filters) { // See which filters might be enabled based on the typed code @@ -571,10 +586,20 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re => result1.CompareTo(result2) > 0; internal static bool MatchesFilterText( - CompletionHelper helper, RoslynCompletionItem item, - string filterText, CompletionTriggerKind initialTriggerKind, - CompletionFilterReason filterReason, ImmutableArray recentItems) + CompletionHelper helper, + RoslynCompletionItem item, + string filterText, + CompletionTriggerKind initialTriggerKind, + CompletionFilterReason filterReason, + ImmutableArray recentItems, + out PatternMatch? patternMatch) { + // Get the match of the given completion item for the pattern provided so far. + // A completion item is checked against the pattern by see if it's + // CompletionItem.FilterText matches the item. That way, the pattern it checked + // against terms like "IList" and not IList<> + patternMatch = helper.GetMatch(item.FilterText, filterText, includeMatchSpans: true, CultureInfo.CurrentCulture); + // For the deletion we bake in the core logic for how matching should work. // This way deletion feels the same across all languages that opt into deletion // as a completion trigger. @@ -603,11 +628,8 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re } } - // Checks if the given completion item matches the pattern provided so far. - // A completion item is checked against the pattern by see if it's - // CompletionItem.FilterText matches the item. That way, the pattern it checked - // against terms like "IList" and not IList<> - return helper.MatchesPattern(item.FilterText, filterText, CultureInfo.CurrentCulture); + // Otherwise, the item matches filter text if a pattern match is returned. + return patternMatch != null; } internal static bool IsHardSelection( @@ -644,7 +666,7 @@ internal static bool IsBetterDeletionMatch(FilterResult result1, FilterResult re // If the user moved the caret left after they started typing, the 'best' match may not match at all // against the full text span that this item would be replacing. - if (!ItemManager.MatchesFilterText(completionHelper, bestFilterMatch, fullFilterText, initialTriggerKind, filterReason, recentItems)) + if (!ItemManager.MatchesFilterText(completionHelper, bestFilterMatch, fullFilterText, initialTriggerKind, filterReason, recentItems, out _)) { return false; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs index 9ae71973bcfe598d59b4b03a8a03f872e9c798de..e036f433b1b9870adbd55accee687c38f98af97a 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs @@ -140,12 +140,12 @@ internal partial class Session } // Check if the item matches the filter text typed so far. - var matchesFilterText = ItemManager.MatchesFilterText(helper, currentItem, filterText, model.Trigger.Kind, filterReason, recentItems); + var matchesFilterText = ItemManager.MatchesFilterText(helper, currentItem, filterText, model.Trigger.Kind, filterReason, recentItems, out var patternMatch); if (matchesFilterText) { filterResults.Add(new FilterResult( - currentItem, filterText, matchedFilterText: true)); + currentItem, filterText, matchedFilterText: true, patternMatch)); } else { @@ -167,7 +167,7 @@ internal partial class Session if (shouldKeepItem) { filterResults.Add(new FilterResult( - currentItem, filterText, matchedFilterText: false)); + currentItem, filterText, matchedFilterText: false, patternMatch)); } } } @@ -250,8 +250,7 @@ private bool IsAfterDot(Model model) } var matchingCompletionItems = filterResults.Where(r => r.MatchedFilterText) - .Select(t => t.CompletionItem) - .AsImmutable(); + .SelectAsArray(t => (t.CompletionItem, t.PatternMatch)); var chosenItems = service.FilterItems( document, matchingCompletionItems, filterText); diff --git a/src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs b/src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs index 590176937a8130eb229bc4b33cd94aa8eda6a854..c1a96b62f14798e14c5c79ab9a11dbc651a15c26 100644 --- a/src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs +++ b/src/EditorFeatures/Text/Shared/Extensions/TextSpanExtensions.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using Microsoft.VisualStudio.Text; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Text.Shared.Extensions { @@ -16,6 +15,14 @@ public static Span ToSpan(this TextSpan textSpan) return new Span(textSpan.Start, textSpan.Length); } + /// + /// Convert a instance to a with additional offset. + /// + public static Span ToSpan(this TextSpan textSpan, int offset) + { + return new Span(textSpan.Start + offset, textSpan.Length); + } + /// /// Convert a to a on the given instance /// diff --git a/src/Features/Core/Portable/Completion/CommonCompletionService.cs b/src/Features/Core/Portable/Completion/CommonCompletionService.cs index e6bf264f15ed8526d88628cf5142dd240029047a..f300adb577d1610d1947845aa6bc3973be83cb2f 100644 --- a/src/Features/Core/Portable/Completion/CommonCompletionService.cs +++ b/src/Features/Core/Portable/Completion/CommonCompletionService.cs @@ -4,6 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.Tags; namespace Microsoft.CodeAnalysis.Completion @@ -55,5 +56,11 @@ protected static bool IsSnippetItem(CompletionItem item) { return item.Tags.Contains(WellKnownTags.Snippet); } + + internal override ImmutableArray FilterItems(Document document, ImmutableArray<(CompletionItem, PatternMatch?)> itemsWithPatternMatch, string filterText) + { + var helper = CompletionHelper.GetHelper(document); + return CompletionService.FilterItems(helper, itemsWithPatternMatch); + } } } diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs index e948a4c331c5f900c301c6791fe94becf2a6b13d..97e543f8b08f6f3c5fdc91ea81d5f3fbfac26ce4 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs @@ -43,14 +43,13 @@ public static CompletionHelper GetHelper(Document document) /// results, or false if it should not be. /// public bool MatchesPattern(string text, string pattern, CultureInfo culture) - => GetMatch(text, pattern, culture) != null; + => GetMatch(text, pattern, includeMatchSpans: false, culture) != null; - private PatternMatch? GetMatch(string text, string pattern, CultureInfo culture) - => GetMatch(text, pattern, includeMatchSpans: false, culture: culture); - - private PatternMatch? GetMatch( - string completionItemText, string pattern, - bool includeMatchSpans, CultureInfo culture) + public PatternMatch? GetMatch( + string completionItemText, + string pattern, + bool includeMatchSpans, + CultureInfo culture) { // If the item has a dot in it (i.e. for something like enum completion), then attempt // to match what the user wrote against the last portion of the name. That way if they @@ -136,9 +135,14 @@ private PatternMatcher GetPatternMatcher(string pattern, CultureInfo culture, bo /// public int CompareItems(CompletionItem item1, CompletionItem item2, string pattern, CultureInfo culture) { - var match1 = GetMatch(item1.FilterText, pattern, culture); - var match2 = GetMatch(item2.FilterText, pattern, culture); + var match1 = GetMatch(item1.FilterText, pattern, includeMatchSpans: false, culture); + var match2 = GetMatch(item2.FilterText, pattern, includeMatchSpans: false, culture); + return CompareItems(item1, match1, item2, match2); + } + + public int CompareItems(CompletionItem item1, PatternMatch? match1, CompletionItem item2, PatternMatch? match2) + { if (match1 != null && match2 != null) { var result = CompareMatches(match1.Value, match2.Value, item1, item2); diff --git a/src/Features/Core/Portable/Completion/CompletionItem.cs b/src/Features/Core/Portable/Completion/CompletionItem.cs index 75cfeecff7acbc3fbbe874152ed4e99789b53723..7777ccedcad5edf1897f55cb0fc0657798e13f4c 100644 --- a/src/Features/Core/Portable/Completion/CompletionItem.cs +++ b/src/Features/Core/Portable/Completion/CompletionItem.cs @@ -14,6 +14,8 @@ namespace Microsoft.CodeAnalysis.Completion [DebuggerDisplay("{DisplayText}")] public sealed class CompletionItem : IComparable { + private readonly string _filterText; + /// /// The text that is displayed to the user. /// @@ -37,7 +39,9 @@ public sealed class CompletionItem : IComparable /// The text used to determine if the item matches the filter and is show in the list. /// This is often the same as but may be different in certain circumstances. /// - public string FilterText { get; } + public string FilterText => _filterText ?? DisplayText; + + internal bool HasDifferentFilterText => _filterText != null; /// /// The text used to determine the order that the item appears in the list. @@ -107,13 +111,17 @@ public sealed class CompletionItem : IComparable DisplayText = displayText ?? ""; DisplayTextPrefix = displayTextPrefix ?? ""; DisplayTextSuffix = displayTextSuffix ?? ""; - FilterText = filterText ?? DisplayText; SortText = sortText ?? DisplayText; InlineDescription = inlineDescription ?? ""; Span = span; Properties = properties ?? ImmutableDictionary.Empty; Tags = tags.NullToEmpty(); Rules = rules ?? CompletionItemRules.Default; + + if (!DisplayText.Equals(filterText, StringComparison.Ordinal)) + { + _filterText = filterText; + } } // binary back compat overload diff --git a/src/Features/Core/Portable/Completion/CompletionService.cs b/src/Features/Core/Portable/Completion/CompletionService.cs index a2ef4b5774e3e71143e2f74914dd3dd26601018a..99986193c0ea0ad3fa8f0a59fddd93ebcefdc88d 100644 --- a/src/Features/Core/Portable/Completion/CompletionService.cs +++ b/src/Features/Core/Portable/Completion/CompletionService.cs @@ -2,11 +2,13 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; using System.Globalization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; +using Microsoft.CodeAnalysis.PatternMatching; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; @@ -175,41 +177,62 @@ public virtual TextSpan GetDefaultCompletionListSpan(SourceText text, int caretP return FilterItems(helper, items, filterText); } + internal virtual ImmutableArray FilterItems( + Document document, + ImmutableArray<(CompletionItem, PatternMatch?)> itemsWithPatternMatch, + string filterText) + { + // Default implementation just drops the pattern matches and + // calls the public overload of FilterItems for compatibility. + return FilterItems(document, itemsWithPatternMatch.SelectAsArray(item => item.Item1), filterText); + } + internal static ImmutableArray FilterItems( CompletionHelper completionHelper, ImmutableArray items, string filterText) { - var bestItems = ArrayBuilder.GetInstance(); - foreach (var item in items) + var itemsWithPatternMatch = items.SelectAsArray( + item => (item, completionHelper.GetMatch(item.FilterText, filterText, includeMatchSpans: false, CultureInfo.CurrentCulture))); + + return FilterItems(completionHelper, itemsWithPatternMatch); + } + + internal static ImmutableArray FilterItems( + CompletionHelper completionHelper, + ImmutableArray<(CompletionItem item, PatternMatch? match)> itemsWithPatternMatch) + { + var bestItems = ArrayBuilder<(CompletionItem, PatternMatch?)>.GetInstance(); + foreach (var pair in itemsWithPatternMatch) { if (bestItems.Count == 0) { // We've found no good items yet. So this is the best item currently. - bestItems.Add(item); + bestItems.Add(pair); } else { - var comparison = completionHelper.CompareItems(item, bestItems.First(), filterText, CultureInfo.CurrentCulture); + var (bestItem, bestItemMatch) = bestItems.First(); + var comparison = completionHelper.CompareItems(pair.item, pair.match, bestItem, bestItemMatch); if (comparison < 0) { // This item is strictly better than the best items we've found so far. bestItems.Clear(); - bestItems.Add(item); + bestItems.Add(pair); } else if (comparison == 0) { // This item is as good as the items we've been collecting. We'll return // it and let the controller decide what to do. (For example, it will // pick the one that has the best MRU index). - bestItems.Add(item); + bestItems.Add(pair); } // otherwise, this item is strictly worse than the ones we've been collecting. // We can just ignore it. } } - return bestItems.ToImmutableAndFree(); + return bestItems.ToImmutableAndFree().SelectAsArray(itemWithPatternMatch => itemWithPatternMatch.Item1); } } } diff --git a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/TypeImportCompletionItem.cs b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/TypeImportCompletionItem.cs index 785cd5ca5762d3108f357f4d949f9e53b392fd6a..654e25d2b2122d756d0b5cf5bc486e1d60f53519 100644 --- a/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/TypeImportCompletionItem.cs +++ b/src/Features/Core/Portable/Completion/Providers/ImportCompletionProvider/TypeImportCompletionItem.cs @@ -34,7 +34,7 @@ public static CompletionItem Create(INamedTypeSymbol typeSymbol, string containi // it also makes sure type with shorter name shows first, e.g. 'SomeType` before 'SomeTypeWithLongerName'. var sortTextBuilder = PooledStringBuilder.GetInstance(); sortTextBuilder.Builder.AppendFormat(SortTextFormat, typeSymbol.Name, containingNamespace); - + var item = CompletionItem.Create( displayText: typeSymbol.Name, filterText: typeSymbol.Name,