Skip to content

Commit

Permalink
Add markerIndent and contentIndent to ListItem
Browse files Browse the repository at this point in the history
This information is required for a renderer producing Markdown.
  • Loading branch information
robinst committed Jan 16, 2024
1 parent 8cf87a3 commit ec66829
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public BlockStart tryStart(ParserState state, MatchedBlockParser matchedBlockPar
}

int newColumn = listData.contentColumn;
ListItemParser listItemParser = new ListItemParser(newColumn - state.getColumn());
ListItemParser listItemParser = new ListItemParser(state.getIndent(), newColumn - state.getColumn());

// prepend the list block if needed
if (!(matched instanceof ListBlockParser) ||
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ public class ListItemParser extends AbstractBlockParser {

private boolean hadBlankLine;

public ListItemParser(int contentIndent) {
public ListItemParser(int markerIndent, int contentIndent) {
this.contentIndent = contentIndent;
block.setMarkerIndent(markerIndent);
block.setContentIndent(contentIndent);
}

@Override
Expand Down
45 changes: 45 additions & 0 deletions commonmark/src/main/java/org/commonmark/node/ListItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,53 @@

public class ListItem extends Block {

private int markerIndent;
private int contentIndent;

@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}

/**
* Returns the indent of the marker such as "-" or "1." in columns (spaces or tab stop of 4).
* <p>
* Some examples and their marker indent:
* <pre>- Foo</pre>
* Marker indent: 0
* <pre> - Foo</pre>
* Marker indent: 1
* <pre> 1. Foo</pre>
* Marker indent: 2
*/
public int getMarkerIndent() {
return markerIndent;
}

public void setMarkerIndent(int markerIndent) {
this.markerIndent = markerIndent;
}

/**
* Returns the indent of the content in columns (spaces or tab stop of 4). The content indent is counted from the
* beginning of the line and includes the marker on the first line.
* <p>
* Some examples and their content indent:
* <pre>- Foo</pre>
* Content indent: 2
* <pre> - Foo</pre>
* Content indent: 3
* <pre> 1. Foo</pre>
* Content indent: 5
* <p>
* Note that subsequent lines in the same list item need to be indented by at least the content indent to be counted
* as part of the list item.
*/
public int getContentIndent() {
return contentIndent;
}

public void setContentIndent(int contentIndent) {
this.contentIndent = contentIndent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.commonmark.test;

import org.commonmark.node.ListItem;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class ListBlockParserTest {

private static final Parser PARSER = Parser.builder().build();

@Test
public void testBulletListIndents() {
assertListItemIndents("* foo", 0, 2);
assertListItemIndents(" * foo", 1, 3);
assertListItemIndents(" * foo", 2, 4);
assertListItemIndents(" * foo", 3, 5);

assertListItemIndents("* foo", 0, 3);
assertListItemIndents("* foo", 0, 4);
assertListItemIndents("* foo", 0, 5);
assertListItemIndents(" * foo", 1, 4);
assertListItemIndents(" * foo", 3, 8);

// The indent is relative to any containing blocks
assertListItemIndents("> * foo", 0, 2);
assertListItemIndents("> * foo", 1, 3);
assertListItemIndents("> * foo", 1, 4);

// Tab counts as 3 spaces here (to the next tab stop column of 4) -> content indent is 1+3
assertListItemIndents("*\tfoo", 0, 4);

// Empty list, content indent is expected to be 2
assertListItemIndents("-\n", 0, 2);
}

@Test
public void testOrderedListIndents() {
assertListItemIndents("1. foo", 0, 3);
assertListItemIndents(" 1. foo", 1, 4);
assertListItemIndents(" 1. foo", 2, 5);
assertListItemIndents(" 1. foo", 3, 6);

assertListItemIndents("1. foo", 0, 4);
assertListItemIndents("1. foo", 0, 5);
assertListItemIndents("1. foo", 0, 6);
assertListItemIndents(" 1. foo", 1, 5);
assertListItemIndents(" 1. foo", 2, 8);

assertListItemIndents("> 1. foo", 0, 3);
assertListItemIndents("> 1. foo", 1, 4);
assertListItemIndents("> 1. foo", 1, 5);

assertListItemIndents("1.\tfoo", 0, 4);
}

private void assertListItemIndents(String input, int expectedMarkerIndent, int expectedContentIndent) {
Node doc = PARSER.parse(input);
ListItem listItem = Nodes.find(doc, ListItem.class);
assertNotNull(listItem);
assertEquals(expectedMarkerIndent, listItem.getMarkerIndent());
assertEquals(expectedContentIndent, listItem.getContentIndent());
}
}
23 changes: 23 additions & 0 deletions commonmark/src/test/java/org/commonmark/test/Nodes.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,27 @@ public static List<Node> getChildren(Node parent) {
}
return children;
}

/**
* Recursively try to find a node with the given type within the children of the specified node.
*
* @param parent The node to get children from (node itself will not be checked)
* @param nodeClass The type of node to find
*/
public static <T> T find(Node parent, Class<T> nodeClass) {
Node node = parent.getFirstChild();
while (node != null) {
Node next = node.getNext();
if (nodeClass.isInstance(node)) {
//noinspection unchecked
return (T) node;
}
T result = find(node, nodeClass);
if (result != null) {
return result;
}
node = next;
}
return null;
}
}

0 comments on commit ec66829

Please sign in to comment.