Skip to content

Commit c3c7ad6

Browse files
authored
Fix angle brackets in generics in hover (#78621)
Resolves #77233 Angle brackets can be used as html elements in markdown, and so sometimes need to be escaped (there is no issue if we always escape them).
2 parents 74a8a6f + 4bd8e3b commit c3c7ad6

File tree

2 files changed

+43
-1
lines changed

2 files changed

+43
-1
lines changed

src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ internal static partial class ProtocolConversions
4141

4242
private static readonly char[] s_dirSeparators = [PathUtilities.DirectorySeparatorChar, PathUtilities.AltDirectorySeparatorChar];
4343

44-
private static readonly Regex s_markdownEscapeRegex = new(@"([\\`\*_\{\}\[\]\(\)#+\-\.!])", RegexOptions.Compiled);
44+
private static readonly Regex s_markdownEscapeRegex = new(@"([\\`\*_\{\}\[\]\(\)#+\-\.!<>])", RegexOptions.Compiled);
4545

4646
// NOTE: While the spec allows it, don't use Function and Method, as both VS and VS Code display them the same
4747
// way which can confuse users

src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,7 @@ public async Task<string> DoAsync()
527527
expectedLocation).ConfigureAwait(false);
528528
Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value);
529529
}
530+
530531
[Theory, CombinatorialData]
531532
public async Task TestGetHoverAsync_UsesNonBreakingSpaceForSupportedPlatforms(bool mutatingLspWorkspace)
532533
{
@@ -586,6 +587,47 @@ static void Main(string[] args)
586587
Assert.Equal(expectedMarkdown, result.Contents.Fourth.Value);
587588
}
588589

590+
[Theory, CombinatorialData, WorkItem("https://github.com/dotnet/vscode-csharp/issues/6577")]
591+
public async Task TestGetHoverAsync_EscapesAngleBracketsInGenerics(bool mutatingLspWorkspace)
592+
{
593+
var markup =
594+
"""
595+
using System.Collections.Generic;
596+
using System.Collections.Immutable;
597+
using System.Threading.Tasks;
598+
class C
599+
{
600+
private async Task<IDictionary<string, ImmutableArray<int>>> GetData()
601+
{
602+
{|caret:var|} d = await GetData();
603+
return null;
604+
}
605+
}
606+
""";
607+
var clientCapabilities = new LSP.ClientCapabilities
608+
{
609+
TextDocument = new LSP.TextDocumentClientCapabilities { Hover = new LSP.HoverSetting { ContentFormat = [LSP.MarkupKind.Markdown] } }
610+
};
611+
await using var testLspServer = await CreateTestLspServerAsync(markup, mutatingLspWorkspace, clientCapabilities);
612+
var expectedLocation = testLspServer.GetLocations("caret").Single();
613+
614+
var expectedMarkdown = """
615+
```csharp
616+
interface System.Collections.Generic.IDictionary<TKey, TValue>
617+
```
618+
619+
620+
TKey&nbsp;is&nbsp;string
621+
TValue&nbsp;is&nbsp;ImmutableArray\<int\>
622+
623+
""";
624+
625+
var results = await RunGetHoverAsync(
626+
testLspServer,
627+
expectedLocation).ConfigureAwait(false);
628+
Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value);
629+
}
630+
589631
private static async Task<LSP.Hover> RunGetHoverAsync(
590632
TestLspServer testLspServer,
591633
LSP.Location caret,

0 commit comments

Comments
 (0)