Skip to content

Commit

Permalink
feat: Add option to increase the indentation in multi-level lists
Browse files Browse the repository at this point in the history
Add property MdSerializationOptions.MinimumListIndentationWidth to
control indentation in multi-level lists.
List items are always indented at by at least the length of the list
marker (2 for bullet list, 3 or more for ordered lists).
With this change, the indentation is now the maximum of the
list marked length and the specified indentation width.

Default value of the property is 2, so lists serialized using the
default options are indented by the same amount as prior to the
introduction of the option.
  • Loading branch information
ap0llo committed Oct 2, 2019
1 parent 3785159 commit 784633c
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ namespace Grynwald.MarkdownGenerator
public Grynwald.MarkdownGenerator.MdEmphasisStyle EmphasisStyle { get; set; }
public Grynwald.MarkdownGenerator.MdHeadingStyle HeadingStyle { get; set; }
public int MaxLineLength { get; set; }
public int MinimumListIndentationWidth { get; set; }
public Grynwald.MarkdownGenerator.MdOrderedListStyle OrderedListStyle { get; set; }
public Grynwald.MarkdownGenerator.MdTableStyle TableStyle { get; set; }
public Grynwald.MarkdownGenerator.ITextFormatter TextFormatter { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,92 @@ public void Serializer_respects_OrderedListStyle_serialization_option(MdOrderedL
);
}

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
[InlineData(5)]
[InlineData(6)]
public void Serializer_respects_MinimumListIndentationWidth_for_ordered_lists(int indentation)
{
var options = new MdSerializationOptions()
{
MinimumListIndentationWidth = indentation
};

// List items are always indented by at least the length of the list marker.
// In this test, the marker length is 3 for all items, e.g. '1. '

AssertToStringEquals(
$"1. Item1\r\n" +
$"{new String(' ', Math.Max(indentation, 3))}1. Item 1.1\r\n" +
$"{new String(' ', Math.Max(indentation, 3) * 2)}1. Item 1.1.1\r\n" +
$"2. Item2\r\n" +
$"{new String(' ', Math.Max(indentation, 3))}1. Item 2.1\r\n",
new MdDocument(
new MdOrderedList(
new MdListItem(
new MdParagraph("Item1"),
new MdOrderedList(
new MdListItem(
new MdParagraph("Item 1.1"),
new MdOrderedList(
new MdListItem("Item 1.1.1"))))
),
new MdListItem(
new MdParagraph("Item2"),
new MdOrderedList(
new MdListItem("Item 2.1"))
)
)),
options
);
}

