Skip to content

Commit 43f50dd

Browse files
committed
Merge branch 'issue-80-textcontent-extension-for-gfm-tables' of https://github.com/ahjaworski/commonmark-java
2 parents 66e2d3f + 006d43a commit 43f50dd

7 files changed

Lines changed: 357 additions & 88 deletions

File tree

commonmark-ext-gfm-tables/src/main/java/org/commonmark/ext/gfm/tables/TablesExtension.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
import org.commonmark.Extension;
44
import org.commonmark.ext.gfm.tables.internal.TableBlockParser;
5-
import org.commonmark.ext.gfm.tables.internal.TableNodeRenderer;
5+
import org.commonmark.ext.gfm.tables.internal.TableHtmlNodeRenderer;
6+
import org.commonmark.ext.gfm.tables.internal.TableTextContentNodeRenderer;
67
import org.commonmark.renderer.html.HtmlRenderer;
78
import org.commonmark.renderer.html.HtmlNodeRendererContext;
89
import org.commonmark.renderer.html.HtmlNodeRendererFactory;
910
import org.commonmark.parser.Parser;
1011
import org.commonmark.renderer.NodeRenderer;
12+
import org.commonmark.renderer.text.TextContentNodeRendererContext;
13+
import org.commonmark.renderer.text.TextContentNodeRendererFactory;
14+
import org.commonmark.renderer.text.TextContentRenderer;
1115

