Implemented tables

This commit is contained in:
Eduard Urbach 2024-04-01 20:59:32 +02:00
parent 8e009702c2
commit e19a41c792
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
3 changed files with 68 additions and 5 deletions

View File

@ -38,7 +38,7 @@ coverage: 100.0% of statements
## Benchmarks ## Benchmarks
``` ```
BenchmarkSmall-12 2585194 462.4 ns/op 248 B/op 5 allocs/op BenchmarkSmall-12 2411152 489.1 ns/op 248 B/op 5 allocs/op
``` ```
## License ## License

View File

@ -11,10 +11,12 @@ var (
) )
type renderer struct { type renderer struct {
out strings.Builder out strings.Builder
paragraphLevel int paragraphLevel int
quoteLevel int quoteLevel int
listLevel int listLevel int
tableLevel int
tableHeaderWritten bool
} }
// Render creates HTML from the supplied markdown text. // Render creates HTML from the supplied markdown text.
@ -104,6 +106,51 @@ func (r *renderer) processLine(line string) {
r.writeText(line) r.writeText(line)
r.out.WriteString("</li>") r.out.WriteString("</li>")
return return
case '|':
r.closeParagraphs()
line = line[1:]
if r.tableLevel == 0 {
r.out.WriteString("<table><thead>")
r.tableLevel++
}
column := 0
for {
pipe := strings.IndexByte(line, '|')
if pipe == -1 {
r.out.WriteString("</tr>")
return
}
content := strings.TrimSpace(line[:pipe])
if strings.HasPrefix(content, "---") {
r.out.WriteString("</thead><tbody>")
r.tableHeaderWritten = true
return
}
if column == 0 {
r.out.WriteString("<tr>")
}
if r.tableHeaderWritten {
r.out.WriteString("<td>")
r.writeText(content)
r.out.WriteString("</td>")
} else {
r.out.WriteString("<th>")
r.writeText(content)
r.out.WriteString("</th>")
}
line = line[pipe+1:]
column++
}
} }
if r.paragraphLevel == 0 { if r.paragraphLevel == 0 {
@ -121,6 +168,7 @@ func (r *renderer) processLine(line string) {
func (r *renderer) closeAll() { func (r *renderer) closeAll() {
r.closeLists() r.closeLists()
r.closeParagraphs() r.closeParagraphs()
r.closeTables()
} }
// closeParagraphs closes open paragraphs. // closeParagraphs closes open paragraphs.
@ -141,6 +189,16 @@ func (r *renderer) closeLists() {
r.listLevel = 0 r.listLevel = 0
} }
// closeTables closes open tables.
func (r *renderer) closeTables() {
for range r.tableLevel {
r.out.WriteString("</tbody></table>")
}
r.tableLevel = 0
r.tableHeaderWritten = false
}
// writeText converts inline markdown to HTML. // writeText converts inline markdown to HTML.
func (r *renderer) writeText(markdown string) { func (r *renderer) writeText(markdown string) {
var ( var (

View File

@ -44,6 +44,11 @@ func TestList(t *testing.T) {
assert.Equal(t, markdown.Render("- Entry 1\n- Entry 2\n- Entry 3"), "<ul><li>Entry 1</li><li>Entry 2</li><li>Entry 3</li></ul>") assert.Equal(t, markdown.Render("- Entry 1\n- Entry 2\n- Entry 3"), "<ul><li>Entry 1</li><li>Entry 2</li><li>Entry 3</li></ul>")
} }
func TestTables(t *testing.T) {
assert.Equal(t, markdown.Render("| Head |\n| --- |\n| Body |"), "<table><thead><tr><th>Head</th></tr></thead><tbody><tr><td>Body</td></tr></tbody></table>")
assert.Equal(t, markdown.Render("| 1 | 2 |\n| --- | --- |\n| 1 | 2 |"), "<table><thead><tr><th>1</th><th>2</th></tr></thead><tbody><tr><td>1</td><td>2</td></tr></tbody></table>")
}
func TestQuote(t *testing.T) { func TestQuote(t *testing.T) {
assert.Equal(t, markdown.Render("> Line"), "<blockquote><p>Line</p></blockquote>") assert.Equal(t, markdown.Render("> Line"), "<blockquote><p>Line</p></blockquote>")
assert.Equal(t, markdown.Render("> Line 1\n> Line 2"), "<blockquote><p>Line 1 Line 2</p></blockquote>") assert.Equal(t, markdown.Render("> Line 1\n> Line 2"), "<blockquote><p>Line 1 Line 2</p></blockquote>")