From 4bd8e3bdc24a26b346d64fbd0d1cc5cbd1659c5d Mon Sep 17 00:00:00 2001 From: David Barbet Date: Fri, 16 May 2025 15:03:02 -0700 Subject: [PATCH] Fix angle brackets in generics in hover --- .../Extensions/ProtocolConversions.cs | 2 +- .../ProtocolUnitTests/Hover/HoverTests.cs | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 187cd244bdfc4..f3c9f8249046b 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -41,7 +41,7 @@ internal static partial class ProtocolConversions private static readonly char[] s_dirSeparators = [PathUtilities.DirectorySeparatorChar, PathUtilities.AltDirectorySeparatorChar]; - private static readonly Regex s_markdownEscapeRegex = new(@"([\\`\*_\{\}\[\]\(\)#+\-\.!])", RegexOptions.Compiled); + private static readonly Regex s_markdownEscapeRegex = new(@"([\\`\*_\{\}\[\]\(\)#+\-\.!<>])", RegexOptions.Compiled); // NOTE: While the spec allows it, don't use Function and Method, as both VS and VS Code display them the same // way which can confuse users diff --git a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs index d272e37c274d3..af452f1de5f70 100644 --- a/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs +++ b/src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs @@ -527,6 +527,7 @@ public async Task DoAsync() expectedLocation).ConfigureAwait(false); Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); } + [Theory, CombinatorialData] public async Task TestGetHoverAsync_UsesNonBreakingSpaceForSupportedPlatforms(bool mutatingLspWorkspace) { @@ -586,6 +587,47 @@ static void Main(string[] args) Assert.Equal(expectedMarkdown, result.Contents.Fourth.Value); } + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/vscode-csharp/issues/6577")] + public async Task TestGetHoverAsync_EscapesAngleBracketsInGenerics(bool mutatingLspWorkspace) + { + var markup = + """ + using System.Collections.Generic; + using System.Collections.Immutable; + using System.Threading.Tasks; + class C + { + private async Task>> GetData() + { + {|caret:var|} d = await GetData(); + return null; + } + } + """; + var clientCapabilities = new LSP.ClientCapabilities + { + TextDocument = new LSP.TextDocumentClientCapabilities { Hover = new LSP.HoverSetting { ContentFormat = [LSP.MarkupKind.Markdown] } } + }; + await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, clientCapabilities); + var expectedLocation = testLspServer.GetLocations("caret").Single(); + + var expectedMarkdown = """ + ```csharp + interface System.Collections.Generic.IDictionary + ``` + + + TKey is string + TValue is ImmutableArray\ + + """; + + var results = await RunGetHoverAsync( + testLspServer, + expectedLocation).ConfigureAwait(false); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); + } + private static async Task RunGetHoverAsync( TestLspServer testLspServer, LSP.Location caret,