Implemented headers and paragraphs

This commit is contained in:
Eduard Urbach 2024-03-31 23:08:01 +02:00
parent a4e5243ab3
commit 93d5949eff
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
4 changed files with 115 additions and 6 deletions

View File

@ -4,7 +4,8 @@ Markdown renderer.
## Features
- Headers
- Paragraphs
## Installation
@ -15,16 +16,25 @@ go get git.akyoto.dev/go/markdown
## Usage
```go
html := markdown.Render("# Header")
fmt.Println(html)
```
## Tests
```
PASS: TestEmpty
PASS: TestParagraphs
PASS: TestHeader
PASS: TestCombined
coverage: 100.0% of statements
```
## Benchmarks
```
BenchmarkSmall-12 2187232 544.9 ns/op 296 B/op 9 allocs/op
```
## License

View File

@ -1,6 +1,71 @@
package markdown
import (
"html"
"strings"
)
var (
headerStart = []string{"<h1>", "<h2>", "<h3>", "<h4>", "<h5>", "<h6>"}
headerEnd = []string{"</h1>", "</h2>", "</h3>", "</h4>", "</h5>", "</h6>"}
)
// Render creates HTML from the supplied markdown text.
func Render(markdown string) string {
return ""
var (
out = strings.Builder{}
paragraph = strings.Builder{}
i = 0
lineStart = 0
)
flush := func() {
if paragraph.Len() == 0 {
return
}
out.WriteString("<p>")
out.WriteString(html.EscapeString(paragraph.String()))
out.WriteString("</p>")
paragraph.Reset()
}
for {
if i > len(markdown) {
flush()
return out.String()
}
if i != len(markdown) && markdown[i] != '\n' {
i++
continue
}
line := markdown[lineStart:i]
lineStart = i + 1
i++
switch {
case strings.HasPrefix(line, "#"):
flush()
space := strings.IndexByte(line, ' ')
if space > 0 && space <= 6 {
out.WriteString(headerStart[space-1])
out.WriteString(html.EscapeString(line[space+1:]))
out.WriteString(headerEnd[space-1])
}
default:
if len(line) == 0 {
continue
}
if paragraph.Len() > 0 {
paragraph.WriteByte(' ')
}
paragraph.WriteString(line)
}
}
}

View File

@ -7,7 +7,28 @@ import (
"git.akyoto.dev/go/markdown"
)
func TestRender(t *testing.T) {
html := markdown.Render("# Hello")
assert.Equal(t, html, "<h1>Hello</h1>")
func TestEmpty(t *testing.T) {
assert.Equal(t, markdown.Render(""), "")
}
func TestParagraphs(t *testing.T) {
assert.Equal(t, markdown.Render("Text"), "<p>Text</p>")
assert.Equal(t, markdown.Render("Text\n"), "<p>Text</p>")
assert.Equal(t, markdown.Render("Text\n\n"), "<p>Text</p>")
assert.Equal(t, markdown.Render("Text\n\n\n"), "<p>Text</p>")
assert.Equal(t, markdown.Render("Line 1\nLine 2"), "<p>Line 1 Line 2</p>")
}
func TestHeader(t *testing.T) {
assert.Equal(t, markdown.Render("# Header"), "<h1>Header</h1>")
assert.Equal(t, markdown.Render("## Header"), "<h2>Header</h2>")
assert.Equal(t, markdown.Render("### Header"), "<h3>Header</h3>")
assert.Equal(t, markdown.Render("#### Header"), "<h4>Header</h4>")
assert.Equal(t, markdown.Render("##### Header"), "<h5>Header</h5>")
assert.Equal(t, markdown.Render("###### Header"), "<h6>Header</h6>")
}
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 1\nLine 1.\n# Header 2\nLine 2."), "<h1>Header 1</h1><p>Line 1.</p><h1>Header 2</h1><p>Line 2.</p>")
}

13
benchmarks_test.go Normal file
View File

@ -0,0 +1,13 @@
package markdown_test
import (
"testing"
"git.akyoto.dev/go/markdown"
)
func BenchmarkSmall(b *testing.B) {
for range b.N {
markdown.Render("# Header\nText.\nText.\n# Header\nText.\nText.")
}
}