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)) + } +}