mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2026-04-29 07:49:01 -04:00
feat(ui): Support Pandoc style code blocks
This commit is contained in:
parent
2b42fdaa26
commit
b53aed2d67
2 changed files with 72 additions and 3 deletions
|
|
@ -1489,14 +1489,14 @@ func TestCallout(t *testing.T) {
|
|||
</blockquote>`)
|
||||
}
|
||||
|
||||
func TestCodeblockLanguageStripping(t *testing.T) {
|
||||
func TestCodeblockLanguageTransformation(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
|
||||
// No transformation
|
||||
test(
|
||||
"```rust\n"+
|
||||
"fn main() {}\n"+
|
||||
|
|
@ -1504,11 +1504,37 @@ func TestCodeblockLanguageStripping(t *testing.T) {
|
|||
`<pre class="code-block"><code class="chroma language-rust display"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{}</span><span class="w">
|
||||
</span></code></pre>`)
|
||||
|
||||
// Stripped
|
||||
// Comma stripped
|
||||
test(
|
||||
"```rust,ignore\n"+
|
||||
"fn main() {}\n"+
|
||||
"```",
|
||||
`<pre class="code-block"><code class="chroma language-rust display"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{}</span><span class="w">
|
||||
</span></code></pre>`)
|
||||
|
||||
// Pandoc stripping
|
||||
// https://pandoc.org/MANUAL.html#extension-fenced_code_attributes
|
||||
test(
|
||||
"```haskell {.numberLines}\n"+
|
||||
"qsort [] = []\n"+
|
||||
"qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++\n"+
|
||||
" qsort (filter (>= x) xs)\n"+
|
||||
"```",
|
||||
`<pre class="code-block"><code class="chroma language-haskell display"><span class="nf">qsort</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="kt">[]</span>
|
||||
<span class="nf">qsort</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> <span class="n">qsort</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o"><</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span> <span class="o">++</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">++</span>
|
||||
<span class="n">qsort</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o">>=</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span>
|
||||
</code></pre>`)
|
||||
|
||||
// Pandoc language extracting
|
||||
// https://pandoc.org/MANUAL.html#extension-fenced_code_attributes
|
||||
test(
|
||||
"```{#mycode .numberLines .haskell startFrom=\"100\"}\n"+
|
||||
"qsort [] = []\n"+
|
||||
"qsort (x:xs) = qsort (filter (< x) xs) ++ [x] ++\n"+
|
||||
" qsort (filter (>= x) xs)\n"+
|
||||
"```",
|
||||
`<pre class="code-block"><code class="chroma language-haskell display"><span class="nf">qsort</span> <span class="kt">[]</span> <span class="ow">=</span> <span class="kt">[]</span>
|
||||
<span class="nf">qsort</span> <span class="p">(</span><span class="n">x</span><span class="kt">:</span><span class="n">xs</span><span class="p">)</span> <span class="ow">=</span> <span class="n">qsort</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o"><</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span> <span class="o">++</span> <span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="o">++</span>
|
||||
<span class="n">qsort</span> <span class="p">(</span><span class="n">filter</span> <span class="p">(</span><span class="o">>=</span> <span class="n">x</span><span class="p">)</span> <span class="n">xs</span><span class="p">)</span>
|
||||
</code></pre>`)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package markdown
|
|||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/alecthomas/chroma/v2/lexers"
|
||||
"github.com/yuin/goldmark/ast"
|
||||
"github.com/yuin/goldmark/text"
|
||||
)
|
||||
|
|
@ -13,6 +14,47 @@ import (
|
|||
func (g *ASTTransformer) transformCodeblockLanguage(v *ast.FencedCodeBlock, reader text.Reader) {
|
||||
src := reader.Source()
|
||||
info := v.Info.Segment.Value(src)
|
||||
|
||||
// Parse Pandoc style attributes
|
||||
// https://pandoc.org/MANUAL.html#extension-fenced_code_attributes
|
||||
//
|
||||
// For example,
|
||||
// ```{.haskell .numberLines}
|
||||
// ...
|
||||
// ```
|
||||
// Should have a language of "haskell", not "{.haskell .numberLines}"
|
||||
if trimmed := bytes.TrimSpace(info); len(trimmed) != 0 && trimmed[0] == '{' && trimmed[len(trimmed)-1] == '}' {
|
||||
attributes := trimmed[1 : len(trimmed)-1]
|
||||
for attribute := range bytes.SplitSeq(attributes, []byte{' '}) {
|
||||
if len(attribute) != 0 && attribute[0] == '.' {
|
||||
class := attribute[1:]
|
||||
if lexer := lexers.Get(string(class)); lexer != nil {
|
||||
lang := class
|
||||
langInx := bytes.Index(info, lang)
|
||||
start := v.Info.Segment.Start + langInx
|
||||
end := start + len(lang)
|
||||
v.Info = ast.NewTextSegment(text.NewSegment(start, end))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Strip trailing Pandoc style attributes
|
||||
// https://pandoc.org/MANUAL.html#extension-fenced_code_attributes
|
||||
//
|
||||
// For example,
|
||||
// ```haskell {.numberLines}
|
||||
// ...
|
||||
// ```
|
||||
// Should have a language of "haskell ", not "haskell {.numberLines}"
|
||||
if i := bytes.IndexByte(info, '{'); i != -1 {
|
||||
start := v.Info.Segment.Start
|
||||
v.Info = ast.NewTextSegment(text.NewSegment(start, start+i))
|
||||
return
|
||||
}
|
||||
|
||||
// Strip language after commas
|
||||
//
|
||||
// For example,
|
||||
|
|
@ -23,5 +65,6 @@ func (g *ASTTransformer) transformCodeblockLanguage(v *ast.FencedCodeBlock, read
|
|||
if i := bytes.IndexByte(info, ','); i != -1 {
|
||||
start := v.Info.Segment.Start
|
||||
v.Info = ast.NewTextSegment(text.NewSegment(start, start+i))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue