mirror of
https://github.com/carlrobertoh/ProxyAI.git
synced 2026-05-17 03:57:27 +00:00
feat: support markdown tables (closes #1186)
This commit is contained in:
parent
b501ffad73
commit
fe02380f5c
3 changed files with 80 additions and 1 deletions
|
|
@ -9,6 +9,10 @@ import com.vladsch.flexmark.ast.Heading;
|
|||
import com.vladsch.flexmark.ast.Link;
|
||||
import com.vladsch.flexmark.ast.OrderedListItem;
|
||||
import com.vladsch.flexmark.ast.Paragraph;
|
||||
import com.vladsch.flexmark.ext.tables.TableBlock;
|
||||
import com.vladsch.flexmark.ext.tables.TableCell;
|
||||
import com.vladsch.flexmark.ext.tables.TableHead;
|
||||
import com.vladsch.flexmark.ext.tables.TableRow;
|
||||
import com.vladsch.flexmark.html.HtmlWriter;
|
||||
import com.vladsch.flexmark.html.renderer.NodeRenderer;
|
||||
import com.vladsch.flexmark.html.renderer.NodeRendererContext;
|
||||
|
|
@ -28,10 +32,49 @@ public class ResponseNodeRenderer implements NodeRenderer {
|
|||
new NodeRenderingHandler<>(CodeBlock.class, this::renderCodeBlock),
|
||||
new NodeRenderingHandler<>(BulletListItem.class, this::renderBulletListItem),
|
||||
new NodeRenderingHandler<>(Heading.class, this::renderHeading),
|
||||
new NodeRenderingHandler<>(OrderedListItem.class, this::renderOrderedListItem)
|
||||
new NodeRenderingHandler<>(OrderedListItem.class, this::renderOrderedListItem),
|
||||
new NodeRenderingHandler<>(TableBlock.class, this::renderTable),
|
||||
new NodeRenderingHandler<>(TableRow.class, this::renderTableRow),
|
||||
new NodeRenderingHandler<>(TableCell.class, this::renderTableCell)
|
||||
);
|
||||
}
|
||||
|
||||
private void renderTable(TableBlock node, NodeRendererContext context, HtmlWriter html) {
|
||||
var borderColor = ColorUtil.toHex(new JBColor(0xD0D0D0, 0x3C3F47));
|
||||
html.attr("style",
|
||||
"border-collapse: collapse; width: 100%; margin: 8px 0; border-top: 1px solid "
|
||||
+ borderColor);
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderTableRow(TableRow node, NodeRendererContext context, HtmlWriter html) {
|
||||
html.attr("style",
|
||||
"border-bottom: 1px solid " + ColorUtil.toHex(new JBColor(0xE3E3E3, 0x2D2F35)) + ";");
|
||||
context.delegateRender();
|
||||
}
|
||||
|
||||
private void renderTableCell(TableCell node, NodeRendererContext context, HtmlWriter html) {
|
||||
TableRow row = (TableRow) node.getParent();
|
||||
var isHeaderCell = row != null && row.getParent() instanceof TableHead;
|
||||
var tag = isHeaderCell ? "th" : "td";
|
||||
|
||||
var styleBuilder = new StringBuilder();
|
||||
styleBuilder.append("padding: 8px 12px; text-align: left; vertical-align: middle;");
|
||||
|
||||
if (isHeaderCell) {
|
||||
var bgColor = ColorUtil.toHex(new JBColor(0xF2F3F5, 0x3A3D41));
|
||||
styleBuilder.append(" font-weight: 600; background-color: ").append(bgColor).append("; color: white; min-width: 200px;");
|
||||
}
|
||||
|
||||
html.attr("style", styleBuilder.toString().trim());
|
||||
if (isHeaderCell) {
|
||||
html.attr("scope", "col");
|
||||
}
|
||||
html.withAttr().tag(tag);
|
||||
context.renderChildren(node);
|
||||
html.tag("/" + tag);
|
||||
}
|
||||
|
||||
private void renderCodeBlock(CodeBlock node, NodeRendererContext context, HtmlWriter html) {
|
||||
html.attr("style", "white-space: pre-wrap;");
|
||||
context.delegateRender();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package ee.carlrobert.codegpt.util
|
||||
|
||||
import com.vladsch.flexmark.ext.tables.TablesExtension
|
||||
import com.vladsch.flexmark.html.HtmlRenderer
|
||||
import com.vladsch.flexmark.parser.Parser
|
||||
import com.vladsch.flexmark.util.data.MutableDataSet
|
||||
|
|
@ -37,6 +38,7 @@ object MarkdownUtil {
|
|||
@JvmStatic
|
||||
fun convertMdToHtml(message: String): String {
|
||||
val options = MutableDataSet()
|
||||
options.set(Parser.EXTENSIONS, listOf(TablesExtension.create()))
|
||||
options.set(HtmlRenderer.SOFT_BREAK, "<br/>")
|
||||
|
||||
val document = Parser.builder(options).build().parse(message)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,40 @@ import org.junit.Test
|
|||
|
||||
class MarkdownUtilTest {
|
||||
|
||||
@Test
|
||||
fun shouldRenderTableCorrectly() {
|
||||
val markdown = """
|
||||
<think>thinking content</think>
|
||||
Here's a basic fruits table:
|
||||
|
||||
| Fruit | Color | Price ($/kg) | Season | Calories (per 100g) |
|
||||
|-------|-------|--------------|--------|---------------------|
|
||||
| Apple | Red | 3.50 | Fall | 52 |
|
||||
| Banana | Yellow | 2.80 | Year-round | 89 |
|
||||
| Orange | Orange | 4.20 | Winter | 47 |
|
||||
| Strawberry | Red | 6.00 | Spring | 32 |
|
||||
| Grape | Purple | 5.50 | Summer | 69 |
|
||||
| Mango | Orange | 7.00 | Summer | 60 |
|
||||
| Watermelon | Green | 1.90 | Summer | 30 |
|
||||
| Kiwi | Brown | 4.80 | Winter | 61 |
|
||||
| Pineapple | Yellow | 5.00 | Year-round | 50 |
|
||||
| Blueberry | Blue | 8.50 | Summer | 57 |
|
||||
""".trimIndent()
|
||||
|
||||
val html = MarkdownUtil.convertMdToHtml(markdown)
|
||||
|
||||
assertThat(html).contains("thead")
|
||||
assertThat(html).contains("/thead")
|
||||
assertThat(html).contains("tbody")
|
||||
assertThat(html).contains("/tbody")
|
||||
assertThat(html).contains("th")
|
||||
assertThat(html).contains("Fruit")
|
||||
assertThat(html).contains("td")
|
||||
assertThat(html).contains("Apple")
|
||||
val tableCount = html.split("<table").size - 1
|
||||
assertThat(tableCount).isEqualTo(1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldExtractMarkdownCodeBlocks() {
|
||||
val testInput = """
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue