Commit 4e9469b
Eric Bower
·
2026-09-14 13:26:05 -0400 EDT
parent a953040
feat: markdown to html
7 files changed,
+191,
-15
+1,
-1
| ... | ... | @@ -7,7 +7,7 @@ RUN go mod download && go mod verify | |
| 7 | 7 | ||
| 8 | 8 | COPY . /app | |
| 9 | 9 | ||
| 10 | - | RUN go build -v -o pgit main.go | |
| 10 | + | RUN go build -v -o pgit . | |
| 11 | 11 | ||
| 12 | 12 | FROM debian:12 | |
| 13 | 13 | WORKDIR /app |
M
Makefile
+5,
-2
| ... | ... | @@ -10,7 +10,7 @@ clean: | |
| 10 | 10 | .PHONY: clean | |
| 11 | 11 | ||
| 12 | 12 | build: | |
| 13 | - | go build -o pgit ./main.go | |
| 13 | + | go build -o pgit . | |
| 14 | 14 | .PHONY: build | |
| 15 | 15 | ||
| 16 | 16 | img: |
| ... | ... | @@ -29,8 +29,11 @@ test: | |
| 29 | 29 | go test ./... | |
| 30 | 30 | .PHONY: test | |
| 31 | 31 | ||
| 32 | + | check: lint test | |
| 33 | + | .PHONY: check | |
| 34 | + | ||
| 32 | 35 | static: | |
| 33 | - | go run main.go \ | |
| 36 | + | go run . \ | |
| 34 | 37 | --out ./public \ | |
| 35 | 38 | --label pgit \ | |
| 36 | 39 | --clone-url "https://github.com/picosh/pgit.git" \ |
M
go.mod
+8,
-1
| ... | ... | @@ -6,11 +6,18 @@ require ( | |
| 6 | 6 | github.com/alecthomas/chroma/v2 v2.13.0 | |
| 7 | 7 | github.com/dustin/go-humanize v1.0.0 | |
| 8 | 8 | github.com/gogs/git-module v1.6.0 | |
| 9 | + | github.com/yuin/goldmark v1.8.2 | |
| 10 | + | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc | |
| 11 | + | github.com/yuin/goldmark-meta v1.1.0 | |
| 12 | + | go.abhg.dev/goldmark/anchor v0.2.0 | |
| 13 | + | go.abhg.dev/goldmark/hashtag v0.4.0 | |
| 9 | 14 | ) | |
| 10 | 15 | ||
| 11 | 16 | require ( | |
| 12 | 17 | github.com/dlclark/regexp2 v1.11.0 // indirect | |
| 18 | + | github.com/forPelevin/gomoji v1.3.0 // indirect | |
| 13 | 19 | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 // indirect | |
| 14 | - | github.com/stretchr/testify v1.8.1 // indirect | |
| 20 | + | github.com/rivo/uniseg v0.4.7 // indirect | |
| 15 | 21 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect | |
| 22 | + | gopkg.in/yaml.v2 v2.3.0 // indirect | |
| 16 | 23 | ) |
M
go.sum
+25,
-6
| ... | ... | @@ -1,16 +1,22 @@ | |
| 1 | 1 | github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= | |
| 2 | 2 | github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= | |
| 3 | + | github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= | |
| 3 | 4 | github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI= | |
| 4 | 5 | github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk= | |
| 6 | + | github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= | |
| 5 | 7 | github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= | |
| 6 | 8 | github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= | |
| 7 | 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| 8 | 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
| 9 | 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| 12 | + | github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= | |
| 13 | + | github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= | |
| 10 | 14 | github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI= | |
| 11 | 15 | github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= | |
| 12 | 16 | github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= | |
| 13 | 17 | github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= | |
| 18 | + | github.com/forPelevin/gomoji v1.3.0 h1:WPIOLWB1bvRYlKZnSSEevLt3IfKlLs+tK+YA9fFYlkE= | |
| 19 | + | github.com/forPelevin/gomoji v1.3.0/go.mod h1:mM6GtmCgpoQP2usDArc6GjbXrti5+FffolyQfGgPboQ= | |
| 14 | 20 | github.com/gogs/git-module v1.6.0 h1:71GdRM9/pFxGgSUz8t2DKmm3RYuHUnTjsOuFInJXnkM= | |
| 15 | 21 | github.com/gogs/git-module v1.6.0/go.mod h1:8jFYhDxLUwEOhM2709l2CJXmoIIslobU1xszpT0NcAI= | |
| 16 | 22 | github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= |
| ... | ... | @@ -19,19 +25,32 @@ github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX | |
| 19 | 25 | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= | |
| 20 | 26 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
| 21 | 27 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
| 28 | + | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= | |
| 29 | + | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= | |
| 22 | 30 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |
| 23 | - | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | |
| 24 | - | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | |
| 25 | 31 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= | |
| 26 | - | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |
| 27 | - | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |
| 28 | - | github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= | |
| 29 | - | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | |
| 32 | + | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |
| 33 | + | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | |
| 34 | + | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | |
| 35 | + | github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | |
| 36 | + | github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE= | |
| 37 | + | github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= | |
| 38 | + | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= | |
| 39 | + | github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= | |
| 40 | + | github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= | |
| 41 | + | github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= | |
| 42 | + | go.abhg.dev/goldmark/anchor v0.2.0 h1:RQZTodRc6VHSUoQYKFlyH0pokbhk1klwUuGgDmjGp2E= | |
| 43 | + | go.abhg.dev/goldmark/anchor v0.2.0/go.mod h1:Ym74zBV+QBKxK9ITOty680N9FT8otgGYvtYXroJUWms= | |
| 44 | + | go.abhg.dev/goldmark/hashtag v0.4.0 h1:jkYcsIRUpog/rhWMnIOjj14qj8p5p4um+IzPbPUxFww= | |
| 45 | + | go.abhg.dev/goldmark/hashtag v0.4.0/go.mod h1:5DQwSo2dEHKtsfXOC1+Po7WgVwR5IoGjgeVIerddz9g= | |
| 30 | 46 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 31 | 47 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= | |
| 32 | 48 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 49 | + | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |
| 33 | 50 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
| 34 | 51 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
| 52 | + | gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= | |
| 53 | + | gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= | |
| 35 | 54 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
| 36 | 55 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |
| 37 | 56 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
M
main.go
+18,
-5
| ... | ... | @@ -403,7 +403,7 @@ func (c *Config) writeHtml(writeData *WriteData) { | |
| 403 | 403 | bail(err) | |
| 404 | 404 | } | |
| 405 | 405 | ||
| 406 | - | // writeHtmlIfChanged renders a template and only writes if content hash differs from existing file | |
| 406 | + | // writeHtmlIfChanged renders a template and only writes if content hash differs from existing file. | |
| 407 | 407 | func (c *Config) writeHtmlIfChanged(writeData *WriteData) { | |
| 408 | 408 | ts, err := template.New("").Funcs(funcMap).ParseFS( | |
| 409 | 409 | embedFS, |
| ... | ... | @@ -431,7 +431,9 @@ func (c *Config) writeHtmlIfChanged(writeData *WriteData) { | |
| 431 | 431 | ||
| 432 | 432 | // compare with existing file | |
| 433 | 433 | if f, err := os.Open(fp); err == nil { | |
| 434 | - | defer f.Close() | |
| 434 | + | defer func() { | |
| 435 | + | _ = f.Close() | |
| 436 | + | }() | |
| 435 | 437 | h := sha256.New() | |
| 436 | 438 | if _, err := io.Copy(h, f); err == nil { | |
| 437 | 439 | if bytes.Equal(h.Sum(nil), newHash[:]) { |
| ... | ... | @@ -522,6 +524,11 @@ func (c *Config) writeRefs(data PageData, refs []*RefInfo) { | |
| 522 | 524 | }) | |
| 523 | 525 | } | |
| 524 | 526 | ||
| 527 | + | func isMarkdown(filename string) bool { | |
| 528 | + | ext := strings.ToLower(filepath.Ext(filename)) | |
| 529 | + | return ext == ".md" || ext == ".markdown" | |
| 530 | + | } | |
| 531 | + | ||
| 525 | 532 | func (c *Config) writeHTMLTreeFile(pageData PageData, treeItem *TreeItem) string { | |
| 526 | 533 | pageData.ActivePage = "code" | |
| 527 | 534 | d := filepath.Dir(treeItem.Path) |
| ... | ... | @@ -535,8 +542,14 @@ func (c *Config) writeHTMLTreeFile(pageData PageData, treeItem *TreeItem) string | |
| 535 | 542 | contents := "binary file, cannot display" | |
| 536 | 543 | if treeItem.IsTextFile { | |
| 537 | 544 | treeItem.NumLines = len(strings.Split(str, "\n")) | |
| 538 | - | contents, err = c.parseText(treeItem.Entry.Name(), string(b)) | |
| 539 | - | bail(err) | |
| 545 | + | if isMarkdown(treeItem.Entry.Name()) { | |
| 546 | + | html, err := ParseMarkdown(str) | |
| 547 | + | bail(err) | |
| 548 | + | contents = html | |
| 549 | + | } else { | |
| 550 | + | contents, err = c.parseText(treeItem.Entry.Name(), str) | |
| 551 | + | bail(err) | |
| 552 | + | } | |
| 540 | 553 | } | |
| 541 | 554 | ||
| 542 | 555 | nameLower := strings.ToLower(treeItem.Entry.Name()) |
| ... | ... | @@ -718,7 +731,7 @@ func getShortID(id string) string { | |
| 718 | 731 | return id[:7] | |
| 719 | 732 | } | |
| 720 | 733 | ||
| 721 | - | // countCommits returns the total number of commits reachable from the given ref | |
| 734 | + | // countCommits returns the total number of commits reachable from the given ref. | |
| 722 | 735 | func countCommits(repo *git.Repository, ref string) int { | |
| 723 | 736 | // git rev-list --count is the most efficient way to get total commit count | |
| 724 | 737 | cmd := exec.Command("git", "rev-list", "--count", ref) |
+59,
-0
| ... | ... | @@ -0,0 +1,59 @@ | |
| 1 | + | package main | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "bytes" | |
| 5 | + | ||
| 6 | + | "github.com/alecthomas/chroma/v2/formatters/html" | |
| 7 | + | "github.com/yuin/goldmark" | |
| 8 | + | highlighting "github.com/yuin/goldmark-highlighting/v2" | |
| 9 | + | meta "github.com/yuin/goldmark-meta" | |
| 10 | + | "github.com/yuin/goldmark/extension" | |
| 11 | + | "github.com/yuin/goldmark/parser" | |
| 12 | + | ghtml "github.com/yuin/goldmark/renderer/html" | |
| 13 | + | gtext "github.com/yuin/goldmark/text" | |
| 14 | + | "go.abhg.dev/goldmark/anchor" | |
| 15 | + | "go.abhg.dev/goldmark/hashtag" | |
| 16 | + | ) | |
| 17 | + | ||
| 18 | + | func CreateGoldmark(extenders ...goldmark.Extender) goldmark.Markdown { | |
| 19 | + | return goldmark.New( | |
| 20 | + | goldmark.WithExtensions( | |
| 21 | + | extenders..., | |
| 22 | + | ), | |
| 23 | + | goldmark.WithParserOptions( | |
| 24 | + | parser.WithAutoHeadingID(), | |
| 25 | + | ), | |
| 26 | + | goldmark.WithRendererOptions( | |
| 27 | + | ghtml.WithUnsafe(), | |
| 28 | + | ), | |
| 29 | + | ) | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | func ParseMarkdown(text string) (string, error) { | |
| 33 | + | hili := highlighting.NewHighlighting( | |
| 34 | + | highlighting.WithFormatOptions( | |
| 35 | + | html.WithClasses(true), | |
| 36 | + | ), | |
| 37 | + | ) | |
| 38 | + | extenders := []goldmark.Extender{ | |
| 39 | + | extension.GFM, | |
| 40 | + | extension.Footnote, | |
| 41 | + | meta.Meta, | |
| 42 | + | &hashtag.Extender{}, | |
| 43 | + | hili, | |
| 44 | + | &anchor.Extender{ | |
| 45 | + | Position: anchor.After, | |
| 46 | + | Texter: anchor.Text("#"), | |
| 47 | + | }, | |
| 48 | + | } | |
| 49 | + | md := CreateGoldmark(extenders...) | |
| 50 | + | context := parser.NewContext() | |
| 51 | + | btext := []byte(text) | |
| 52 | + | doc := md.Parser().Parse(gtext.NewReader(btext), parser.WithContext(context)) | |
| 53 | + | ||
| 54 | + | var buf bytes.Buffer | |
| 55 | + | if err := md.Renderer().Render(&buf, btext, doc); err != nil { | |
| 56 | + | return "", err | |
| 57 | + | } | |
| 58 | + | return buf.String(), nil | |
| 59 | + | } |
+75,
-0
| ... | ... | @@ -0,0 +1,75 @@ | |
| 1 | + | package main | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "strings" | |
| 5 | + | "testing" | |
| 6 | + | ) | |
| 7 | + | ||
| 8 | + | func TestIsMarkdown(t *testing.T) { | |
| 9 | + | tests := []struct { | |
| 10 | + | filename string | |
| 11 | + | expected bool | |
| 12 | + | }{ | |
| 13 | + | {"README.md", true}, | |
| 14 | + | {"readme.markdown", true}, | |
| 15 | + | {"doc.MD", true}, | |
| 16 | + | {"main.go", false}, | |
| 17 | + | {"Makefile", false}, | |
| 18 | + | {"file.txt", false}, | |
| 19 | + | } | |
| 20 | + | ||
| 21 | + | for _, tt := range tests { | |
| 22 | + | t.Run(tt.filename, func(t *testing.T) { | |
| 23 | + | if got := isMarkdown(tt.filename); got != tt.expected { | |
| 24 | + | t.Errorf("isMarkdown(%q) = %v, expected %v", tt.filename, got, tt.expected) | |
| 25 | + | } | |
| 26 | + | }) | |
| 27 | + | } | |
| 28 | + | } | |
| 29 | + | ||
| 30 | + | func TestParseMarkdown(t *testing.T) { | |
| 31 | + | input := `# Hello World | |
| 32 | + | ||
| 33 | + | This is a paragraph with **bold** and *italic* text. | |
| 34 | + | ||
| 35 | + | ## Features | |
| 36 | + | ||
| 37 | + | - Item 1 | |
| 38 | + | - Item 2 | |
| 39 | + | ||
| 40 | + | ### Code block | |
| 41 | + | ||
| 42 | + | ` + "```go\nfunc main() {\n\tprintln(\"hello\")\n}\n```" + ` | |
| 43 | + | ||
| 44 | + | ### Table | |
| 45 | + | ||
| 46 | + | | Name | Role | | |
| 47 | + | |------|------| | |
| 48 | + | | Alice | Admin | | |
| 49 | + | ` | |
| 50 | + | ||
| 51 | + | html, err := ParseMarkdown(input) | |
| 52 | + | if err != nil { | |
| 53 | + | t.Fatalf("ParseMarkdown returned error: %v", err) | |
| 54 | + | } | |
| 55 | + | ||
| 56 | + | // Heading should not be deleted from HTML | |
| 57 | + | if !strings.Contains(html, `<h1 id="hello-world">Hello World`) { | |
| 58 | + | t.Errorf("expected HTML to contain rendered <h1>, got:\n%s", html) | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | // Heading should have anchor | |
| 62 | + | if !strings.Contains(html, `<a class="anchor" href="#hello-world"`) { | |
| 63 | + | t.Errorf("expected anchor on heading, got:\n%s", html) | |
| 64 | + | } | |
| 65 | + | ||
| 66 | + | // Code block should have chroma classes | |
| 67 | + | if !strings.Contains(html, `class="chroma"`) { | |
| 68 | + | t.Errorf("expected code block to have chroma class, got:\n%s", html) | |
| 69 | + | } | |
| 70 | + | ||
| 71 | + | // Table should be rendered | |
| 72 | + | if !strings.Contains(html, `<table>`) { | |
| 73 | + | t.Errorf("expected table to be rendered, got:\n%s", html) | |
| 74 | + | } | |
| 75 | + | } |