summaryrefslogtreecommitdiff
path: root/vendor/github.com/yuin/goldmark-highlighting/v2
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/yuin/goldmark-highlighting/v2')
-rw-r--r--vendor/github.com/yuin/goldmark-highlighting/v2/.gitignore13
-rw-r--r--vendor/github.com/yuin/goldmark-highlighting/v2/LICENSE21
-rw-r--r--vendor/github.com/yuin/goldmark-highlighting/v2/README.md66
-rw-r--r--vendor/github.com/yuin/goldmark-highlighting/v2/highlighting.go578
4 files changed, 678 insertions, 0 deletions
diff --git a/vendor/github.com/yuin/goldmark-highlighting/v2/.gitignore b/vendor/github.com/yuin/goldmark-highlighting/v2/.gitignore
new file mode 100644
index 0000000..6e4db92
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark-highlighting/v2/.gitignore
@@ -0,0 +1,13 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+*.pprof
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
diff --git a/vendor/github.com/yuin/goldmark-highlighting/v2/LICENSE b/vendor/github.com/yuin/goldmark-highlighting/v2/LICENSE
new file mode 100644
index 0000000..dc5b2a6
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark-highlighting/v2/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Yusuke Inuzuka
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/yuin/goldmark-highlighting/v2/README.md b/vendor/github.com/yuin/goldmark-highlighting/v2/README.md
new file mode 100644
index 0000000..5f33672
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark-highlighting/v2/README.md
@@ -0,0 +1,66 @@
+goldmark-highlighting
+=========================
+
+goldmark-highlighting is an extension for the [goldmark](http://github.com/yuin/goldmark)
+that adds syntax-highlighting to the fenced code blocks.
+
+goldmark-highlighting uses [chroma](https://github.com/alecthomas/chroma) as a
+syntax highlighter.
+
+Installation
+--------------------
+
+```
+go get github.com/yuin/goldmark-highlighting/v2
+```
+
+Usage
+--------------------
+
+```go
+import (
+ "bytes"
+ "fmt"
+ "github.com/alecthomas/chroma/formatters/html"
+ "github.com/yuin/goldmark"
+ "github.com/yuin/goldmark/extension"
+ "github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark-highlighting/v2"
+
+)
+
+func main() {
+ markdown := goldmark.New(
+ goldmark.WithExtensions(
+ highlighting.Highlighting,
+ ),
+ )
+ var buf bytes.Buffer
+ if err := markdown.Convert([]byte(source), &buf); err != nil {
+ panic(err)
+ }
+ fmt.Print(title)
+}
+```
+
+
+```go
+ markdown := goldmark.New(
+ goldmark.WithExtensions(
+ highlighting.NewHighlighting(
+ highlighting.WithStyle("monokai"),
+ highlighting.WithFormatOptions(
+ html.WithLineNumbers(),
+ ),
+ ),
+ ),
+ )
+```
+
+License
+--------------------
+MIT
+
+Author
+--------------------
+Yusuke Inuzuka
diff --git a/vendor/github.com/yuin/goldmark-highlighting/v2/highlighting.go b/vendor/github.com/yuin/goldmark-highlighting/v2/highlighting.go
new file mode 100644
index 0000000..d14408a
--- /dev/null
+++ b/vendor/github.com/yuin/goldmark-highlighting/v2/highlighting.go
@@ -0,0 +1,578 @@
+// package highlighting is a extension for the goldmark(http://github.com/yuin/goldmark).
+//
+// This extension adds syntax-highlighting to the fenced code blocks using
+// chroma(https://github.com/alecthomas/chroma).
+package highlighting
+
+import (
+ "bytes"
+ "io"
+ "strconv"
+ "strings"
+
+ "github.com/yuin/goldmark"
+ "github.com/yuin/goldmark/ast"
+ "github.com/yuin/goldmark/parser"
+ "github.com/yuin/goldmark/renderer"
+ "github.com/yuin/goldmark/renderer/html"
+ "github.com/yuin/goldmark/text"
+ "github.com/yuin/goldmark/util"
+
+ "github.com/alecthomas/chroma/v2"
+ chromahtml "github.com/alecthomas/chroma/v2/formatters/html"
+ "github.com/alecthomas/chroma/v2/lexers"
+ "github.com/alecthomas/chroma/v2/styles"
+)
+
+// ImmutableAttributes is a read-only interface for ast.Attributes.
+type ImmutableAttributes interface {
+ // Get returns (value, true) if an attribute associated with given
+ // name exists, otherwise (nil, false)
+ Get(name []byte) (interface{}, bool)
+
+ // GetString returns (value, true) if an attribute associated with given
+ // name exists, otherwise (nil, false)
+ GetString(name string) (interface{}, bool)
+
+ // All returns all attributes.
+ All() []ast.Attribute
+}
+
+type immutableAttributes struct {
+ n ast.Node
+}
+
+func (a *immutableAttributes) Get(name []byte) (interface{}, bool) {
+ return a.n.Attribute(name)
+}
+
+func (a *immutableAttributes) GetString(name string) (interface{}, bool) {
+ return a.n.AttributeString(name)
+}
+
+func (a *immutableAttributes) All() []ast.Attribute {
+ if a.n.Attributes() == nil {
+ return []ast.Attribute{}
+ }
+ return a.n.Attributes()
+}
+
+// CodeBlockContext holds contextual information of code highlighting.
+type CodeBlockContext interface {
+ // Language returns (language, true) if specified, otherwise (nil, false).
+ Language() ([]byte, bool)
+
+ // Highlighted returns true if this code block can be highlighted, otherwise false.
+ Highlighted() bool
+
+ // Attributes return attributes of the code block.
+ Attributes() ImmutableAttributes
+}
+
+type codeBlockContext struct {
+ language []byte
+ highlighted bool
+ attributes ImmutableAttributes
+}
+
+func newCodeBlockContext(language []byte, highlighted bool, attrs ImmutableAttributes) CodeBlockContext {
+ return &codeBlockContext{
+ language: language,
+ highlighted: highlighted,
+ attributes: attrs,
+ }
+}
+
+func (c *codeBlockContext) Language() ([]byte, bool) {
+ if c.language != nil {
+ return c.language, true
+ }
+ return nil, false
+}
+
+func (c *codeBlockContext) Highlighted() bool {
+ return c.highlighted
+}
+
+func (c *codeBlockContext) Attributes() ImmutableAttributes {
+ return c.attributes
+}
+
+// WrapperRenderer renders wrapper elements like div, pre, etc.
+type WrapperRenderer func(w util.BufWriter, context CodeBlockContext, entering bool)
+
+// CodeBlockOptions creates Chroma options per code block.
+type CodeBlockOptions func(ctx CodeBlockContext) []chromahtml.Option
+
+// Config struct holds options for the extension.
+type Config struct {
+ html.Config
+
+ // Style is a highlighting style.
+ // Supported styles are defined under https://github.com/alecthomas/chroma/tree/master/formatters.
+ Style string
+
+ // Pass in a custom Chroma style. If this is not nil, the Style string will be ignored
+ CustomStyle *chroma.Style
+
+ // If set, will try to guess language if none provided.
+ // If the guessing fails, we will fall back to a text lexer.
+ // Note that while Chroma's API supports language guessing, the implementation
+ // is not there yet, so you will currently always get the basic text lexer.
+ GuessLanguage bool
+
+ // FormatOptions is a option related to output formats.
+ // See https://github.com/alecthomas/chroma#the-html-formatter for details.
+ FormatOptions []chromahtml.Option
+
+ // CSSWriter is an io.Writer that will be used as CSS data output buffer.
+ // If WithClasses() is enabled, you can get CSS data corresponds to the style.
+ CSSWriter io.Writer
+
+ // CodeBlockOptions allows set Chroma options per code block.
+ CodeBlockOptions CodeBlockOptions
+
+ // WrapperRenderer allows you to change wrapper elements.
+ WrapperRenderer WrapperRenderer
+}
+
+// NewConfig returns a new Config with defaults.
+func NewConfig() Config {
+ return Config{
+ Config: html.NewConfig(),
+ Style: "github",
+ FormatOptions: []chromahtml.Option{},
+ CSSWriter: nil,
+ WrapperRenderer: nil,
+ CodeBlockOptions: nil,
+ }
+}
+
+// SetOption implements renderer.SetOptioner.
+func (c *Config) SetOption(name renderer.OptionName, value interface{}) {
+ switch name {
+ case optStyle:
+ c.Style = value.(string)
+ case optCustomStyle:
+ c.CustomStyle = value.(*chroma.Style)
+ case optFormatOptions:
+ if value != nil {
+ c.FormatOptions = value.([]chromahtml.Option)
+ }
+ case optCSSWriter:
+ c.CSSWriter = value.(io.Writer)
+ case optWrapperRenderer:
+ c.WrapperRenderer = value.(WrapperRenderer)
+ case optCodeBlockOptions:
+ c.CodeBlockOptions = value.(CodeBlockOptions)
+ case optGuessLanguage:
+ c.GuessLanguage = value.(bool)
+ default:
+ c.Config.SetOption(name, value)
+ }
+}
+
+// Option interface is a functional option interface for the extension.
+type Option interface {
+ renderer.Option
+ // SetHighlightingOption sets given option to the extension.
+ SetHighlightingOption(*Config)
+}
+
+type withHTMLOptions struct {
+ value []html.Option
+}
+
+func (o *withHTMLOptions) SetConfig(c *renderer.Config) {
+ if o.value != nil {
+ for _, v := range o.value {
+ v.(renderer.Option).SetConfig(c)
+ }
+ }
+}
+
+func (o *withHTMLOptions) SetHighlightingOption(c *Config) {
+ if o.value != nil {
+ for _, v := range o.value {
+ v.SetHTMLOption(&c.Config)
+ }
+ }
+}
+
+// WithHTMLOptions is functional option that wraps goldmark HTMLRenderer options.
+func WithHTMLOptions(opts ...html.Option) Option {
+ return &withHTMLOptions{opts}
+}
+
+const optStyle renderer.OptionName = "HighlightingStyle"
+const optCustomStyle renderer.OptionName = "HighlightingCustomStyle"
+
+var highlightLinesAttrName = []byte("hl_lines")
+
+var styleAttrName = []byte("hl_style")
+var nohlAttrName = []byte("nohl")
+var linenosAttrName = []byte("linenos")
+var linenosTableAttrValue = []byte("table")
+var linenosInlineAttrValue = []byte("inline")
+var linenostartAttrName = []byte("linenostart")
+
+type withStyle struct {
+ value string
+}
+
+func (o *withStyle) SetConfig(c *renderer.Config) {
+ c.Options[optStyle] = o.value
+}
+
+func (o *withStyle) SetHighlightingOption(c *Config) {
+ c.Style = o.value
+}
+
+// WithStyle is a functional option that changes highlighting style.
+func WithStyle(style string) Option {
+ return &withStyle{style}
+}
+
+type withCustomStyle struct {
+ value *chroma.Style
+}
+
+func (o *withCustomStyle) SetConfig(c *renderer.Config) {
+ c.Options[optCustomStyle] = o.value
+}
+
+func (o *withCustomStyle) SetHighlightingOption(c *Config) {
+ c.CustomStyle = o.value
+}
+
+// WithStyle is a functional option that changes highlighting style.
+func WithCustomStyle(style *chroma.Style) Option {
+ return &withCustomStyle{style}
+}
+
+const optCSSWriter renderer.OptionName = "HighlightingCSSWriter"
+
+type withCSSWriter struct {
+ value io.Writer
+}
+
+func (o *withCSSWriter) SetConfig(c *renderer.Config) {
+ c.Options[optCSSWriter] = o.value
+}
+
+func (o *withCSSWriter) SetHighlightingOption(c *Config) {
+ c.CSSWriter = o.value
+}
+
+// WithCSSWriter is a functional option that sets io.Writer for CSS data.
+func WithCSSWriter(w io.Writer) Option {
+ return &withCSSWriter{w}
+}
+
+const optGuessLanguage renderer.OptionName = "HighlightingGuessLanguage"
+
+type withGuessLanguage struct {
+ value bool
+}
+
+func (o *withGuessLanguage) SetConfig(c *renderer.Config) {
+ c.Options[optGuessLanguage] = o.value
+}
+
+func (o *withGuessLanguage) SetHighlightingOption(c *Config) {
+ c.GuessLanguage = o.value
+}
+
+// WithGuessLanguage is a functional option that toggles language guessing
+// if none provided.
+func WithGuessLanguage(b bool) Option {
+ return &withGuessLanguage{value: b}
+}
+
+const optWrapperRenderer renderer.OptionName = "HighlightingWrapperRenderer"
+
+type withWrapperRenderer struct {
+ value WrapperRenderer
+}
+
+func (o *withWrapperRenderer) SetConfig(c *renderer.Config) {
+ c.Options[optWrapperRenderer] = o.value
+}
+
+func (o *withWrapperRenderer) SetHighlightingOption(c *Config) {
+ c.WrapperRenderer = o.value
+}
+
+// WithWrapperRenderer is a functional option that sets WrapperRenderer that
+// renders wrapper elements like div, pre, etc.
+func WithWrapperRenderer(w WrapperRenderer) Option {
+ return &withWrapperRenderer{w}
+}
+
+const optCodeBlockOptions renderer.OptionName = "HighlightingCodeBlockOptions"
+
+type withCodeBlockOptions struct {
+ value CodeBlockOptions
+}
+
+func (o *withCodeBlockOptions) SetConfig(c *renderer.Config) {
+ c.Options[optWrapperRenderer] = o.value
+}
+
+func (o *withCodeBlockOptions) SetHighlightingOption(c *Config) {
+ c.CodeBlockOptions = o.value
+}
+
+// WithCodeBlockOptions is a functional option that sets CodeBlockOptions that
+// allows setting Chroma options per code block.
+func WithCodeBlockOptions(c CodeBlockOptions) Option {
+ return &withCodeBlockOptions{value: c}
+}
+
+const optFormatOptions renderer.OptionName = "HighlightingFormatOptions"
+
+type withFormatOptions struct {
+ value []chromahtml.Option
+}
+
+func (o *withFormatOptions) SetConfig(c *renderer.Config) {
+ if _, ok := c.Options[optFormatOptions]; !ok {
+ c.Options[optFormatOptions] = []chromahtml.Option{}
+ }
+ c.Options[optFormatOptions] = append(c.Options[optFormatOptions].([]chromahtml.Option), o.value...)
+}
+
+func (o *withFormatOptions) SetHighlightingOption(c *Config) {
+ c.FormatOptions = append(c.FormatOptions, o.value...)
+}
+
+// WithFormatOptions is a functional option that wraps chroma HTML formatter options.
+func WithFormatOptions(opts ...chromahtml.Option) Option {
+ return &withFormatOptions{opts}
+}
+
+// HTMLRenderer struct is a renderer.NodeRenderer implementation for the extension.
+type HTMLRenderer struct {
+ Config
+}
+
+// NewHTMLRenderer builds a new HTMLRenderer with given options and returns it.
+func NewHTMLRenderer(opts ...Option) renderer.NodeRenderer {
+ r := &HTMLRenderer{
+ Config: NewConfig(),
+ }
+ for _, opt := range opts {
+ opt.SetHighlightingOption(&r.Config)
+ }
+ return r
+}
+
+// RegisterFuncs implements NodeRenderer.RegisterFuncs.
+func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
+ reg.Register(ast.KindFencedCodeBlock, r.renderFencedCodeBlock)
+}
+
+func getAttributes(node *ast.FencedCodeBlock, infostr []byte) ImmutableAttributes {
+ if node.Attributes() != nil {
+ return &immutableAttributes{node}
+ }
+ if infostr != nil {
+ attrStartIdx := -1
+
+ for idx, char := range infostr {
+ if char == '{' {
+ attrStartIdx = idx
+ break
+ }
+ }
+ if attrStartIdx > 0 {
+ n := ast.NewTextBlock() // dummy node for storing attributes
+ attrStr := infostr[attrStartIdx:]
+ if attrs, hasAttr := parser.ParseAttributes(text.NewReader(attrStr)); hasAttr {
+ for _, attr := range attrs {
+ n.SetAttribute(attr.Name, attr.Value)
+ }
+ return &immutableAttributes{n}
+ }
+ }
+ }
+ return nil
+}
+
+func (r *HTMLRenderer) renderFencedCodeBlock(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
+ n := node.(*ast.FencedCodeBlock)
+ if !entering {
+ return ast.WalkContinue, nil
+ }
+ language := n.Language(source)
+
+ chromaFormatterOptions := make([]chromahtml.Option, len(r.FormatOptions))
+ copy(chromaFormatterOptions, r.FormatOptions)
+
+ style := r.CustomStyle
+ if style == nil {
+ style = styles.Get(r.Style)
+ }
+ nohl := false
+
+ var info []byte
+ if n.Info != nil {
+ info = n.Info.Segment.Value(source)
+ }
+ attrs := getAttributes(n, info)
+ if attrs != nil {
+ baseLineNumber := 1
+ if linenostartAttr, ok := attrs.Get(linenostartAttrName); ok {
+ if linenostart, ok := linenostartAttr.(float64); ok {
+ baseLineNumber = int(linenostart)
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.BaseLineNumber(baseLineNumber))
+ }
+ }
+ if linesAttr, hasLinesAttr := attrs.Get(highlightLinesAttrName); hasLinesAttr {
+ if lines, ok := linesAttr.([]interface{}); ok {
+ var hlRanges [][2]int
+ for _, l := range lines {
+ if ln, ok := l.(float64); ok {
+ hlRanges = append(hlRanges, [2]int{int(ln) + baseLineNumber - 1, int(ln) + baseLineNumber - 1})
+ }
+ if rng, ok := l.([]uint8); ok {
+ slices := strings.Split(string([]byte(rng)), "-")
+ lhs, err := strconv.Atoi(slices[0])
+ if err != nil {
+ continue
+ }
+ rhs := lhs
+ if len(slices) > 1 {
+ rhs, err = strconv.Atoi(slices[1])
+ if err != nil {
+ continue
+ }
+ }
+ hlRanges = append(hlRanges, [2]int{lhs + baseLineNumber - 1, rhs + baseLineNumber - 1})
+ }
+ }
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.HighlightLines(hlRanges))
+ }
+ }
+ if styleAttr, hasStyleAttr := attrs.Get(styleAttrName); hasStyleAttr {
+ if st, ok := styleAttr.([]uint8); ok {
+ styleStr := string([]byte(st))
+ style = styles.Get(styleStr)
+ }
+ }
+ if _, hasNohlAttr := attrs.Get(nohlAttrName); hasNohlAttr {
+ nohl = true
+ }
+
+ if linenosAttr, ok := attrs.Get(linenosAttrName); ok {
+ switch v := linenosAttr.(type) {
+ case bool:
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.WithLineNumbers(v))
+ case []uint8:
+ if v != nil {
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.WithLineNumbers(true))
+ }
+ if bytes.Equal(v, linenosTableAttrValue) {
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.LineNumbersInTable(true))
+ } else if bytes.Equal(v, linenosInlineAttrValue) {
+ chromaFormatterOptions = append(chromaFormatterOptions, chromahtml.LineNumbersInTable(false))
+ }
+ }
+ }
+ }
+
+ var lexer chroma.Lexer
+ if language != nil {
+ lexer = lexers.Get(string(language))
+ }
+ if !nohl && (lexer != nil || r.GuessLanguage) {
+ if style == nil {
+ style = styles.Fallback
+ }
+ var buffer bytes.Buffer
+ l := n.Lines().Len()
+ for i := 0; i < l; i++ {
+ line := n.Lines().At(i)
+ buffer.Write(line.Value(source))
+ }
+
+ if lexer == nil {
+ lexer = lexers.Analyse(buffer.String())
+ if lexer == nil {
+ lexer = lexers.Fallback
+ }
+ language = []byte(strings.ToLower(lexer.Config().Name))
+ }
+ lexer = chroma.Coalesce(lexer)
+
+ iterator, err := lexer.Tokenise(nil, buffer.String())
+ if err == nil {
+ c := newCodeBlockContext(language, true, attrs)
+
+ if r.CodeBlockOptions != nil {
+ chromaFormatterOptions = append(chromaFormatterOptions, r.CodeBlockOptions(c)...)
+ }
+ formatter := chromahtml.New(chromaFormatterOptions...)
+ if r.WrapperRenderer != nil {
+ r.WrapperRenderer(w, c, true)
+ }
+ _ = formatter.Format(w, style, iterator) == nil
+ if r.WrapperRenderer != nil {
+ r.WrapperRenderer(w, c, false)
+ }
+ if r.CSSWriter != nil {
+ _ = formatter.WriteCSS(r.CSSWriter, style)
+ }
+ return ast.WalkContinue, nil
+ }
+ }
+
+ var c CodeBlockContext
+ if r.WrapperRenderer != nil {
+ c = newCodeBlockContext(language, false, attrs)
+ r.WrapperRenderer(w, c, true)
+ } else {
+ _, _ = w.WriteString("<pre><code")
+ language := n.Language(source)
+ if language != nil {
+ _, _ = w.WriteString(" class=\"language-")
+ r.Writer.Write(w, language)
+ _, _ = w.WriteString("\"")
+ }
+ _ = w.WriteByte('>')
+ }
+ l := n.Lines().Len()
+ for i := 0; i < l; i++ {
+ line := n.Lines().At(i)
+ r.Writer.RawWrite(w, line.Value(source))
+ }
+ if r.WrapperRenderer != nil {
+ r.WrapperRenderer(w, c, false)
+ } else {
+ _, _ = w.WriteString("</code></pre>\n")
+ }
+ return ast.WalkContinue, nil
+}
+
+type highlighting struct {
+ options []Option
+}
+
+// Highlighting is a goldmark.Extender implementation.
+var Highlighting = &highlighting{
+ options: []Option{},
+}
+
+// NewHighlighting returns a new extension with given options.
+func NewHighlighting(opts ...Option) goldmark.Extender {
+ return &highlighting{
+ options: opts,
+ }
+}
+
+// Extend implements goldmark.Extender.
+func (e *highlighting) Extend(m goldmark.Markdown) {
+ m.Renderer().AddOptions(renderer.WithNodeRenderers(
+ util.Prioritized(NewHTMLRenderer(e.options...), 200),
+ ))
+}