Skip to content

Commit

Permalink
refactor syntax highlighting to be blank by default
Browse files Browse the repository at this point in the history
lets you decide in the theme
  • Loading branch information
tj committed Jan 25, 2018
1 parent edaa6e4 commit f1a610f
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 106 deletions.
74 changes: 0 additions & 74 deletions html.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package static

import (
"bytes"
"io"
"strconv"
"strings"

dom "github.com/PuerkitoBio/goquery"
"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters/html"
"github.com/alecthomas/chroma/lexers"
"github.com/alecthomas/chroma/styles"
snakecase "github.com/segmentio/go-snakecase"
)

Expand Down Expand Up @@ -78,72 +73,3 @@ func HeadingAnchors(r io.Reader) io.ReadCloser {

return pr
}

// SyntaxHighlight returns a reader with HTML code prettified with chroma
func SyntaxHighlight(r io.Reader) io.ReadCloser {
pr, pw := io.Pipe()
go func() {
doc, err := dom.NewDocumentFromReader(r)
if err != nil {
pw.CloseWithError(err)
return
}
// TODO: make this configurable?
style := styles.Get("github")
if style == nil {
style = styles.Fallback
}
formatter := html.New(html.Standalone())
doc.Find("pre>code").Each(func(i int, s *dom.Selection) {
lexer := detectLexer(s)
code := s.Contents().Text()
iterator, err := lexer.Tokenise(nil, code)
if err != nil {
pw.CloseWithError(err)
return
}
var html bytes.Buffer
err = formatter.Format(&html, style, iterator)
if err != nil {
pw.CloseWithError(err)
return
}

// Parent() because chroma html is already in a <pre><code>.
s.Parent().ReplaceWithHtml(html.String())
})

html, err := doc.Html()
if err != nil {
pw.CloseWithError(err)
return
}

pw.Write([]byte(html))
pw.Close()
}()
return pr
}

func detectLexer(s *dom.Selection) chroma.Lexer {
var lang string
classes, ok := s.Attr("class")
if ok {
for _, class := range strings.Split(classes, " ") {
if strings.HasPrefix(class, "language-") {
lang = strings.TrimPrefix(class, "language-")
}
}
}
var lexer chroma.Lexer
if lang != "" {
lexer = lexers.Get(lang)
}
if lexer == nil {
lexer = lexers.Analyse(s.Contents().Text())
}
if lexer == nil {
lexer = lexers.Fallback
}
return chroma.Coalesce(lexer)
}
89 changes: 89 additions & 0 deletions html_highlight.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package static

import (
"bytes"
"io"
"strings"

dom "github.com/PuerkitoBio/goquery"
"github.com/alecthomas/chroma"
"github.com/alecthomas/chroma/formatters/html"
"github.com/alecthomas/chroma/lexers"
)

// blankStyle is a blank style.
var blankStyle = chroma.MustNewStyle("blank", chroma.StyleEntries{})

// SyntaxHighlight returns a reader with HTML code prettified with chroma.
func SyntaxHighlight(r io.Reader) io.ReadCloser {
pr, pw := io.Pipe()

go func() {
doc, err := dom.NewDocumentFromReader(r)
if err != nil {
pw.CloseWithError(err)
return
}

formatter := html.New(html.WithClasses())
doc.Find("pre > code").Each(func(i int, s *dom.Selection) {
lexer := detectLexer(s)
code := s.Contents().Text()

iterator, err := lexer.Tokenise(nil, code)
if err != nil {
pw.CloseWithError(err)
return
}

var buf bytes.Buffer
err = formatter.Format(&buf, blankStyle, iterator)
if err != nil {
pw.CloseWithError(err)
return
}

// Parent() because chroma html is already in a <pre><code>.
s.Parent().ReplaceWithHtml(buf.String())
})

html, err := doc.Html()
if err != nil {
pw.CloseWithError(err)
return
}

pw.Write([]byte(html))
pw.Close()
}()

return pr
}

// detectLexer returns a chroma lexer based on the classname.
func detectLexer(s *dom.Selection) chroma.Lexer {
var lexer chroma.Lexer
var lang string

if classes, ok := s.Attr("class"); ok {
for _, c := range strings.Split(classes, " ") {
if strings.HasPrefix(c, "language-") {
lang = strings.TrimPrefix(c, "language-")
}
}
}

if lang != "" {
lexer = lexers.Get(lang)
}

if lexer == nil {
lexer = lexers.Analyse(s.Contents().Text())
}

if lexer == nil {
lexer = lexers.Fallback
}

return chroma.Coalesce(lexer)
}
38 changes: 38 additions & 0 deletions html_highlight_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package static

import (
"io/ioutil"
"strings"
"testing"
)

func TestSyntaxHighlight(t *testing.T) {
r := ioutil.NopCloser(strings.NewReader(`
<pre><code>
package main
func main() {
fmt.Println("foo")
}
</code></pre>
<pre><code class="language-yaml">
foo: bar
list:
- 1
- 2
</code></pre>
<pre><code>
this is not even a lang
</code></pre>
`))

r = SyntaxHighlight(r)
got, _ := ioutil.ReadAll(r)
expect, _ := ioutil.ReadFile("testdata/code.html")
if string(got) != string(expect) {
t.Errorf("expected %s but got %s", string(expect), string(got))
// ioutil.WriteFile("testdata/code.html", got, 0644)
}
}
32 changes: 0 additions & 32 deletions html_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"io/ioutil"
"os"
"strings"
"testing"
)

func ExampleHeadingAnchors() {
Expand Down Expand Up @@ -53,34 +52,3 @@ func ExampleHeadingAnchors() {
// </a>Section 1</h2>
// </body></html>
}

func TestSyntaxHighlight(t *testing.T) {
r := ioutil.NopCloser(strings.NewReader(`
<pre><code>
package main
func main() {
fmt.Println("foo")
}
</code></pre>
<pre><code class="language-yaml">
foo: bar
list:
- 1
- 2
</code></pre>
<pre><code>
this is not even a lang
</code></pre>
`))

r = SyntaxHighlight(r)
got, _ := ioutil.ReadAll(r)
expect, _ := ioutil.ReadFile("testdata/code.html")
if string(got) != string(expect) {
t.Errorf("expected %s but got %s", string(expect), string(got))
// ioutil.WriteFile("testdata/code.html", got, 0644)
}
}

0 comments on commit f1a610f

Please sign in to comment.