From 162e5659c2100e4167ff91e05c743f906191585c Mon Sep 17 00:00:00 2001 From: David Poeschl Date: Mon, 16 Apr 2018 14:16:13 -0700 Subject: [PATCH] Handle completion items with leading/trailing decorative text Leading/trailing decorative text can interfere with the pattern matcher's ability to find/bold matching spans and add redundant items to the MRU list. --- .../Presentation/RoslynCompletionSet.cs | 23 ++++++++++++++++--- .../Controller.Session_FilterModel.cs | 2 +- .../Completion/Controller_Commit.cs | 2 +- .../Portable/Completion/CompletionHelper.cs | 8 +++++++ 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynCompletionSet.cs b/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynCompletionSet.cs index d5ac895953c..be3b119b611 100644 --- a/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynCompletionSet.cs +++ b/src/EditorFeatures/Core.Wpf/Completion/Presentation/RoslynCompletionSet.cs @@ -1,5 +1,9 @@ -using System.Collections.Generic; +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Globalization; using System.Linq; using Microsoft.CodeAnalysis.Completion; @@ -29,6 +33,8 @@ internal class RoslynCompletionSet : CompletionSet2 protected Dictionary CompletionItemMap; protected CompletionItem SuggestionModeItem; + private readonly Dictionary _displayTextToBoldingTextMap = new Dictionary(); + protected string FilterText; public RoslynCompletionSet( @@ -90,6 +96,14 @@ public override void Recalculate() { _foregroundThread.AssertIsForeground(); + foreach (var item in completionItems) + { + if (!_displayTextToBoldingTextMap.ContainsKey(item.DisplayText)) + { + _displayTextToBoldingTextMap.Add(item.DisplayText, CompletionHelper.GetDisplayTextForMatching(item)); + } + } + // Initialize the completion map to a reasonable default initial size (+1 for the builder) CompletionItemMap = CompletionItemMap ?? new Dictionary(completionItems.Count + 1); FilterText = filterText; @@ -215,6 +229,9 @@ public override IReadOnlyList GetHighlightedSpansInDisplayText(string disp return null; } + var textForBolding = _displayTextToBoldingTextMap.TryGetValue(displayText, out var matchingText) ? matchingText : displayText; + Debug.Assert(displayText.Contains(textForBolding)); + var pattern = this.FilterText; if (_highlightMatchingPortions && !string.IsNullOrWhiteSpace(pattern)) { @@ -222,9 +239,9 @@ public override IReadOnlyList GetHighlightedSpansInDisplayText(string disp if (completionHelper != null) { var highlightedSpans = completionHelper.GetHighlightedSpans( - displayText, pattern, CultureInfo.CurrentCulture); + textForBolding, pattern, CultureInfo.CurrentCulture); - return highlightedSpans.SelectAsArray(s => s.ToSpan()); + return highlightedSpans.SelectAsArray(s => new Span(s.Start + Math.Max(0, displayText.IndexOf(textForBolding)), s.Length)); } } 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 9f936c90188..34849d5db81 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs @@ -498,7 +498,7 @@ private bool IsBetterDeletionMatch(FilterResult result1, FilterResult result2) private static int GetRecentItemIndex(ImmutableArray recentItems, CompletionItem item) { - var index = recentItems.IndexOf(item.DisplayText); + var index = recentItems.IndexOf(CompletionHelper.GetDisplayTextForMatching(item)); return -index; } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs index 9a4764e6f12..2335f8dc8bd 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_Commit.cs @@ -174,7 +174,7 @@ private CompletionProvider GetCompletionProvider(CompletionItem item) } // Let the completion rules know that this item was committed. - this.MakeMostRecentItem(item.DisplayText); + this.MakeMostRecentItem(CompletionHelper.GetDisplayTextForMatching(item)); } private void SetCaretPosition(int desiredCaretPosition) diff --git a/src/Features/Core/Portable/Completion/CompletionHelper.cs b/src/Features/Core/Portable/Completion/CompletionHelper.cs index 4c5cf8c4b08..24b58678c49 100644 --- a/src/Features/Core/Portable/Completion/CompletionHelper.cs +++ b/src/Features/Core/Portable/Completion/CompletionHelper.cs @@ -19,6 +19,11 @@ internal sealed class CompletionHelper private static readonly CultureInfo EnUSCultureInfo = new CultureInfo("en-US"); private readonly bool _isCaseSensitive; + // Support for completion items with extra decorative characters in their DisplayText. + // This allows bolding and MRU to operate on the "real" display text (without text + // decorations). This should be a substring of the corresponding DisplayText. + private static string DisplayTextForMatching = nameof(DisplayTextForMatching); + public CompletionHelper(bool isCaseSensitive) { _isCaseSensitive = isCaseSensitive; @@ -252,5 +257,8 @@ private int ComparePreselection(CompletionItem item1, CompletionItem item2) return 0; } + + internal static string GetDisplayTextForMatching(CompletionItem item) + => item.Properties.TryGetValue(DisplayTextForMatching, out var displayText) ? displayText : item.DisplayText; } } -- GitLab