diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Completion/CompletionService.cs b/src/OmniSharp.Roslyn.CSharp/Services/Completion/CompletionService.cs index 187383eb8d..a95e2d6ad6 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Completion/CompletionService.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Completion/CompletionService.cs @@ -174,6 +174,16 @@ public async Task Handle(CompletionRequest request) string providerName = completion.GetProviderName(); switch (providerName) { + case CompletionItemExtensions.EmeddedLanguageCompletionProvider: + // The Regex completion provider can change escapes based on whether + // we're in a verbatim string or not + { + CompletionChange change = await completionService.GetChangeAsync(document, completion); + Debug.Assert(typedSpan == change.TextChange.Span); + insertText = change.TextChange.NewText!; + } + break; + case CompletionItemExtensions.InternalsVisibleToCompletionProvider: // The IVT completer doesn't add extra things before the completion // span, only assembly keys at the end if they exist. diff --git a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs index 866ae0b1d0..e8f828aa6a 100644 --- a/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs +++ b/src/OmniSharp.Roslyn.CSharp/Services/Intellisense/CompletionItemExtensions.cs @@ -26,6 +26,7 @@ internal static class CompletionItemExtensions internal const string XmlDocCommentCompletionProvider = "Microsoft.CodeAnalysis.CSharp.Completion.Providers.XmlDocCommentCompletionProvider"; internal const string TypeImportCompletionProvider = "Microsoft.CodeAnalysis.CSharp.Completion.Providers.TypeImportCompletionProvider"; internal const string ExtensionMethodImportCompletionProvider = "Microsoft.CodeAnalysis.CSharp.Completion.Providers.ExtensionMethodImportCompletionProvider"; + internal const string EmeddedLanguageCompletionProvider = "Microsoft.CodeAnalysis.CSharp.Completion.Providers.EmbeddedLanguageCompletionProvider"; private const string ProviderName = nameof(ProviderName); private const string SymbolCompletionItem = "Microsoft.CodeAnalysis.Completion.Providers.SymbolCompletionItem"; private const string SymbolKind = nameof(SymbolKind); diff --git a/tests/OmniSharp.Roslyn.CSharp.Tests/CompletionFacts.cs b/tests/OmniSharp.Roslyn.CSharp.Tests/CompletionFacts.cs index 917fb0dec2..56b8f607bd 100644 --- a/tests/OmniSharp.Roslyn.CSharp.Tests/CompletionFacts.cs +++ b/tests/OmniSharp.Roslyn.CSharp.Tests/CompletionFacts.cs @@ -1336,6 +1336,48 @@ public async Task InternalsVisibleToCompletionSkipsMiscProject() Assert.Equal("AssemblyNameVal", completions.Items[0].InsertText); } + [ConditionalTheory(typeof(WindowsOnly))] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task RegexCompletionInNormalString(string filename) + { + const string input = @" +using System.Text.RegularExpressions; +class Foo +{ + public void M() + { + _ = new Regex(""$$""); + } +}"; + + var completions = await FindCompletionsAsync(filename, input, SharedOmniSharpTestHost); + var aCompletion = completions.Items.First(c => c.Label == @"\A"); + Assert.NotNull(aCompletion); + Assert.Equal(@"\\A", aCompletion.InsertText); + } + + [ConditionalTheory(typeof(WindowsOnly))] + [InlineData("dummy.cs")] + [InlineData("dummy.csx")] + public async Task RegexCompletionInVerbatimString(string filename) + { + const string input = @" +using System.Text.RegularExpressions; +class Foo +{ + public void M() + { + _ = new Regex(@""$$""); + } +}"; + + var completions = await FindCompletionsAsync(filename, input, SharedOmniSharpTestHost); + var aCompletion = completions.Items.First(c => c.Label == @"\A"); + Assert.NotNull(aCompletion); + Assert.Equal(@"\A", aCompletion.InsertText); + } + private CompletionService GetCompletionService(OmniSharpTestHost host) => host.GetRequestHandler(EndpointName);