[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
[InlineData(5)]
[InlineData(6)]
public void Serializer_respects_MinimumListIndentationWidth_for_bullet_lists(int indentation)
{
var options = new MdSerializationOptions()
{
MinimumListIndentationWidth = indentation
};

// List items are always indented by at least the length of the list marker.
// In this test, the marker length is 2 for all items: '- '

AssertToStringEquals(
$"- Item1\r\n" +
$"{new String(' ', Math.Max(indentation, 2))}- Item 1.1\r\n" +
$"{new String(' ', Math.Max(indentation, 2) * 2)}- Item 1.1.1\r\n" +
$"- Item2\r\n" +
$"{new String(' ', Math.Max(indentation, 2))}- Item 2.1\r\n",
new MdDocument(
new MdBulletList(
new MdListItem(
new MdParagraph("Item1"),
new MdBulletList(
new MdListItem(
new MdParagraph("Item 1.1"),
new MdBulletList(
new MdListItem("Item 1.1.1"))))
),
new MdListItem(
new MdParagraph("Item2"),
new MdBulletList(
new MdListItem("Item 2.1"))
)
)),
options
);
}

[Theory]
[InlineData(MdThematicBreakStyle.Underscore, '_', MdBulletListStyle.Asterisk, '*')]
[InlineData(MdThematicBreakStyle.Underscore, '_', MdBulletListStyle.Dash, '-')]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ public void Properties_of_non_default_instance_can_be_modified(string propertyNa
Assert.Equal(newValue, actualValue);
}

[Theory]
[InlineData(-1)]
[InlineData(-10)]
[InlineData(-5)]
public void ListIndentationWidth_throws_ArgumentOutOfRangeException_when_set_to_a_negative_value(int value)
{
var instance = new MdSerializationOptions();
Assert.Throws<ArgumentOutOfRangeException>(() => instance.MinimumListIndentationWidth = value);
}

private object GetTestValue(Type type)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -417,10 +417,10 @@ private ListPrefixHandler GetListPrefixHandler(MdList list)
switch (list)
{
case MdBulletList _:
return new BulletListPrefixHandler(m_Options.BulletListStyle);
return new BulletListPrefixHandler(m_Options);

case MdOrderedList _:
return new OrderedListPrefixHandler(m_Options.OrderedListStyle);
return new OrderedListPrefixHandler(m_Options);

default:
throw new NotSupportedException($"Unsupported list type: {list.GetType().FullName}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@ namespace Grynwald.MarkdownGenerator.Internal
/// Prefix handler for bullet lists
/// </summary>
internal sealed class BulletListPrefixHandler : ListPrefixHandler
{
private readonly MdBulletListStyle m_BulletListStyle; // determines the list marker for bullet lists (either -, + or *)

{
public BulletListPrefixHandler(MdSerializationOptions serializationOptions) : base(serializationOptions)
{ }

public BulletListPrefixHandler(MdBulletListStyle bulletListStyle)
{
m_BulletListStyle = bulletListStyle;
}


protected override string GetListMarker()
{
switch (m_BulletListStyle)
switch (m_SerializationOptions.BulletListStyle)
{
case MdBulletListStyle.Dash:
return "- ";
Expand All @@ -30,7 +25,7 @@ protected override string GetListMarker()
return "* ";

default:
throw new ArgumentException($"Unsupported bullet list style: {m_BulletListStyle}");
throw new ArgumentException($"Unsupported bullet list style: {m_SerializationOptions.BulletListStyle}");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@ namespace Grynwald.MarkdownGenerator.Internal
{
internal abstract class ListPrefixHandler : IPrefixHandler
{
protected readonly MdSerializationOptions m_SerializationOptions;
protected string m_ListPrefix; // the prefix for lines other than the first line
protected bool m_LineWritten = false; // indicates if any lines have been written in the current list item
protected string m_ListMarker; // the prefix for list items


public ListPrefixHandler(MdSerializationOptions serializationOptions)
{
m_SerializationOptions = serializationOptions ?? throw new ArgumentNullException(nameof(serializationOptions));
}


public int PrefixLength => m_LineWritten ? m_ListPrefix.Length : m_ListMarker.Length;


Expand Down Expand Up @@ -38,8 +45,8 @@ public virtual void BeginListItem()
// update list marker
// marker is a dash, plus or asterisk for bullet lists and the number followed by a period for ordered lists
m_ListMarker = GetListMarker();
m_ListPrefix = new String(' ', m_ListMarker.Length);

m_ListPrefix = new string(' ', Math.Max(m_ListMarker.Length, m_SerializationOptions.MinimumListIndentationWidth));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,12 @@ namespace Grynwald.MarkdownGenerator.Internal
/// Prefix handler for ordered lists
/// </summary>
internal sealed class OrderedListPrefixHandler : ListPrefixHandler
{
private readonly MdOrderedListStyle m_OrderedListStyle; // determines the list marker for ordered lists (either '.' or ')' )
private int m_ListItemNumber = 0; // the number of the list item (for ordered lists)
{
private int m_ListItemNumber = 0; // the number of the list item (for ordered lists)


public OrderedListPrefixHandler(MdOrderedListStyle orderedListStyle)
{
m_OrderedListStyle = orderedListStyle;
}
public OrderedListPrefixHandler(MdSerializationOptions serializationOptions) : base(serializationOptions)
{ }


public override void BeginListItem()
Expand All @@ -28,18 +25,18 @@ public override void BeginListItem()

protected override string GetListMarker()
{
switch (m_OrderedListStyle)
switch (m_SerializationOptions.OrderedListStyle)
{
case MdOrderedListStyle.Dot:
return $"{m_ListItemNumber}. ";

case MdOrderedListStyle.Parenthesis:
return $"{m_ListItemNumber}) ";

default:
throw new ArgumentException($"Unsupported ordered list style: {m_OrderedListStyle}");
throw new ArgumentException($"Unsupported ordered list style: {m_SerializationOptions.OrderedListStyle}");
}
}

}
}
27 changes: 27 additions & 0 deletions src/MarkdownGenerator/_Model/_Options/MdSerializationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class MdSerializationOptions
private MdCodeBlockStyle m_CodeBlockStyle = MdCodeBlockStyle.Backtick;
private MdBulletListStyle m_BulletListStyle = MdBulletListStyle.Dash;
private MdOrderedListStyle m_OrderedListStyle = MdOrderedListStyle.Dot;
private int m_ListIndentationWidth = 2;
private MdTableStyle m_TableStyle = MdTableStyle.GFM;
private int m_MaxLineLength = -1;
private ITextFormatter m_TextFormatter = DefaultTextFormatter.Instance;
Expand Down Expand Up @@ -106,6 +107,32 @@ public MdOrderedListStyle OrderedListStyle
}

/// <summary>
/// Gets or sets the minimum number of characters to use for indenting list items
/// in multi-level lists (compared to items of the outer list level).
/// <para>
/// The value indicates a minimum indentation.
/// List items are always indented at least by the length of the list marker.
/// </para>
/// <para>
/// Default value: <c>2</c>
/// </para>
/// </summary>
/// <remarks>
/// Setting the indentation to less than <c>2</c> will cause multi-level lists to
/// be "flattened" to a single level.
/// </remarks>
/// <exception cref="ArgumentOutOfRangeException">Thrown when setting the property to a negative value.</exception>
public int MinimumListIndentationWidth
{
get => m_ListIndentationWidth;
set
{
if (value < 0)
throw new ArgumentOutOfRangeException(nameof(value), "Value must not be less than 0");

SetValue(nameof(MinimumListIndentationWidth), value, ref m_ListIndentationWidth);
}
}

/// <summary>
/// Gets or sets the style for tables.
Expand Down

0 comments on commit 784633c

Please sign in to comment.