diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs index 379668ac18f338bca64e6655affc75e201475a39..ef96e08df843685860f491218195f6fe7ee4f1c6 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/AbstractCSharpCompletionProviderTests.cs @@ -7,6 +7,7 @@ using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Completion; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; using Microsoft.CodeAnalysis.Editor.UnitTests.Completion; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Text; @@ -151,8 +152,7 @@ protected async Task VerifySendEnterThroughToEnterAsync(string initialMarkup, st var completionList = await GetCompletionListAsync(service, document, position, CompletionTrigger.Default); var item = completionList.Items.First(i => i.DisplayText.StartsWith(textTypedSoFar)); - var completionRules = CompletionHelper.GetHelper(document, service); - Assert.Equal(expected, completionRules.SendEnterThroughToEditor(item, textTypedSoFar, workspace.Options)); + Assert.Equal(expected, Controller.SendEnterThroughToEditor(service.GetRules(), item, textTypedSoFar)); } } @@ -216,16 +216,14 @@ protected async Task VerifyCommitCharactersAsync(string initialMarkup, string te var completionList = await GetCompletionListAsync(service, document, position, CompletionTrigger.Default); var item = completionList.Items.First(i => i.DisplayText.StartsWith(textTypedSoFar)); - var completionRules = CompletionHelper.GetHelper(document, service); - foreach (var ch in validChars) { - Assert.True(completionRules.IsCommitCharacter(item, ch, textTypedSoFar), $"Expected '{ch}' to be a commit character"); + Assert.True(Controller.IsCommitCharacter(service.GetRules(), item, ch, textTypedSoFar), $"Expected '{ch}' to be a commit character"); } foreach (var ch in invalidChars) { - Assert.False(completionRules.IsCommitCharacter(item, ch, textTypedSoFar), $"Expected '{ch}' NOT to be a commit character"); + Assert.False(Controller.IsCommitCharacter(service.GetRules(), item, ch, textTypedSoFar), $"Expected '{ch}' NOT to be a commit character"); } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs index 253078d572e4860dbf5cb74be58b5c3fd765f1c2..af7010886051c34781b0a708cdbf227970f884cd 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/ObjectInitializerCompletionProviderTests.cs @@ -4,6 +4,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Roslyn.Test.Utilities; using Xunit; @@ -579,9 +580,7 @@ void foo() var completionList = await GetCompletionListAsync(service, document, position, triggerInfo); var item = completionList.Items.First(); - var completionRules = CompletionHelper.GetHelper(document, service); - - Assert.False(completionRules.SendEnterThroughToEditor(item, string.Empty, workspace.Options), "Expected false from SendEnterThroughToEditor()"); + Assert.False(Controller.SendEnterThroughToEditor(service.GetRules(), item, string.Empty), "Expected false from SendEnterThroughToEditor()"); } } diff --git a/src/EditorFeatures/Core/Extensibility/Completion/CompletionHelper.cs b/src/EditorFeatures/Core/Extensibility/Completion/CompletionHelper.cs index a9556b09a1b9f4255601efb425a090fd3986d4f8..f50ceeff1946152ffbfb2e7ba60b8dae9a900665 100644 --- a/src/EditorFeatures/Core/Extensibility/Completion/CompletionHelper.cs +++ b/src/EditorFeatures/Core/Extensibility/Completion/CompletionHelper.cs @@ -313,80 +313,11 @@ protected bool IsArgumentName(CompletionItem item) return item.Tags.Contains(CompletionTags.ArgumentName); } - /// - /// Returns true if the character is one that can commit the specified completion item. A - /// character will be checked to see if it should filter an item. If not, it will be checked - /// to see if it should commit that item. If it does neither, then completion will be - /// dismissed. - /// - public virtual bool IsCommitCharacter(CompletionItem item, char ch, string textTypedSoFar, string textTypedWithChar = null) + private static bool TextTypedSoFarMatchesItem(CompletionItem item, char ch, string textTypedSoFar) { - // general rule: if the filtering text exactly matches the start of the item then it must be a filter character - textTypedWithChar = textTypedWithChar ?? textTypedSoFar + ch; - if (item.DisplayText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase) - || item.FilterText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase)) - { - return false; - } - - foreach (var rule in item.Rules.CommitCharacterRules) - { - switch (rule.Kind) - { - case CharacterSetModificationKind.Add: - if (rule.Characters.IndexOf(ch) >= 0) - return true; - break; - - case CharacterSetModificationKind.Remove: - if (rule.Characters.IndexOf(ch) >= 0) - return false; - break; - - case CharacterSetModificationKind.Replace: - return rule.Characters.IndexOf(ch) >= 0; - } - } - - return _rules.DefaultCommitCharacters.IndexOf(ch) >= 0; - } - - /// - /// Returns true if the character typed should be used to filter the specified completion - /// item. A character will be checked to see if it should filter an item. If not, it will be - /// checked to see if it should commit that item. If it does neither, then completion will - /// be dismissed. - /// - public virtual bool IsFilterCharacter(CompletionItem item, char ch, string textTypedSoFar, string textTypedWithChar = null) - { - // general rule: if the filtering text exactly matches the start of the item then it must be a filter character - textTypedWithChar = textTypedWithChar ?? textTypedSoFar + ch; - if (item.DisplayText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase) - || item.FilterText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase)) - { - return false; - } - - foreach (var rule in item.Rules.FilterCharacterRules) - { - switch (rule.Kind) - { - case CharacterSetModificationKind.Add: - if (rule.Characters.IndexOf(ch) >= 0) - return true; - break; - - case CharacterSetModificationKind.Remove: - if (rule.Characters.IndexOf(ch) >= 0) - return false; - break; - - case CharacterSetModificationKind.Replace: - return rule.Characters.IndexOf(ch) >= 0; - } - } - - return false; + var textTypedWithChar = textTypedSoFar + ch; + return item.DisplayText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase) || + item.FilterText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase); } private static StringComparison GetComparision(bool isCaseSensitive) @@ -394,31 +325,6 @@ private static StringComparison GetComparision(bool isCaseSensitive) return isCaseSensitive? StringComparison.CurrentCulture: StringComparison.CurrentCultureIgnoreCase; } - /// - /// Returns true if the enter key that was typed should also be sent through to the editor - /// after committing the provided completion item. - /// - public virtual bool SendEnterThroughToEditor(CompletionItem item, string textTypedSoFar, OptionSet options) - { - var rule = item.Rules.EnterKeyRule; - if (rule == EnterKeyRule.Default) - { - rule = _rules.DefaultEnterKeyRule; - } - - switch (rule) - { - default: - case EnterKeyRule.Default: - case EnterKeyRule.Never: - return false; - case EnterKeyRule.Always: - return true; - case EnterKeyRule.AfterFullyTypedWord: - return item.DisplayText == textTypedSoFar; - } - } - /// /// Returns true if the completion item should be "soft" selected, or false if it should be "hard" /// selected. @@ -432,22 +338,5 @@ protected bool IsObjectCreationItem(CompletionItem item) { return item.Tags.Contains(CompletionTags.ObjectCreation); } - - public static async Task GetTextChangeAsync( - CompletionService service, Document document, CompletionItem item, - char? commitKey = null, CancellationToken cancellationToken = default(CancellationToken)) - { - var change = await service.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false); - - // normally the items that produce multiple changes are not expecting to trigger the behaviors that rely on looking at the text - if (change.TextChanges.Length == 1) - { - return change.TextChanges[0]; - } - else - { - return new TextChange(item.Span, item.DisplayText); - } - } } } \ No newline at end of file diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_ReturnKey.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_ReturnKey.cs index 687f399a469879125933281d097f2ec0006ace4e..6722c6ff6033afdd79e0fdb73887a41a8d70b93a 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_ReturnKey.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_ReturnKey.cs @@ -1,6 +1,7 @@ // 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 Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Editor.Commands; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion @@ -82,8 +83,6 @@ private void CommitOnEnter(out bool sendThrough, out bool committed) return; } - var helper = GetCompletionHelper(); - if (sendThrough) { // Get the text that the user has currently entered into the buffer @@ -91,15 +90,37 @@ private void CommitOnEnter(out bool sendThrough, out bool committed) var textTypedSoFar = model.GetCurrentTextInSnapshot( viewSpan, this.TextView.TextSnapshot, this.GetCaretPointInViewBuffer()); - var options = GetOptions(); - if (options != null) - { - sendThrough = helper.SendEnterThroughToEditor(model.SelectedItem.Item, textTypedSoFar, options); - } + var service = GetCompletionService(); + sendThrough = SendEnterThroughToEditor( + service.GetRules(), model.SelectedItem.Item, textTypedSoFar); } this.Commit(model.SelectedItem, model, commitChar: null); committed = true; } + + /// + /// Internal for testing purposes only. + /// + internal static bool SendEnterThroughToEditor(CompletionRules rules, CompletionItem item, string textTypedSoFar) + { + var rule = item.Rules.EnterKeyRule; + if (rule == EnterKeyRule.Default) + { + rule = rules.DefaultEnterKeyRule; + } + + switch (rule) + { + default: + case EnterKeyRule.Default: + case EnterKeyRule.Never: + return false; + case EnterKeyRule.Always: + return true; + case EnterKeyRule.AfterFullyTypedWord: + return item.DisplayText == textTypedSoFar; + } + } } } diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_TypeChar.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_TypeChar.cs index ace7bb2dc068e121d9a197e038665f7af18e03e1..06ee4c886440f26df41fb0bc1766340ac7abc01f 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_TypeChar.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/Controller_TypeChar.cs @@ -311,14 +311,49 @@ private bool IsCommitCharacter(char ch) return char.IsLetterOrDigit(ch); } - var helper = GetCompletionHelper(); - if (helper != null) + var completionService = GetCompletionService(); + var filterText = GetCurrentFilterText(model, model.SelectedItem.Item); + return IsCommitCharacter( + completionService.GetRules(), model.SelectedItem.Item, ch, filterText); + } + + /// + /// Internal for testing purposes only. + /// + internal static bool IsCommitCharacter( + CompletionRules completionRules, CompletionItem item, char ch, string filterText) + { + // general rule: if the filtering text exactly matches the start of the item then it must be a filter character + if (TextTypedSoFarMatchesItem(item, ch, textTypedSoFar: filterText)) { - var filterText = GetCurrentFilterText(model, model.SelectedItem.Item); - return helper.IsCommitCharacter(model.SelectedItem.Item, ch, filterText); + return false; } - return false; + foreach (var rule in item.Rules.CommitCharacterRules) + { + switch (rule.Kind) + { + case CharacterSetModificationKind.Add: + if (rule.Characters.Contains(ch)) + { + return true; + } + continue; + + case CharacterSetModificationKind.Remove: + if (rule.Characters.Contains(ch)) + { + return false; + } + continue; + + case CharacterSetModificationKind.Replace: + return rule.Characters.Contains(ch); + } + } + + // Fall back to the default rules for this language's completion service. + return completionRules.DefaultCommitCharacters.IndexOf(ch) >= 0; } private bool IsFilterCharacter(char ch) @@ -337,11 +372,49 @@ private bool IsFilterCharacter(char ch) return char.IsLetterOrDigit(ch); } - var helper = GetCompletionHelper(); - if (helper != null) + var filterText = GetCurrentFilterText(model, model.SelectedItem.Item); + return IsFilterCharacter(model.SelectedItem.Item, ch, filterText); + } + + private static bool TextTypedSoFarMatchesItem(CompletionItem item, char ch, string textTypedSoFar) + { + var textTypedWithChar = textTypedSoFar + ch; + return item.DisplayText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase) || + item.FilterText.StartsWith(textTypedWithChar, StringComparison.CurrentCultureIgnoreCase); + } + + /// + /// Internal for testing purposes only. + /// + internal static bool IsFilterCharacter(CompletionItem item, char ch, string filterText) + { + // general rule: if the filtering text exactly matches the start of the item then it must be a filter character + if (TextTypedSoFarMatchesItem(item, ch, textTypedSoFar: filterText)) + { + return false; + } + + foreach (var rule in item.Rules.FilterCharacterRules) { - var filterText = GetCurrentFilterText(model, model.SelectedItem.Item); - return helper.IsFilterCharacter(model.SelectedItem.Item, ch, filterText); + switch (rule.Kind) + { + case CharacterSetModificationKind.Add: + if (rule.Characters.Contains(ch)) + { + return true; + } + continue; + + case CharacterSetModificationKind.Remove: + if (rule.Characters.Contains(ch)) + { + return false; + } + continue; + + case CharacterSetModificationKind.Replace: + return rule.Characters.Contains(ch); + } } return false; diff --git a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/DescriptionModifyingPresentationItem.cs b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/DescriptionModifyingPresentationItem.cs index 373c4bd1bd393c689b9ea94f6eb466f188255fca..4be06883600f6a2d92d2931970708e3dadd926ef 100644 --- a/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/DescriptionModifyingPresentationItem.cs +++ b/src/EditorFeatures/Core/Implementation/IntelliSense/Completion/DescriptionModifyingPresentationItem.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.Completion; using Microsoft.CodeAnalysis.Snippets; +using Microsoft.CodeAnalysis.Text; namespace Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion { @@ -34,7 +35,7 @@ public override async Task GetDescriptionAsync(Document d var description = await this.CompletionService.GetDescriptionAsync(document, this.Item, cancellationToken).ConfigureAwait(false); var parts = description.TaggedParts; - var change = await CompletionHelper.GetTextChangeAsync(this.CompletionService, document, this.Item, '\t').ConfigureAwait(false); + var change = await GetTextChangeAsync(this.CompletionService, document, this.Item, '\t').ConfigureAwait(false); var insertionText = change.NewText; var note = string.Empty; @@ -55,5 +56,25 @@ public override async Task GetDescriptionAsync(Document d return description.WithTaggedParts(parts); } + + /// + /// Internal for testing purposes only. + /// + internal static async Task GetTextChangeAsync( + CompletionService service, Document document, CompletionItem item, + char? commitKey = null, CancellationToken cancellationToken = default(CancellationToken)) + { + var change = await service.GetChangeAsync(document, item, commitKey, cancellationToken).ConfigureAwait(false); + + // normally the items that produce multiple changes are not expecting to trigger the behaviors that rely on looking at the text + if (change.TextChanges.Length == 1) + { + return change.TextChanges[0]; + } + else + { + return new TextChange(item.Span, item.DisplayText); + } + } } } diff --git a/src/EditorFeatures/Test/Completion/AbstractCompletionProviderTests.cs b/src/EditorFeatures/Test/Completion/AbstractCompletionProviderTests.cs index ece3ef7ba1590e3db050bf7e33438a7d6ff87e78..e15fdeab367df43fe3ab7d3479dd8466603dd458 100644 --- a/src/EditorFeatures/Test/Completion/AbstractCompletionProviderTests.cs +++ b/src/EditorFeatures/Test/Completion/AbstractCompletionProviderTests.cs @@ -6,13 +6,12 @@ using System.Security; using System.Threading; using System.Threading.Tasks; -using System.Windows.Threading; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Completion; +using Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.LanguageServices; using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Text; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; @@ -313,7 +312,7 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document { var completionRules = GetCompletionHelper(document, service); var textView = (await WorkspaceFixture.GetWorkspaceAsync()).Documents.Single().GetTextView(); - VerifyCustomCommitWorker(customCommitCompletionProvider, firstItem, completionRules, textView, textBuffer, codeBeforeCommit, expectedCodeAfterCommit, commitChar); + VerifyCustomCommitWorker(service, customCommitCompletionProvider, firstItem, completionRules, textView, textBuffer, codeBeforeCommit, expectedCodeAfterCommit, commitChar); } else { @@ -333,9 +332,7 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document string actualExpectedCode = null; MarkupTestFile.GetPosition(expectedCodeAfterCommit, out actualExpectedCode, out expectedCaretPosition); - CompletionHelper completionRules = GetCompletionHelper(document, service); - - if (commitChar.HasValue && !completionRules.IsCommitCharacter(completionItem, commitChar.Value, string.Empty)) + if (commitChar.HasValue && !Controller.IsCommitCharacter(service.GetRules(), completionItem, commitChar.Value, string.Empty)) { Assert.Equal(codeBeforeCommit, actualExpectedCode); return; @@ -359,6 +356,7 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document } internal virtual void VerifyCustomCommitWorker( + CompletionService service, ICustomCommitCompletionProvider customCommitCompletionProvider, CompletionItem completionItem, CompletionHelper completionRules, @@ -372,7 +370,7 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document string actualExpectedCode = null; MarkupTestFile.GetPosition(expectedCodeAfterCommit, out actualExpectedCode, out expectedCaretPosition); - if (commitChar.HasValue && !completionRules.IsCommitCharacter(completionItem, commitChar.Value, string.Empty)) + if (commitChar.HasValue && !Controller.IsCommitCharacter(service.GetRules(), completionItem, commitChar.Value, string.Empty)) { Assert.Equal(codeBeforeCommit, actualExpectedCode); return; @@ -407,7 +405,8 @@ private async Task VerifyCustomCommitProviderCheckResultsAsync(Document document } } - private async Task VerifyProviderCommitCheckResultsAsync(Document document, int position, string itemToCommit, string expectedCodeAfterCommit, char? commitCharOpt, string textTypedSoFar) + private async Task VerifyProviderCommitCheckResultsAsync( + Document document, int position, string itemToCommit, string expectedCodeAfterCommit, char? commitCharOpt, string textTypedSoFar) { var workspace = await WorkspaceFixture.GetWorkspaceAsync(); var textBuffer = workspace.Documents.Single().TextBuffer; @@ -422,9 +421,10 @@ private async Task VerifyProviderCommitCheckResultsAsync(Document document, int var text = await document.GetTextAsync(); - if (commitChar == '\t' || completionRules.IsCommitCharacter(firstItem, commitChar, textTypedSoFar)) + if (commitChar == '\t' || Controller.IsCommitCharacter(service.GetRules(), firstItem, commitChar, textTypedSoFar)) { - var textChange = CompletionHelper.GetTextChangeAsync(service, document, firstItem, commitChar).Result; + var textChange = await DescriptionModifyingPresentationItem.GetTextChangeAsync( + service, document, firstItem, commitChar); // Adjust TextChange to include commit character, so long as it isn't TAB. if (commitChar != '\t') diff --git a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb index d19394b1ddceb9b911b287d0d3c4ee1138043767..e7d9f92b5667d3bc9d2fe070e7688996cae9c16e 100644 --- a/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb +++ b/src/EditorFeatures/VisualBasicTest/Completion/CompletionProviders/AbstractVisualBasicCompletionProviderTests.vb @@ -3,6 +3,7 @@ Imports System.Collections.Immutable Imports Microsoft.CodeAnalysis Imports Microsoft.CodeAnalysis.Completion +Imports Microsoft.CodeAnalysis.Editor.Implementation.IntelliSense.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Completion Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces Imports Microsoft.CodeAnalysis.Text @@ -121,8 +122,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Dim completionList = Await GetCompletionListAsync(service, document, position, CompletionTrigger.Default) Dim item = completionList.Items.First(Function(i) i.DisplayText.StartsWith(textTypedSoFar)) - Dim helper = CompletionHelper.GetHelper(document, service) - Assert.Equal(expected, helper.SendEnterThroughToEditor(item, textTypedSoFar, document.Options)) + Assert.Equal(expected, Controller.SendEnterThroughToEditor(service.GetRules(), item, textTypedSoFar)) End Using End Function @@ -145,11 +145,11 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.UnitTests.Completion.Complet Dim helper = CompletionHelper.GetHelper(document, service) For Each ch In chars - Assert.True(helper.IsCommitCharacter(item, ch, textTypedSoFar), $"Expected '{ch}' to be a commit character") + Assert.True(Controller.IsCommitCharacter(service.GetRules(), item, ch, textTypedSoFar), $"Expected '{ch}' to be a commit character") Next Dim chr = "x"c - Assert.False(helper.IsCommitCharacter(item, chr, textTypedSoFar), $"Expected '{chr}' NOT to be a commit character") + Assert.False(Controller.IsCommitCharacter(service.GetRules(), item, chr, textTypedSoFar), $"Expected '{chr}' NOT to be a commit character") End Using End Function