Implemented lists
This commit is contained in:
parent
133d01bd11
commit
8e009702c2
@ -5,6 +5,7 @@ Markdown renderer.
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Links
|
- Links
|
||||||
|
- Lists
|
||||||
- Headers
|
- Headers
|
||||||
- Paragraphs
|
- Paragraphs
|
||||||
- Quotes
|
- Quotes
|
||||||
@ -37,7 +38,7 @@ coverage: 100.0% of statements
|
|||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
```
|
```
|
||||||
BenchmarkSmall-12 2425053 492.8 ns/op 248 B/op 5 allocs/op
|
BenchmarkSmall-12 2585194 462.4 ns/op 248 B/op 5 allocs/op
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
42
Render.go
42
Render.go
@ -14,6 +14,7 @@ type renderer struct {
|
|||||||
out strings.Builder
|
out strings.Builder
|
||||||
paragraphLevel int
|
paragraphLevel int
|
||||||
quoteLevel int
|
quoteLevel int
|
||||||
|
listLevel int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render creates HTML from the supplied markdown text.
|
// Render creates HTML from the supplied markdown text.
|
||||||
@ -26,7 +27,7 @@ func Render(markdown string) string {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
if i > len(markdown) {
|
if i > len(markdown) {
|
||||||
r.closeParagraphs()
|
r.closeAll()
|
||||||
|
|
||||||
for range r.quoteLevel {
|
for range r.quoteLevel {
|
||||||
r.out.WriteString("</blockquote>")
|
r.out.WriteString("</blockquote>")
|
||||||
@ -72,8 +73,14 @@ func (r *renderer) processLine(line string) {
|
|||||||
|
|
||||||
r.quoteLevel = newQuoteLevel
|
r.quoteLevel = newQuoteLevel
|
||||||
|
|
||||||
if strings.HasPrefix(line, "#") {
|
if len(line) == 0 {
|
||||||
r.closeParagraphs()
|
r.closeAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch line[0] {
|
||||||
|
case '#':
|
||||||
|
r.closeAll()
|
||||||
space := strings.IndexByte(line, ' ')
|
space := strings.IndexByte(line, ' ')
|
||||||
|
|
||||||
if space > 0 && space <= 6 {
|
if space > 0 && space <= 6 {
|
||||||
@ -83,10 +90,19 @@ func (r *renderer) processLine(line string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
|
||||||
|
|
||||||
if len(line) == 0 {
|
case '-', '*':
|
||||||
r.closeParagraphs()
|
r.closeParagraphs()
|
||||||
|
line = strings.TrimSpace(line[1:])
|
||||||
|
|
||||||
|
if r.listLevel == 0 {
|
||||||
|
r.out.WriteString("<ul>")
|
||||||
|
r.listLevel++
|
||||||
|
}
|
||||||
|
|
||||||
|
r.out.WriteString("<li>")
|
||||||
|
r.writeText(line)
|
||||||
|
r.out.WriteString("</li>")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +117,12 @@ func (r *renderer) processLine(line string) {
|
|||||||
r.writeText(line)
|
r.writeText(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closeAll closes all open tags.
|
||||||
|
func (r *renderer) closeAll() {
|
||||||
|
r.closeLists()
|
||||||
|
r.closeParagraphs()
|
||||||
|
}
|
||||||
|
|
||||||
// closeParagraphs closes open paragraphs.
|
// closeParagraphs closes open paragraphs.
|
||||||
func (r *renderer) closeParagraphs() {
|
func (r *renderer) closeParagraphs() {
|
||||||
for range r.paragraphLevel {
|
for range r.paragraphLevel {
|
||||||
@ -110,6 +132,15 @@ func (r *renderer) closeParagraphs() {
|
|||||||
r.paragraphLevel = 0
|
r.paragraphLevel = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// closeLists closes open lists.
|
||||||
|
func (r *renderer) closeLists() {
|
||||||
|
for range r.listLevel {
|
||||||
|
r.out.WriteString("</ul>")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.listLevel = 0
|
||||||
|
}
|
||||||
|
|
||||||
// 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 (
|
||||||
@ -170,6 +201,7 @@ func (r *renderer) writeText(markdown string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanitizeURL makes a URL safe to use as the value for a `href` attribute.
|
||||||
func sanitizeURL(linkURL string) string {
|
func sanitizeURL(linkURL string) string {
|
||||||
linkURL = strings.TrimSpace(linkURL)
|
linkURL = strings.TrimSpace(linkURL)
|
||||||
|
|
||||||
|
@ -38,6 +38,12 @@ func TestLink(t *testing.T) {
|
|||||||
assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), "<p>Prefix <a href=\"https://example.com/\">text</a> suffix.</p>")
|
assert.Equal(t, markdown.Render("Prefix [text](https://example.com/) suffix."), "<p>Prefix <a href=\"https://example.com/\">text</a> suffix.</p>")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
assert.Equal(t, markdown.Render("- Entry"), "<ul><li>Entry</li></ul>")
|
||||||
|
assert.Equal(t, markdown.Render("- Entry 1\n- Entry 2"), "<ul><li>Entry 1</li><li>Entry 2</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 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>")
|
||||||
@ -51,6 +57,9 @@ func TestCombined(t *testing.T) {
|
|||||||
assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), "<h1>Header</h1><p>Line 1. Line 2. Line 3.</p>")
|
assert.Equal(t, markdown.Render("# Header\nLine 1.\nLine 2.\nLine 3."), "<h1>Header</h1><p>Line 1. Line 2. Line 3.</p>")
|
||||||
assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), "<h1>Header 1</h1><p>Line 1.</p><h1>Header 2</h1><p>Line 2.</p>")
|
assert.Equal(t, markdown.Render("# Header 1\nLine 1.\n# Header 2\nLine 2."), "<h1>Header 1</h1><p>Line 1.</p><h1>Header 2</h1><p>Line 2.</p>")
|
||||||
assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), "<h1><a href=\"https://example.com/\">Header Link</a></h1>")
|
assert.Equal(t, markdown.Render("# [Header Link](https://example.com/)"), "<h1><a href=\"https://example.com/\">Header Link</a></h1>")
|
||||||
|
assert.Equal(t, markdown.Render("# Title\n\n- Entry 1\n- Entry 2\n\nText."), "<h1>Title</h1><ul><li>Entry 1</li><li>Entry 2</li></ul><p>Text.</p>")
|
||||||
|
assert.Equal(t, markdown.Render("- Entry\n# Header"), "<ul><li>Entry</li></ul><h1>Header</h1>")
|
||||||
|
assert.Equal(t, markdown.Render("> - Entry\n> # Header"), "<blockquote><ul><li>Entry</li></ul><h1>Header</h1></blockquote>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSecurity(t *testing.T) {
|
func TestSecurity(t *testing.T) {
|
||||||
|
Loading…
Reference in New Issue
Block a user