diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 1ea3375ab5..aec710fd46 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -90,6 +90,8 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa } case *ast.RawHTML: g.transformRawHTML(ctx, v, reader) + case *ast.FencedCodeBlock: + g.transformCodeblockLanguage(v, reader) } return ast.WalkContinue, nil }) diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index 61ded3cedc..fc4a515f72 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -1488,3 +1488,27 @@ func TestCallout(t *testing.T) {
Bad stuff is brewing here
`) } + +func TestCodeblockLanguageStripping(t *testing.T) { + test := func(input, expected string) { + buffer, err := markdown.RenderString(&markup.RenderContext{Ctx: git.DefaultContext}, input) + require.NoError(t, err) + assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(string(buffer))) + } + + // Unstripped + test( + "```rust\n"+ + "fn main() {}\n"+ + "```", + `fn main() {}
+`)
+
+ // Stripped
+ test(
+ "```rust,ignore\n"+
+ "fn main() {}\n"+
+ "```",
+ `fn main() {}
+`)
+}
diff --git a/modules/markup/markdown/transform_codeblock_lang.go b/modules/markup/markdown/transform_codeblock_lang.go
new file mode 100644
index 0000000000..2c90373c4e
--- /dev/null
+++ b/modules/markup/markdown/transform_codeblock_lang.go
@@ -0,0 +1,27 @@
+// Copyright 2026 The Forgejo Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package markdown
+
+import (
+ "bytes"
+
+ "github.com/yuin/goldmark/ast"
+ "github.com/yuin/goldmark/text"
+)
+
+func (g *ASTTransformer) transformCodeblockLanguage(v *ast.FencedCodeBlock, reader text.Reader) {
+ src := reader.Source()
+ info := v.Info.Segment.Value(src)
+ // Strip language after commas
+ //
+ // For example,
+ // ```rust,ignore
+ // ...
+ // ```
+ // Should have a language of "rust", not "rust,ignore"
+ if i := bytes.IndexByte(info, ','); i != -1 {
+ start := v.Info.Segment.Start
+ v.Info = ast.NewTextSegment(text.NewSegment(start, start+i))
+ }
+}