bfchroma
Integrating Chroma syntax highlighter as
a Blackfriday renderer.
Install and prerequisites
This project requires and uses the v2
version of
Blackfriday.
$ go get -u github.com/Depado/bfchroma
This project uses the module approach of go 1.11
Features
This renderer integrates chroma to highlight code with triple backtick notation.
It will try to use the given language when available otherwise it will try to
detect the language. If none of these two method works it will fallback to sane
defaults.
Usage
bfchroma uses the functional options approach so you can customize the behavior
of the renderer. It uses sane defaults when no option is passed so you can use
the renderer simply by doing so :
html := bf.Run([]byte(md), bf.WithRenderer(bfchroma.NewRenderer()))
Options
Style(s string)
Define the style used by chroma for the rendering. The full list can be found hereChromaStyle(*chroma.Style)
This option can be used to passe directly a *chroma.Style
instead of the
string representing the style as with the Style(string)
option.WithoutAutodetect()
By default when no language information is written in the code block, this
renderer will try to auto-detect the used language. This option disables
this behavior and will fallback to a sane default when no language
information is available.EmbedCSS()
This option will embed CSS needed for chroma's html.WithClasses()
at the beginning of blackfriday document.
CSS can also be extracted separately by calling Renderer
's.ChromaCSS(w)
method, which will return styleshet for currently set styleExtend(bf.Renderer)
This option allows to define the base blackfriday that will be extended.ChromaOptions(...html.Option)
This option allows you to pass Chroma's html options in the renderer. Such
options can be found here.
Option examples
Disabling language auto-detection and displaying line numbers
r := bfchroma.NewRenderer(
bfchroma.WithoutAutodetect(),
bfchroma.ChromaOptions(html.WithLineNumbers()),
)
Extend a blackfriday renderer
b := bf.NewHTMLRenderer(bf.HTMLRendererParameters{
Flags: bf.CommonHTMLFlags,
})
r := bfchroma.NewRenderer(bfchroma.Extend(b))
Use a different style
r := bfchroma.NewRenderer(bfchroma.Style("dracula"))
r = bfchroma.NewRenderer(bfchroma.ChromaStyle(styles.Dracula))
Examples
package main
import (
"fmt"
"github.com/Depado/bfchroma"
bf "github.com/SaitoJP/blackfriday/v2"
)
var md = "This is some sample code.\n\n```go\n" +
`func main() {
fmt.Println("Hi")
}
` + "```"
func main() {
html := bf.Run([]byte(md), bf.WithRenderer(bfchroma.NewRenderer()))
fmt.Println(string(html))
}
Will output :
<p>This is some sample code.</p>
<pre style="color:#f8f8f2;background-color:#272822"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">"Hi"</span>)
}
</pre>
Real-life example
In smallblog I'm using bfchroma to render
my articles. It's using a combination of both bfchroma's options and blackfriday
extensions and flags.
package main
import (
"github.com/Depado/bfchroma"
"github.com/alecthomas/chroma/formatters/html"
bf "github.com/SaitoJP/blackfriday/v2"
)
var exts = bf.NoIntraEmphasis | bf.Tables | bf.FencedCode | bf.Autolink |
bf.Strikethrough | bf.SpaceHeadings | bf.BackslashLineBreak |
bf.DefinitionLists | bf.Footnotes
var flags = bf.UseXHTML | bf.Smartypants | bf.SmartypantsFractions |
bf.SmartypantsDashes | bf.SmartypantsLatexDashes | bf.TOC
func render(input []byte) []byte {
return bf.Run(
input,
bf.WithRenderer(
bfchroma.NewRenderer(
bfchroma.WithoutAutodetect(),
bfchroma.ChromaOptions(
html.WithLineNumbers(),
),
bfchroma.Extend(
bf.NewHTMLRenderer(bf.HTMLRendererParameters{
Flags: flags,
}),
),
),
),
bf.WithExtensions(exts),
)
}
Classes
If you have loads of code in your markdown, you might want to consider using
html.WithClasses()
in your bfchroma.ChromaOptions()
. The CSS of the style
you chose can then be accessed like this :
r := bfchroma.NewRenderer(
bfchroma.WithoutAutodetect(),
bfchroma.Extend(
bf.NewHTMLRenderer(bf.HTMLRendererParameters{Flags: flags}),
),
bfchroma.Style("monokai"),
bfchroma.ChromaOptions(html.WithClasses()),
)
var css template.CSS
b := new(bytes.Buffer)
if err := r.ChromaCSS(b); err != nil {
logrus.WithError(err).Warning("Couldn't write CSS")
}
css = template.CSS(b.String())
bf.Run(input, bf.WithRenderer(r), bf.WithExtensions(exts))
This way, you can pass your css
var to any template and render it along the
rendered markdown.