Skip to content

[WIP] Fix rendering of various elements #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/FencedCodeBlockRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,26 @@ protected override void Write(VT100Renderer renderer, FencedCodeBlock obj)
{
if (obj?.Lines.Lines != null)
{
bool f = true;
foreach (StringLine codeLine in obj.Lines.Lines)
{
if (!string.IsNullOrWhiteSpace(codeLine.ToString()))
{
if (f) f = false;
else renderer.WriteLine();

// If the code block is of type YAML, then tab to right to improve readability.
// This specifically helps for parameters help content.
if (string.Equals(obj.Info, "yaml", StringComparison.OrdinalIgnoreCase))
{
renderer.Write("\t").WriteLine(codeLine.ToString());
renderer.Write("\t").Write(codeLine.ToString());
}
else
{
renderer.WriteLine(renderer.EscapeSequences.FormatCode(codeLine.ToString(), isInline: false));
renderer.Write(renderer.EscapeSequences.FormatCode(codeLine.ToString(), isInline: false));
}
}
}

// Add a blank line after the code block for better readability.
renderer.WriteLine();
}
}
}
Expand Down
18 changes: 6 additions & 12 deletions src/HeaderBlockRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,27 @@ protected override void Write(VT100Renderer renderer, HeadingBlock obj)
switch (obj.Level)
{
case 1:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader1(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader1(headerText));
break;

case 2:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader2(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader2(headerText));
break;

case 3:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader3(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader3(headerText));
break;

case 4:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader4(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader4(headerText));
break;

case 5:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader5(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader5(headerText));
break;

case 6:
renderer.WriteLine(renderer.EscapeSequences.FormatHeader6(headerText));
renderer.WriteLine();
renderer.Write(renderer.EscapeSequences.FormatHeader6(headerText));
break;
}
}
Expand Down
12 changes: 1 addition & 11 deletions src/LeafInlineRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,7 @@ internal class LeafInlineRenderer : VT100ObjectRenderer<LeafInline>
{
protected override void Write(VT100Renderer renderer, LeafInline obj)
{
// If the next sibling is null, then this is the last line in the paragraph.
// Add new line character at the end.
// Else just write without newline at the end.
if (obj.NextSibling == null)
{
renderer.WriteLine(obj.ToString());
}
else
{
renderer.Write(obj.ToString());
}
renderer.Write(obj.ToString());
}
}
}
45 changes: 16 additions & 29 deletions src/ListBlockRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,23 @@ internal class ListBlockRenderer : VT100ObjectRenderer<ListBlock>
{
protected override void Write(VT100Renderer renderer, ListBlock obj)
{
// start index of a numbered block.
int index = 1;
for (int idx = 0; idx < obj.Count; idx++)
{
if (idx > 0) renderer.WriteLine();

Block block = obj[idx];

if (obj.IsOrdered)
{
renderer.Write((idx + 1).ToString()).Write(". ");
}
else
{
renderer.Write(obj.BulletType).Write(" ");
}

renderer.Write(block);

foreach (var item in obj)
{
if (item is ListItemBlock listItem)
{
if (obj.IsOrdered)
{
RenderNumberedList(renderer, listItem, index++);
}
else
{
renderer.Write(listItem);
}
}
}

renderer.WriteLine();
}

private static void RenderNumberedList(VT100Renderer renderer, ListItemBlock block, int index)
{
// For a numbered list, we need to make sure the index is incremented.
foreach (var line in block)
{
if (line is ParagraphBlock paragraphBlock)
{
renderer.Write(index.ToString()).Write(". ").Write(paragraphBlock.Inline);
}
}
}
}
Expand Down
66 changes: 4 additions & 62 deletions src/ListItemBlockRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,68 +13,10 @@ internal class ListItemBlockRenderer : VT100ObjectRenderer<ListItemBlock>
{
protected override void Write(VT100Renderer renderer, ListItemBlock obj)
{
if (obj.Parent is ListBlock parent)
{
if (!parent.IsOrdered)
{
foreach (var line in obj)
{
RenderWithIndent(renderer, line, parent.BulletType, 0);
}
}
}
}

private static void RenderWithIndent(VT100Renderer renderer, MarkdownObject block, char listBullet, int indentLevel)
{
// Indent left by 2 for each level on list.
string indent = Padding(indentLevel * 2);

if (block is ParagraphBlock paragraphBlock)
{
renderer.Write(indent).Write(listBullet).Write(" ").Write(paragraphBlock.Inline);
}
else
{
// If there is a sublist, the block is a ListBlock instead of ParagraphBlock.
if (block is ListBlock subList)
{
foreach (var subListItem in subList)
{
if (subListItem is ListItemBlock subListItemBlock)
{
foreach (var line in subListItemBlock)
{
// Increment indent level for sub list.
RenderWithIndent(renderer, line, listBullet, indentLevel + 1);
}
}
}
}
}
}

// Typical padding is at most a screen's width, any more than that and we won't bother caching.
private const int IndentCacheMax = 120;

private static readonly string[] IndentCache = new string[IndentCacheMax];

internal static string Padding(int countOfSpaces)
{
if (countOfSpaces >= IndentCacheMax)
{
return new string(' ', countOfSpaces);
}

var result = IndentCache[countOfSpaces];

if (result == null)
{
Interlocked.CompareExchange(ref IndentCache[countOfSpaces], new string(' ', countOfSpaces), comparand: null);
result = IndentCache[countOfSpaces];
}

return result;
// 2 spaces for indentation
renderer.PushIndent(" ");
renderer.WriteChildrenJoinNewLine(obj);
renderer.PopIndent();
}
}
}
2 changes: 1 addition & 1 deletion src/MarkdownConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public static MarkdownInfo Convert(string markdownString, MarkdownConversionType

if (conversionType.HasFlag(MarkdownConversionType.VT100))
{
pipeline = new MarkdownPipelineBuilder().Build();
pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();

// Use the VT100 renderer.
var renderer = new VT100Renderer(writer, optionInfo);
Expand Down
29 changes: 29 additions & 0 deletions src/MarkdownDocumentRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Markdig.Syntax;
using Markdig.Syntax.Inlines;

namespace Microsoft.PowerShell.MarkdownRender
{
/// <summary>
/// Renderer for adding VT100 escape sequences for paragraphs.
/// </summary>
internal class MarkdownDocumentRenderer : VT100ObjectRenderer<MarkdownDocument>
{
protected override void Write(VT100Renderer renderer, MarkdownDocument obj)
{
bool f = true;
foreach (Block item in obj)
{
if (item.Span.IsEmpty) continue;

if (f) f = false;
else renderer.WriteLine();

renderer.Write(item);
renderer.WriteLine();
}
}
}
}
44 changes: 22 additions & 22 deletions src/ParagraphBlockRenderer.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Markdig.Syntax;

namespace Microsoft.PowerShell.MarkdownRender
{
/// <summary>
/// Renderer for adding VT100 escape sequences for paragraphs.
/// </summary>
internal class ParagraphBlockRenderer : VT100ObjectRenderer<ParagraphBlock>
{
protected override void Write(VT100Renderer renderer, ParagraphBlock obj)
{
// Call the renderer for children, leaf inline or line breaks.
renderer.WriteChildren(obj.Inline);

// Add new line at the end of the paragraph.
renderer.WriteLine();
}
}
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Markdig.Syntax;
namespace Microsoft.PowerShell.MarkdownRender
{
/// <summary>
/// Renderer for adding VT100 escape sequences for paragraphs.
/// </summary>
internal class ParagraphBlockRenderer : VT100ObjectRenderer<ParagraphBlock>
{
/**
* Does not append newline after rendering the paragraph.
*/
protected override void Write(VT100Renderer renderer, ParagraphBlock obj)
{
// Call the renderer for children, leaf inline or line breaks.
renderer.WriteChildren(obj.Inline);
}
}
}
11 changes: 3 additions & 8 deletions src/QuoteBlockRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,9 @@ internal class QuoteBlockRenderer : VT100ObjectRenderer<QuoteBlock>
{
protected override void Write(VT100Renderer renderer, QuoteBlock obj)
{
// Iterate through each item and add the quote character before the content.
foreach (var item in obj)
{
renderer.Write(obj.QuoteChar).Write(" ").Write(item);
}

// Add blank line after the quote block.
renderer.WriteLine();
renderer.PushIndent(obj.QuoteChar + " ");
renderer.WriteChildrenJoinNewLine(obj);
renderer.PopIndent();
}
}
}
62 changes: 62 additions & 0 deletions src/TableRenderer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Markdig.Extensions.Tables;
using Markdig.Syntax;

namespace Microsoft.PowerShell.MarkdownRender
{
/// <summary>
/// Renderer for adding VT100 escape sequences for quote blocks.
/// </summary>
internal class TableRenderer : VT100ObjectRenderer<Table>
{
protected override void Write(VT100Renderer renderer, Table table)
{
// TODO: improve table rendering
// Probably have to create a new renderer, render the content as string,
// and then process the string to table in order to align the columns
// Additionally, the new rendered content will not have proper length because of
// VT100 escape sequences, therefore a sanitization step is needed
// The sanitization regex is currently in VT100Tests.cs:VT100Tests.MarkdownDocument
// Console column width can be exposed by renderer in order
// to prevent tables from being wider than console

for (int i = 0; i < table.Count; i++)
{
Block b = table[i];
if (b.Span.IsEmpty) continue;

if (i > 0) renderer.WriteLine();
if (i == 1)
{
if (table[0] is TableRow head)
{
foreach (var cell in head)
{
renderer.Write("|-");
renderer.Write(new string('-', cell.Span.End - cell.Span.Start));
}
renderer.Write("|");
}
renderer.WriteLine();
}

if (b is ContainerBlock cb)
{
foreach (var item in cb)
{
renderer.Write("| ");
renderer.Write(item);
renderer.Write(" ");
}

renderer.Write("|");
} else
{
renderer.Write(b);
}
}
}
}
}
Loading