From 99d0ab9b9aa15e79a8b61a25dfc4a7f5fc19e6b6 Mon Sep 17 00:00:00 2001 From: johnnyjoy Date: Fri, 12 Jul 2024 21:59:56 +0800 Subject: [PATCH] feat: use block nodes in table cells --- ast/block.go | 8 ++-- parser/table.go | 35 +++++++++++++----- parser/table_test.go | 77 +++++++++++++++++++++++++++++---------- renderer/html/html.go | 4 +- renderer/string/string.go | 4 +- 5 files changed, 91 insertions(+), 37 deletions(-) diff --git a/ast/block.go b/ast/block.go index f3b79b4..b33fa80 100644 --- a/ast/block.go +++ b/ast/block.go @@ -201,9 +201,9 @@ func (n *MathBlock) Restore() string { type Table struct { BaseBlock - Header []string + Header []Node Delimiter []string - Rows [][]string + Rows [][]Node } func (*Table) Type() NodeType { @@ -213,7 +213,7 @@ func (*Table) Type() NodeType { func (n *Table) Restore() string { result := "" for _, header := range n.Header { - result += fmt.Sprintf("| %s ", header) + result += fmt.Sprintf("| %s ", header.Restore()) } result += "|\n" for _, d := range n.Delimiter { @@ -222,7 +222,7 @@ func (n *Table) Restore() string { result += "|\n" for index, row := range n.Rows { for _, cell := range row { - result += fmt.Sprintf("| %s ", cell) + result += fmt.Sprintf("| %s ", cell.Restore()) } result += "|" if index != len(n.Rows)-1 { diff --git a/parser/table.go b/parser/table.go index 9c8327e..645e24c 100644 --- a/parser/table.go +++ b/parser/table.go @@ -88,16 +88,24 @@ func (*TableParser) Match(tokens []*tokenizer.Token) (ast.Node, int) { } rows = rows[:matchedRows] - header := make([]string, 0) + headerNodes := make([]ast.Node, 0) delimiter := make([]string, 0) - rowsStr := make([][]string, 0) + rowsNodes := make([][]ast.Node, 0) cols := len(tokenizer.Split(headerTokens, tokenizer.Pipe)) - 2 for _, t := range tokenizer.Split(headerTokens, tokenizer.Pipe)[1 : cols+1] { if len(t) < 3 { - header = append(header, "") + headerNodes = append(headerNodes, &ast.Text{}) } else { - header = append(header, tokenizer.Stringify(t[1:len(t)-1])) + cellTokens := t[1 : len(t)-1] + nodes, err := ParseBlockWithParsers(cellTokens, []BlockParser{NewHeadingParser(), NewParagraphParser()}) + if err != nil { + return nil, 0 + } + if len(nodes) != 1 { + return nil, 0 + } + headerNodes = append(headerNodes, nodes[0]) } } for _, t := range tokenizer.Split(delimiterTokens, tokenizer.Pipe)[1 : cols+1] { @@ -108,15 +116,22 @@ func (*TableParser) Match(tokens []*tokenizer.Token) (ast.Node, int) { } } for _, row := range rows { - cells := make([]string, 0) + rowNodes := make([]ast.Node, 0) for _, t := range tokenizer.Split(row, tokenizer.Pipe)[1 : cols+1] { if len(t) < 3 { - cells = append(cells, "") + rowNodes = append(rowNodes, &ast.Text{}) } else { - cells = append(cells, tokenizer.Stringify(t[1:len(t)-1])) + nodes, err := ParseBlockWithParsers(t[1:len(t)-1], []BlockParser{NewHeadingParser(), NewParagraphParser()}) + if err != nil { + return nil, 0 + } + if len(nodes) != 1 { + return nil, 0 + } + rowNodes = append(rowNodes, nodes[0]) } } - rowsStr = append(rowsStr, cells) + rowsNodes = append(rowsNodes, rowNodes) } size := len(headerTokens) + len(delimiterTokens) + 2 @@ -126,9 +141,9 @@ func (*TableParser) Match(tokens []*tokenizer.Token) (ast.Node, int) { size = size + len(rows) - 1 return &ast.Table{ - Header: header, + Header: headerNodes, Delimiter: delimiter, - Rows: rowsStr, + Rows: rowsNodes, }, size } diff --git a/parser/table_test.go b/parser/table_test.go index 0ef2a82..2a8faeb 100644 --- a/parser/table_test.go +++ b/parser/table_test.go @@ -18,32 +18,71 @@ func TestTableParser(t *testing.T) { { text: "| header |\n| --- |\n| cell |\n", table: &ast.Table{ - Header: []string{"header"}, + Header: []ast.Node{ + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "header"}, + }, + }, + }, Delimiter: []string{"---"}, - Rows: [][]string{ - {"cell"}, + Rows: [][]ast.Node{ + { + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "cell"}, + }, + }, + }, }, }, }, { - text: "| header1 | header2 |\n| --- | ---- |\n| cell1 | cell2 |\n| cell3 | cell4 |", + text: "| **header1** | header2 |\n| --- | ---- |\n| cell1 | cell2 |\n| cell3 | cell4 |", table: &ast.Table{ - Header: []string{"header1", "header2"}, - Delimiter: []string{"---", "----"}, - Rows: [][]string{ - {"cell1", "cell2"}, - {"cell3", "cell4"}, + Header: []ast.Node{ + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Bold{ + Symbol: "*", + Children: []ast.Node{ + &ast.Text{Content: "header1"}, + }, + }, + }, + }, + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "header2"}, + }, + }, }, - }, - }, - { - text: "| header1 | header2 |\n| :-- | ----: |\n| cell1 | cell2 |\n| cell3 | cell4 |", - table: &ast.Table{ - Header: []string{"header1", "header2"}, - Delimiter: []string{":--", "----:"}, - Rows: [][]string{ - {"cell1", "cell2"}, - {"cell3", "cell4"}, + Delimiter: []string{"---", "----"}, + Rows: [][]ast.Node{ + { + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "cell1"}, + }, + }, + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "cell2"}, + }, + }, + }, + { + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "cell3"}, + }, + }, + &ast.Paragraph{ + Children: []ast.Node{ + &ast.Text{Content: "cell4"}, + }, + }, + }, }, }, }, diff --git a/renderer/html/html.go b/renderer/html/html.go index a313bb7..e8ace60 100644 --- a/renderer/html/html.go +++ b/renderer/html/html.go @@ -203,7 +203,7 @@ func (r *HTMLRenderer) renderTable(node *ast.Table) { r.output.WriteString("") for _, cell := range node.Header { r.output.WriteString("") - r.output.WriteString(cell) + r.RenderNodes([]ast.Node{cell}) r.output.WriteString("") } r.output.WriteString("") @@ -213,7 +213,7 @@ func (r *HTMLRenderer) renderTable(node *ast.Table) { r.output.WriteString("") for _, cell := range row { r.output.WriteString("") - r.output.WriteString(cell) + r.RenderNodes([]ast.Node{cell}) r.output.WriteString("") } r.output.WriteString("") diff --git a/renderer/string/string.go b/renderer/string/string.go index 6413cd1..74f9c28 100644 --- a/renderer/string/string.go +++ b/renderer/string/string.go @@ -166,13 +166,13 @@ func (r *StringRenderer) renderMathBlock(node *ast.MathBlock) { func (r *StringRenderer) renderTable(node *ast.Table) { for _, cell := range node.Header { - r.output.WriteString(cell) + r.RenderNodes([]ast.Node{cell}) r.output.WriteString("\t") } r.output.WriteString("\n") for _, row := range node.Rows { for _, cell := range row { - r.output.WriteString(cell) + r.RenderNodes([]ast.Node{cell}) r.output.WriteString("\t") } r.output.WriteString("\n")