diff --git a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs index 79b5ab45911ba..eac849642c1fe 100644 --- a/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs +++ b/src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs @@ -19,7 +19,6 @@ using Microsoft.CodeAnalysis.Internal.Log; using Microsoft.CodeAnalysis.LanguageServer.Handler; using Microsoft.CodeAnalysis.NavigateTo; -using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.SpellCheck; using Microsoft.CodeAnalysis.Tags; @@ -936,12 +935,23 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray`) in doc comments. + // Since code elements optionally support a `lang` attribute and we do not have access to the + // language which was specified at this point, we tell the client to render it as plain text. + + if (!markdownBuilder.IsLineEmpty()) + AppendLineBreak(markdownBuilder); + + // The current line is empty, we can append a code block. + markdownBuilder.AppendLine($"{BlockCodeFence}text"); + markdownBuilder.AppendLine(taggedText.Text); + markdownBuilder.AppendLine(BlockCodeFence); + break; case TextTags.LineBreak: - // A line ending with double space and a new line indicates to markdown - // to render a single-spaced line break. - markdownBuilder.Append(" "); - markdownBuilder.AppendLine(); + AppendLineBreak(markdownBuilder); break; default: var styledText = GetStyledText(taggedText, codeFence != null); @@ -958,6 +968,14 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray + /// + /// if (true) { + /// Console.WriteLine(""hello""); + /// } + /// + /// + void {|caret:AMethod|}(int i) + { + } +}"; + 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 +void A.AMethod(int i) +``` + + +```text +if (true) { + Console.WriteLine(""hello""); +} +``` +"; + + var results = await RunGetHoverAsync( + testLspServer, + expectedLocation).ConfigureAwait(false); + Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value); + } + [Theory, CombinatorialData, WorkItem("https://github.com/dotnet/vscode-csharp/issues/6577")] public async Task TestGetHoverAsync_UsesInlineCodeFencesInAwaitReturn(bool mutatingLspWorkspace) {