Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ Parser and Renderer options
| `html.WithHardWraps` | `-` | Render newlines as `<br>`.|
| `html.WithXHTML` | `-` | Render as XHTML. |
| `html.WithUnsafe` | `-` | By default, goldmark does not render raw HTML or potentially dangerous links. With this option, goldmark renders such content as written. |
| `html.WithCodeClassPrefix` | `string` | Sets a custom prefix for the `class` attribute of `<code>` elements. An empty string removes the prefix. |

### Built-in extensions

Expand Down
38 changes: 38 additions & 0 deletions extra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,41 @@ func TestDangerousURLStringCase(t *testing.T) {
t.Error("Dangerous URL should ignore cases:\n" + string(testutil.DiffPretty(expected, b.Bytes())))
}
}

func TestCodeClassPrefix(t *testing.T) {
cases := []struct {
prefix string
source string
expected string
}{
{
prefix: "language-",
source: "```go\ncode\n```",
expected: "<pre><code class=\"language-go\">code\n</code></pre>\n",
},
{
prefix: "custom-",
source: "```go\ncode\n```",
expected: "<pre><code class=\"custom-go\">code\n</code></pre>\n",
},
{
prefix: "",
source: "```go\ncode\n```",
expected: "<pre><code class=\"go\">code\n</code></pre>\n",
},
}

for _, c := range cases {
markdown := New(WithRendererOptions(
html.WithCodeClassPrefix(c.prefix),
))
var b bytes.Buffer
err := markdown.Convert([]byte(c.source), &b)
if err != nil {
t.Errorf("unexpected error: %v", err)
}
if b.String() != c.expected {
t.Errorf("prefix: %q\nsource: %q\nexpected: %q\ngot: %q", c.prefix, c.source, c.expected, b.String())
}
}
}
33 changes: 32 additions & 1 deletion renderer/html/html.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ type Config struct {
EastAsianLineBreaks EastAsianLineBreaks
XHTML bool
Unsafe bool
CodeClassPrefix string
}

// Default class prefix for <code> elements.
const DefaultCodeClassPrefix = "language-"

// NewConfig returns a new Config with defaults.
func NewConfig() Config {
return Config{
Expand All @@ -30,6 +34,7 @@ func NewConfig() Config {
EastAsianLineBreaks: EastAsianLineBreaksNone,
XHTML: false,
Unsafe: false,
CodeClassPrefix: DefaultCodeClassPrefix,
}
}

Expand All @@ -46,6 +51,8 @@ func (c *Config) SetOption(name renderer.OptionName, value interface{}) {
c.Unsafe = value.(bool)
case optTextWriter:
c.Writer = value.(Writer)
case optCodeClassPrefix:
c.CodeClassPrefix = value.(string)
}
}

Expand Down Expand Up @@ -240,6 +247,29 @@ func WithUnsafe() interface {
return &withUnsafe{}
}

// CodeClassPrefix is an option name used in WithCodeClassPrefix.
const optCodeClassPrefix renderer.OptionName = "CodeClassPrefix"

type withCodeClassPrefix struct {
value string
}

func (o *withCodeClassPrefix) SetConfig(c *renderer.Config) {
c.Options[optCodeClassPrefix] = o.value
}

func (o *withCodeClassPrefix) SetHTMLOption(c *Config) {
c.CodeClassPrefix = o.value
}

// WithCodeClassPrefix is a functional option to set the class prefix for <code> elements.
func WithCodeClassPrefix(prefix string) interface {
renderer.Option
Option
} {
return &withCodeClassPrefix{prefix}
}

// A Renderer struct is an implementation of renderer.NodeRenderer that renders
// nodes as (X)HTML.
type Renderer struct {
Expand Down Expand Up @@ -360,7 +390,8 @@ func (r *Renderer) renderFencedCodeBlock(
_, _ = w.WriteString("<pre><code")
language := n.Language(source)
if language != nil {
_, _ = w.WriteString(" class=\"language-")
_, _ = w.WriteString(" class=\"")
_, _ = w.WriteString(r.CodeClassPrefix)
r.Writer.Write(w, language)
_, _ = w.WriteString("\"")
}
Expand Down