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 455375ce68a0c47830e0c3594a582057f98d8fdc..29746ab539f3c3d2afa0ff8a07f53f9e9a5f4fe8 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller.Session_FilterModel.cs @@ -1,5 +1,6 @@ // 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; @@ -131,13 +132,27 @@ internal partial class Session var filterResults = new List(); - var filterText = model.GetCurrentTextInSnapshot(model.OriginalList.Span, textSnapshot, textSpanToText); + var filterText = model.GetCurrentTextInSnapshot( + model.OriginalList.Span, textSnapshot, textSpanToText); - // If the user was typing a number, then immediately dismiss completion. + // Check if the user is typing a number. If so, only proceed if it's a number + // directly after a . That's because it is actually reasonable for completion + // to be brought up after a and for the user to want to filter completion + // items based on a number that exists in the name of the item. However, when + // we are not after a dot (i.e. we're being brought up after is typed) + // then we don't want to filter things. Consider the user writing: + // + // dim i = + // + // We'll bring up the completion list here (as VB has completion on ). + // If the user then types '3', we don't want to match against Int32. var filterTextStartsWithANumber = filterText.Length > 0 && char.IsNumber(filterText[0]); if (filterTextStartsWithANumber) { - return null; + if (!IsAfterDot(model, textSnapshot, textSpanToText)) + { + return null; + } } foreach (var currentItem in model.TotalItems) @@ -196,6 +211,17 @@ internal partial class Session helper, recentItems, filterText, filterResults); } + private Boolean IsAfterDot(Model model, ITextSnapshot textSnapshot, Dictionary textSpanToText) + { + var span = model.OriginalList.Span; + + // Move the span back one character if possible. + span = TextSpan.FromBounds(Math.Max(0, span.Start - 1), span.End); + + var text = model.GetCurrentTextInSnapshot(span, textSnapshot, textSpanToText); + return text.Length > 0 && text[0] == '.'; + } + private Model HandleNormalFiltering( Model model, Document document, @@ -424,13 +450,6 @@ public FilterResult(PresentationItem presentationItem, string filterText, bool m } } - if (filterText.Length > 0 && IsAllDigits(filterText)) - { - // The user is just typing a number. We never want this to match against - // anything we would put in a completion list. - return false; - } - return helper.MatchesFilterText(item, filterText, CultureInfo.CurrentCulture); } diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 3029443707a626e05e110984e073f860f919385c..f69fec4acfa5a6a3e4b9ab2e3dd1130f3634cd42 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -2244,5 +2244,26 @@ class Program Await state.AssertSelectedCompletionItem("DateTime") End Using End Function + + + + Public Async Function TypingNumberShouldNotDismiss1() As Task + Using state = TestState.CreateCSharpTestState( + ) + + state.SendTypeChars(".") + Await state.AssertCompletionSession() + state.SendTypeChars("1") + Await state.AssertSelectedCompletionItem("Moo1") + End Using + End Function End Class End Namespace \ No newline at end of file