1216
/**
1317
* Extension for GFM tables using "|" pipes (GitHub Flavored Markdown).
@@ -20,7 +24,8 @@
2024
* The parsed tables are turned into {@link TableBlock} blocks.
2125
* </p>
2226
*/
23-
public class TablesExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension {
27+
public class TablesExtension implements Parser.ParserExtension, HtmlRenderer.HtmlRendererExtension,
28+
TextContentRenderer.TextContentRendererExtension {
2429

2530
private TablesExtension() {
2631
}
@@ -39,7 +44,17 @@ public void extend(HtmlRenderer.Builder rendererBuilder) {
3944
rendererBuilder.nodeRendererFactory(new HtmlNodeRendererFactory() {
4045
@Override
4146
public NodeRenderer create(HtmlNodeRendererContext context) {
42-
return new TableNodeRenderer(context);
47+
return new TableHtmlNodeRenderer(context);
48+
}
49+
});
50+
}
51+
52+
@Override
53+
public void extend(TextContentRenderer.Builder rendererBuilder) {
54+
rendererBuilder.nodeRendererFactory(new TextContentNodeRendererFactory() {
55+
@Override
56+
public NodeRenderer create(TextContentNodeRendererContext context) {
57+
return new TableTextContentNodeRenderer(context);
4358
}
4459
});
4560
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package org.commonmark.ext.gfm.tables.internal;
2+
3+
import java.util.Collections;
4+
import java.util.Map;
5+
6+
import org.commonmark.ext.gfm.tables.TableBlock;
7+
import org.commonmark.ext.gfm.tables.TableBody;
8+
import org.commonmark.ext.gfm.tables.TableCell;
9+
import org.commonmark.ext.gfm.tables.TableHead;
10+
import org.commonmark.ext.gfm.tables.TableRow;
11+
import org.commonmark.node.Node;
12+
import org.commonmark.renderer.html.HtmlNodeRendererContext;
13+
import org.commonmark.renderer.html.HtmlWriter;
14+
15+
public class TableHtmlNodeRenderer extends TableNodeRenderer {
16+
17+
private final HtmlWriter htmlWriter;
18+
private final HtmlNodeRendererContext context;
19+
20+
public TableHtmlNodeRenderer(HtmlNodeRendererContext context) {
21+
this.htmlWriter = context.getWriter();
22+
this.context = context;
23+
}
24+
25+
protected void renderBlock(TableBlock tableBlock) {
26+
htmlWriter.line();
27+
htmlWriter.tag("table", getAttributes(tableBlock, "table"));
28+
renderChildren(tableBlock);
29+
htmlWriter.tag("/table");
30+
htmlWriter.line();
31+
}
32+
33+
protected void renderHead(TableHead tableHead) {
34+
htmlWriter.line();
35+
htmlWriter.tag("thead", getAttributes(tableHead, "thead"));
36+
renderChildren(tableHead);
37+
htmlWriter.tag("/thead");
38+
htmlWriter.line();
39+
}
40+
41+
protected void renderBody(TableBody tableBody) {
42+
htmlWriter.line();
43+
htmlWriter.tag("tbody", getAttributes(tableBody, "tbody"));
44+
renderChildren(tableBody);
45+
htmlWriter.tag("/tbody");
46+
htmlWriter.line();
47+
}
48+
49+
protected void renderRow(TableRow tableRow) {
50+
htmlWriter.line();
51+
htmlWriter.tag("tr", getAttributes(tableRow, "tr"));
52+
renderChildren(tableRow);
53+
htmlWriter.tag("/tr");
54+
htmlWriter.line();
55+
}
56+
57+
protected void renderCell(TableCell tableCell) {
58+
String tagName = tableCell.isHeader() ? "th" : "td";
59+
htmlWriter.tag(tagName, getCellAttributes(tableCell, tagName));
60+
renderChildren(tableCell);
61+
htmlWriter.tag("/" + tagName);
62+
}
63+
64+
private Map<String, String> getAttributes(Node node, String tagName) {
65+
return context.extendAttributes(node, tagName, Collections.<String, String>emptyMap());
66+
}
67+
68+
private Map<String, String> getCellAttributes(TableCell tableCell, String tagName) {
69+
if (tableCell.getAlignment() != null) {
70+
return context.extendAttributes(tableCell, tagName, Collections.singletonMap("align", getAlignValue(tableCell.getAlignment())));
71+
} else {
72+
return context.extendAttributes(tableCell, tagName, Collections.<String, String>emptyMap());
73+
}
74+
}
75+
76+
private static String getAlignValue(TableCell.Alignment alignment) {
77+
switch (alignment) {
78+
case LEFT:
79+
return "left";
80+
case CENTER:
81+
return "center";
82+
case RIGHT:
83+
return "right";
84+
}
85+
throw new IllegalStateException("Unknown alignment: " + alignment);
86+
}
87+
88+
private void renderChildren(Node parent) {
89+
Node node = parent.getFirstChild();
90+
while (node != null) {
91+
Node next = node.getNext();
92+
context.render(node);
93+
node = next;
94+
}
95+
}
96+
}
Lines changed: 15 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
package org.commonmark.ext.gfm.tables.internal;
22

3-
import org.commonmark.ext.gfm.tables.*;
3+
import java.util.Arrays;
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
import org.commonmark.ext.gfm.tables.TableBlock;
8+
import org.commonmark.ext.gfm.tables.TableBody;
9+
import org.commonmark.ext.gfm.tables.TableCell;
10+
import org.commonmark.ext.gfm.tables.TableHead;
11+
import org.commonmark.ext.gfm.tables.TableRow;
412
import org.commonmark.node.Node;
513
import org.commonmark.renderer.NodeRenderer;
6-
import org.commonmark.renderer.html.HtmlNodeRendererContext;
7-
import org.commonmark.renderer.html.HtmlWriter;
814

9-
import java.util.*;
10-
11-
public class TableNodeRenderer implements NodeRenderer {
12-
13-
private final HtmlWriter htmlWriter;
14-
private final HtmlNodeRendererContext context;
15-
16-
public TableNodeRenderer(HtmlNodeRendererContext context) {
17-
this.htmlWriter = context.getWriter();
18-
this.context = context;
19-
}
15+
abstract class TableNodeRenderer implements NodeRenderer {
2016

2117
@Override
2218
public Set<Class<? extends Node>> getNodeTypes() {
@@ -44,75 +40,13 @@ public void render(Node node) {
4440
}
4541
}
4642

47-
private void renderBlock(TableBlock tableBlock) {
48-
htmlWriter.line();
49-
htmlWriter.tag("table", getAttributes(tableBlock, "table"));
50-
renderChildren(tableBlock);
51-
htmlWriter.tag("/table");
52-
htmlWriter.line();
53-
}
54-
55-
private void renderHead(TableHead tableHead) {
56-
htmlWriter.line();
57-
htmlWriter.tag("thead", getAttributes(tableHead, "thead"));
58-
renderChildren(tableHead);
59-
htmlWriter.tag("/thead");
60-
htmlWriter.line();
61-
}
62-
63-
private void renderBody(TableBody tableBody) {
64-
htmlWriter.line();
65-
htmlWriter.tag("tbody", getAttributes(tableBody, "tbody"));
66-
renderChildren(tableBody);
67-
htmlWriter.tag("/tbody");
68-
htmlWriter.line();
69-
}
70-
71-
private void renderRow(TableRow tableRow) {
72-
htmlWriter.line();
73-
htmlWriter.tag("tr", getAttributes(tableRow, "tr"));
74-
renderChildren(tableRow);
75-
htmlWriter.tag("/tr");
76-
htmlWriter.line();
77-
}
43+
protected abstract void renderBlock(TableBlock node);
7844

79-
private void renderCell(TableCell tableCell) {
80-
String tagName = tableCell.isHeader() ? "th" : "td";
81-
htmlWriter.tag(tagName, getCellAttributes(tableCell, tagName));
82-
renderChildren(tableCell);
83-
htmlWriter.tag("/" + tagName);
84-
}
45+
protected abstract void renderHead(TableHead node);
8546

86-
private Map<String, String> getAttributes(Node node, String tagName) {
87-
return context.extendAttributes(node, tagName, Collections.<String, String>emptyMap());
88-
}
89-
90-
private Map<String, String> getCellAttributes(TableCell tableCell, String tagName) {
91-
if (tableCell.getAlignment() != null) {
92-
return context.extendAttributes(tableCell, tagName, Collections.singletonMap("align", getAlignValue(tableCell.getAlignment())));
93-
} else {
94-
return context.extendAttributes(tableCell, tagName, Collections.<String, String>emptyMap());
95-
}
96-
}
47+
protected abstract void renderBody(TableBody node);
9748

98-
private static String getAlignValue(TableCell.Alignment alignment) {
99-
switch (alignment) {
100-
case LEFT:
101-
return "left";
102-
case CENTER:
103-
return "center";
104-
case RIGHT:
105-
return "right";
106-
}
107-
throw new IllegalStateException("Unknown alignment: " + alignment);
108-
}
49+
protected abstract void renderRow(TableRow node);
10950

110-
private void renderChildren(Node parent) {
111-
Node node = parent.getFirstChild();
112-
while (node != null) {
113-
Node next = node.getNext();
114-
context.render(node);
115-
node = next;
116-
}
117-
}
51+
protected abstract void renderCell(TableCell node);
11852
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package org.commonmark.ext.gfm.tables.internal;
2+
3+
import org.commonmark.ext.gfm.tables.TableBlock;
4+
import org.commonmark.ext.gfm.tables.TableBody;
5+
import org.commonmark.ext.gfm.tables.TableCell;
6+
import org.commonmark.ext.gfm.tables.TableHead;
7+
import org.commonmark.ext.gfm.tables.TableRow;
8+
import org.commonmark.node.Node;
9+
import org.commonmark.renderer.text.TextContentNodeRendererContext;
10+
import org.commonmark.renderer.text.TextContentWriter;
11+
12+
/**
13+
* The Table node renderer that is needed for rendering GFM tables (GitHub Flavored Markdown) to text content.
14+
*/
15+
public class TableTextContentNodeRenderer extends TableNodeRenderer {
16+
17+
private final TextContentWriter textContentWriter;
18+
private final TextContentNodeRendererContext context;
19+
20+
public TableTextContentNodeRenderer(TextContentNodeRendererContext context) {
21+
this.textContentWriter = context.getWriter();
22+
this.context = context;
23+
}
24+
25+
protected void renderBlock(TableBlock tableBlock) {
26+
renderChildren(tableBlock);
27+
if (tableBlock.getNext() != null) {
28+
textContentWriter.write("\n");
29+
}
30+
}
31+
32+
protected void renderHead(TableHead tableHead) {
33+
renderChildren(tableHead);
34+
}
35+
36+
protected void renderBody(TableBody tableBody) {
37+
renderChildren(tableBody);
38+
}
39+
40+
protected void renderRow(TableRow tableRow) {
41+
textContentWriter.line();
42+
renderChildren(tableRow);
43+
textContentWriter.line();
44+
}
45+
46+
protected void renderCell(TableCell tableCell) {
47+
renderChildren(tableCell);
48+
textContentWriter.pipe();
49+
textContentWriter.whitespace();
50+
}
51+
52+
private void renderLastCell(TableCell tableCell) {
53+
renderChildren(tableCell);
54+
}
55+
56+
private void renderChildren(Node parent) {
57+
Node node = parent.getFirstChild();
58+
while (node != null) {
59+
Node next = node.getNext();
60+
61+
// For last cell in row, we dont render the delimiter.
62+
if (node instanceof TableCell && next == null) {
63+
renderLastCell((TableCell) node);
64+
} else {
65+
context.render(node);
66+
}
67+
68+
node = next;
69+
}
70+
}
71+
}

0 commit comments

Comments
 (0)