Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slight bug in katex #21171

Merged
merged 7 commits into from
Oct 5, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
50 changes: 50 additions & 0 deletions modules/markup/markdown/markdown_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package markdown_test

import (
"context"
"os"
"strings"
"testing"

Expand Down Expand Up @@ -37,6 +38,7 @@ func TestMain(m *testing.M) {
if err := git.InitSimple(context.Background()); err != nil {
log.Fatal("git init failed, err: %v", err)
}
os.Exit(m.Run())
}

func TestRender_StandardLinks(t *testing.T) {
Expand Down Expand Up @@ -426,3 +428,51 @@ func TestRenderEmojiInLinks_Issue12331(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, expected, res)
}

func TestMathBlock(t *testing.T) {
const nl = "\n"
testcases := []struct {
testcase string
expected string
}{
{
"$a$",
`<p><code class="language-math is-loading">a</code></p>` + nl,
},
{
"$ a $",
`<p><code class="language-math is-loading">a</code></p>` + nl,
},
{
"$a$ $b$",
`<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl,
},
{
`\(a\) \(b\)`,
`<p><code class="language-math is-loading">a</code> <code class="language-math is-loading">b</code></p>` + nl,
},
{
`$a a$b b$`,
`<p><code class="language-math is-loading">a a$b b</code></p>` + nl,
},
{
`a a$b b`,
`<p>a a$b b</p>` + nl,
},
{
`a$b $a a$b b$`,
`<p>a$b <code class="language-math is-loading">a a$b b</code></p>` + nl,
},
{
"$$a$$",
`<pre class="code-block is-loading"><code class="chroma language-math display">a</code></pre>` + nl,
},
}

for _, test := range testcases {
res, err := RenderString(&markup.RenderContext{}, test.testcase)
assert.NoError(t, err, "Unexpected error in testcase: %q", test.testcase)
assert.Equal(t, test.expected, res, "Unexpected result in testcase %q", test.testcase)

}
}
47 changes: 34 additions & 13 deletions modules/markup/markdown/math/inline_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func NewInlineBracketParser() parser.InlineParser {
return defaultInlineBracketParser
}

// Trigger triggers this parser on $
// Trigger returns nil
zeripath marked this conversation as resolved.
Show resolved Hide resolved
func (parser *inlineParser) Trigger() []byte {
return parser.start[0:1]
}
Expand All @@ -50,29 +50,50 @@ func isAlphanumeric(b byte) bool {
// Parse parses the current line and returns a result of parsing.
func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node {
line, _ := block.PeekLine()
opener := bytes.Index(line, parser.start)
if opener < 0 {
return nil
}
if opener != 0 && isAlphanumeric(line[opener-1]) {

if !bytes.HasPrefix(line, parser.start) {
// We'll catch this one on the next time round
return nil
}

opener += len(parser.start)
ender := bytes.Index(line[opener:], parser.end)
if ender < 0 {
precedingCharacter := block.PrecendingCharacter()
if precedingCharacter < 256 && isAlphanumeric(byte(precedingCharacter)) {
// need to exclude things like `a$` from being considered a start
return nil
}
if len(line) > opener+ender+len(parser.end) && isAlphanumeric(line[opener+ender+len(parser.end)]) {
return nil

// move the opener marker point at the start of the text
opener := len(parser.start)

// Now look for an ending line
ender := opener
for {
pos := bytes.Index(line[ender:], parser.end)
if pos < 0 {
return nil
}

ender += pos

// Now we want to check the character at the end of our parser section
// that is ender + len(parser.end)
pos = ender + len(parser.end)
if len(line) <= pos {
break
}
if !isAlphanumeric(line[pos]) {
break
}
// move the pointer onwards
ender += len(parser.end)
}

block.Advance(opener)
_, pos := block.Position()
node := NewInline()
segment := pos.WithStop(pos.Start + ender)
segment := pos.WithStop(pos.Start + ender - opener)
node.AppendChild(node, ast.NewRawTextSegment(segment))
block.Advance(ender + len(parser.end))
block.Advance(ender - opener + len(parser.end))

trimBlock(node, block)
return node
Expand Down
96 changes: 52 additions & 44 deletions modules/markup/markdown/renderconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
package markdown

import (
"fmt"
"strings"

"code.gitea.io/gitea/modules/log"

"github.com/yuin/goldmark/ast"
"gopkg.in/yaml.v3"
)
Expand All @@ -33,72 +32,81 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
}
rc.yamlNode = value

type basicRenderConfig struct {
Gitea *yaml.Node `yaml:"gitea"`
TOC bool `yaml:"include_toc"`
Lang string `yaml:"lang"`
type commonRenderConfig struct {
TOC bool `yaml:"include_toc"`
Lang string `yaml:"lang"`
}

var basic basicRenderConfig

err := value.Decode(&basic)
if err != nil {
return err
var basic commonRenderConfig
if err := value.Decode(&basic); err != nil {
return fmt.Errorf("unable to decode into basicRenderConfig %w", err)
zeripath marked this conversation as resolved.
Show resolved Hide resolved
}

if basic.Lang != "" {
rc.Lang = basic.Lang
}

rc.TOC = basic.TOC
if basic.Gitea == nil {
return nil

type controlStringRenderConfig struct {
Gitea string `yaml:"gitea"`
}

var control *string
if err := basic.Gitea.Decode(&control); err == nil && control != nil {
log.Info("control %v", control)
switch strings.TrimSpace(strings.ToLower(*control)) {
case "none":
rc.Meta = "none"
case "table":
rc.Meta = "table"
default: // "details"
rc.Meta = "details"
var stringBasic controlStringRenderConfig

if err := value.Decode(&stringBasic); err == nil {
if stringBasic.Gitea != "" {
switch strings.TrimSpace(strings.ToLower(stringBasic.Gitea)) {
case "none":
rc.Meta = "none"
case "table":
rc.Meta = "table"
default: // "details"
rc.Meta = "details"
}
}
return nil
}

type giteaControl struct {
Meta string `yaml:"meta"`
Icon string `yaml:"details_icon"`
TOC *yaml.Node `yaml:"include_toc"`
Lang string `yaml:"lang"`
Meta *string `yaml:"meta"`
Icon *string `yaml:"details_icon"`
TOC *bool `yaml:"include_toc"`
Lang *string `yaml:"lang"`
}

type complexGiteaConfig struct {
Gitea *giteaControl `yaml:"gitea"`
}
var complex complexGiteaConfig
if err := value.Decode(&complex); err != nil {
return fmt.Errorf("unable to decode into complexRenderConfig %w", err)
}

var controlStruct *giteaControl
if err := basic.Gitea.Decode(controlStruct); err != nil || controlStruct == nil {
return err
if complex.Gitea == nil {
return nil
}

switch strings.TrimSpace(strings.ToLower(controlStruct.Meta)) {
case "none":
rc.Meta = "none"
case "table":
rc.Meta = "table"
default: // "details"
rc.Meta = "details"
if complex.Gitea.Meta != nil {
switch strings.TrimSpace(strings.ToLower(*complex.Gitea.Meta)) {
case "none":
rc.Meta = "none"
case "table":
rc.Meta = "table"
default: // "details"
rc.Meta = "details"
}
}

rc.Icon = strings.TrimSpace(strings.ToLower(controlStruct.Icon))
if complex.Gitea.Icon != nil {
rc.Icon = strings.TrimSpace(strings.ToLower(*complex.Gitea.Icon))
}

if controlStruct.Lang != "" {
rc.Lang = controlStruct.Lang
if complex.Gitea.Lang != nil && *complex.Gitea.Lang != "" {
rc.Lang = *complex.Gitea.Lang
}

var toc bool
if err := controlStruct.TOC.Decode(&toc); err == nil {
rc.TOC = toc
if complex.Gitea.TOC != nil {
rc.TOC = *complex.Gitea.TOC
}

return nil
Expand Down
22 changes: 12 additions & 10 deletions modules/markup/markdown/renderconfig_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
package markdown

import (
"strings"
"testing"

"code.gitea.io/gitea/modules/util"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -80,20 +82,20 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
Icon: "table",
TOC: true,
Lang: "testlang",
}, `
include_toc: true
lang: testlang
`,
}, util.Dedent(`
include_toc: true
lang: testlang
`),
},
{
"complexlang", &RenderConfig{
Meta: "table",
Icon: "table",
Lang: "testlang",
}, `
gitea:
lang: testlang
`,
}, util.Dedent(`
gitea:
lang: testlang
`),
},
{
"complexlang2", &RenderConfig{
Expand Down Expand Up @@ -140,8 +142,8 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
Icon: "table",
Lang: "",
}
if err := yaml.Unmarshal([]byte(tt.args), got); err != nil {
t.Errorf("RenderConfig.UnmarshalYAML() error = %v", err)
if err := yaml.Unmarshal([]byte(strings.ReplaceAll(tt.args, "\t", " ")), got); err != nil {
t.Errorf("RenderConfig.UnmarshalYAML() error = %v\n%q", err, tt.args)
return
}

Expand Down