diff --git a/README.md b/README.md index ef74fc9f..f1591780 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ Parser and Renderer options | `html.WithHardWraps` | `-` | Render newlines as `
`.| | `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 `` elements. An empty string removes the prefix. | ### Built-in extensions diff --git a/extra_test.go b/extra_test.go index a2d3d623..9bae4918 100644 --- a/extra_test.go +++ b/extra_test.go @@ -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: "
code\n
\n", + }, + { + prefix: "custom-", + source: "```go\ncode\n```", + expected: "
code\n
\n", + }, + { + prefix: "", + source: "```go\ncode\n```", + expected: "
code\n
\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()) + } + } +} diff --git a/renderer/html/html.go b/renderer/html/html.go index 903dc680..08308546 100644 --- a/renderer/html/html.go +++ b/renderer/html/html.go @@ -20,8 +20,12 @@ type Config struct { EastAsianLineBreaks EastAsianLineBreaks XHTML bool Unsafe bool + CodeClassPrefix string } +// Default class prefix for elements. +const DefaultCodeClassPrefix = "language-" + // NewConfig returns a new Config with defaults. func NewConfig() Config { return Config{ @@ -30,6 +34,7 @@ func NewConfig() Config { EastAsianLineBreaks: EastAsianLineBreaksNone, XHTML: false, Unsafe: false, + CodeClassPrefix: DefaultCodeClassPrefix, } } @@ -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) } } @@ -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 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 { @@ -360,7 +390,8 @@ func (r *Renderer) renderFencedCodeBlock( _, _ = w.WriteString("