Skip to content

Commit

Permalink
Add Hover test for code block in DocComments
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeRobich committed Sep 24, 2024
1 parent ed773f3 commit 14b8958
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 18 deletions.
37 changes: 19 additions & 18 deletions src/LanguageServer/Protocol/Extensions/ProtocolConversions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -936,29 +936,22 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray<Tag
codeFence = null;

break;
case TextTags.Text when taggedText.Style.HasFlag(TaggedTextStyle.Code):
// This represents `<code></code>` in doc comments. It can be a block or it can be inline.
case TextTags.Text when taggedText.Style == (TaggedTextStyle.Code | TaggedTextStyle.PreserveWhitespace):
// This represents a block of code (`<code></code>`) 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())
{
// If the current line is empty, we can append a code block.
markdownBuilder.AppendLine($"{BlockCodeFence}text");
markdownBuilder.AppendLine(taggedText.Text);
markdownBuilder.AppendLine(BlockCodeFence);
}
else
{
// There is text on the line already - we should append an in-line code block.
markdownBuilder.Append($"`{taggedText.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);
Expand All @@ -975,6 +968,14 @@ public static LSP.MarkupContent GetDocumentationMarkupContent(ImmutableArray<Tag
Value = content,
};

static void AppendLineBreak(MarkdownContentBuilder markdownBuilder)
{
// A line ending with double space and a new line indicates to markdown
// to render a single-spaced line break.
markdownBuilder.Append(" ");
markdownBuilder.AppendLine();
}

static string GetCodeBlockLanguageName(string language)
{
return language switch
Expand Down
42 changes: 42 additions & 0 deletions src/LanguageServer/ProtocolUnitTests/Hover/HoverTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,48 @@ void A.AMethod(int i)
Assert.Equal(expectedMarkdown, results.Contents.Fourth.Value);
}

[Theory, CombinatorialData]
public async Task TestGetHoverAsync_UsingMarkupContentDoesNotEscapeCodeBlock(bool mutatingLspWorkspace)
{
var markup =
@"class A
{
/// <summary>
/// <code>
/// if (true) {
/// Console.WriteLine(""hello"");
/// }
/// </code>
/// </summary>
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)
{
Expand Down

0 comments on commit 14b8958

Please sign in to comment.