diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 05b7494f96..07a6ebdcf2 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -1413,14 +1413,14 @@ LEVEL = Info
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; Render soft line breaks as hard line breaks, which means a single newline character between
-;; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not
-;; necessary to force a line break.
-;; Render soft line breaks as hard line breaks for comments
-;ENABLE_HARD_LINE_BREAK_IN_COMMENTS = true
-;;
-;; Render soft line breaks as hard line breaks for markdown documents
-;ENABLE_HARD_LINE_BREAK_IN_DOCUMENTS = false
+;; Customize render options for different contexts. Set to "none" to disable the defaults, or use comma separated list:
+;; * short-issue-pattern: recognized "#123" issue reference and render it as a link to the issue
+;; * new-line-hard-break: render soft line breaks as hard line breaks, which means a single newline character between
+;; paragraphs will cause a line break and adding trailing whitespace to paragraphs is not
+;; necessary to force a line break.
+;RENDER_OPTIONS_COMMENT = short-issue-pattern, new-line-hard-break
+;RENDER_OPTIONS_WIKI = short-issue-pattern
+;RENDER_OPTIONS_REPO_FILE =
;;
;; Comma separated list of custom URL-Schemes that are allowed as links when rendering Markdown
;; for example git,magnet,ftp (more at https://en.wikipedia.org/wiki/List_of_URI_schemes)
@@ -1434,6 +1434,12 @@ LEVEL = Info
;;
;; Enables math inline and block detection
;ENABLE_MATH = true
+;;
+;; Enable delimiters for math code block detection. Set to "none" to disable all,
+;; or use comma separated list: inline-dollar, inline-parentheses, block-dollar, block-square-brackets
+;; Defaults to "inline-dollar,block-dollar" to follow GitHub's behavior.
+;MATH_CODE_BLOCK_DETECTION =
+;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/models/renderhelper/repo_comment.go b/models/renderhelper/repo_comment.go
index eab85bf6d4..7c40eded44 100644
--- a/models/renderhelper/repo_comment.go
+++ b/models/renderhelper/repo_comment.go
@@ -56,7 +56,7 @@ func NewRenderContextRepoComment(ctx context.Context, repo *repo_model.Repositor
if repo != nil {
helper.repoLink = repo.Link()
helper.commitChecker = newCommitChecker(ctx, repo)
- rctx = rctx.WithMetas(repo.ComposeMetas(ctx))
+ rctx = rctx.WithMetas(repo.ComposeCommentMetas(ctx))
} else {
// this is almost dead code, only to pass the incorrect tests
helper.repoLink = fmt.Sprintf("%s/%s", helper.opts.DeprecatedOwnerName, helper.opts.DeprecatedRepoName)
@@ -64,7 +64,7 @@ func NewRenderContextRepoComment(ctx context.Context, repo *repo_model.Repositor
"user": helper.opts.DeprecatedOwnerName,
"repo": helper.opts.DeprecatedRepoName,
- "markdownLineBreakStyle": "comment",
+ "markdownNewLineHardBreak": "true",
"markupAllowShortIssuePattern": "true",
})
}
diff --git a/models/renderhelper/repo_file.go b/models/renderhelper/repo_file.go
index 5bf754bf20..e0375ed280 100644
--- a/models/renderhelper/repo_file.go
+++ b/models/renderhelper/repo_file.go
@@ -61,15 +61,13 @@ func NewRenderContextRepoFile(ctx context.Context, repo *repo_model.Repository,
if repo != nil {
helper.repoLink = repo.Link()
helper.commitChecker = newCommitChecker(ctx, repo)
- rctx = rctx.WithMetas(repo.ComposeDocumentMetas(ctx))
+ rctx = rctx.WithMetas(repo.ComposeRepoFileMetas(ctx))
} else {
// this is almost dead code, only to pass the incorrect tests
helper.repoLink = fmt.Sprintf("%s/%s", helper.opts.DeprecatedOwnerName, helper.opts.DeprecatedRepoName)
rctx = rctx.WithMetas(map[string]string{
"user": helper.opts.DeprecatedOwnerName,
"repo": helper.opts.DeprecatedRepoName,
-
- "markdownLineBreakStyle": "document",
})
}
rctx = rctx.WithHelper(helper)
diff --git a/models/renderhelper/repo_wiki.go b/models/renderhelper/repo_wiki.go
index 1e3e07295c..b75f1b9701 100644
--- a/models/renderhelper/repo_wiki.go
+++ b/models/renderhelper/repo_wiki.go
@@ -68,7 +68,6 @@ func NewRenderContextRepoWiki(ctx context.Context, repo *repo_model.Repository,
"user": helper.opts.DeprecatedOwnerName,
"repo": helper.opts.DeprecatedRepoName,
- "markdownLineBreakStyle": "document",
"markupAllowShortIssuePattern": "true",
})
}
diff --git a/models/repo/repo.go b/models/repo/repo.go
index 050be760d5..2977dfb9f1 100644
--- a/models/repo/repo.go
+++ b/models/repo/repo.go
@@ -512,15 +512,15 @@ func (repo *Repository) composeCommonMetas(ctx context.Context) map[string]strin
"repo": repo.Name,
}
- unit, err := repo.GetUnit(ctx, unit.TypeExternalTracker)
+ unitExternalTracker, err := repo.GetUnit(ctx, unit.TypeExternalTracker)
if err == nil {
- metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat
- switch unit.ExternalTrackerConfig().ExternalTrackerStyle {
+ metas["format"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerFormat
+ switch unitExternalTracker.ExternalTrackerConfig().ExternalTrackerStyle {
case markup.IssueNameStyleAlphanumeric:
metas["style"] = markup.IssueNameStyleAlphanumeric
case markup.IssueNameStyleRegexp:
metas["style"] = markup.IssueNameStyleRegexp
- metas["regexp"] = unit.ExternalTrackerConfig().ExternalTrackerRegexpPattern
+ metas["regexp"] = unitExternalTracker.ExternalTrackerConfig().ExternalTrackerRegexpPattern
default:
metas["style"] = markup.IssueNameStyleNumeric
}
@@ -544,11 +544,11 @@ func (repo *Repository) composeCommonMetas(ctx context.Context) map[string]strin
return repo.commonRenderingMetas
}
-// ComposeMetas composes a map of metas for properly rendering comments or comment-like contents (commit message)
-func (repo *Repository) ComposeMetas(ctx context.Context) map[string]string {
+// ComposeCommentMetas composes a map of metas for properly rendering comments or comment-like contents (commit message)
+func (repo *Repository) ComposeCommentMetas(ctx context.Context) map[string]string {
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "comment"
- metas["markupAllowShortIssuePattern"] = "true"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsComment.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsComment.ShortIssuePattern)
return metas
}
@@ -556,16 +556,17 @@ func (repo *Repository) ComposeMetas(ctx context.Context) map[string]string {
func (repo *Repository) ComposeWikiMetas(ctx context.Context) map[string]string {
// does wiki need the "teams" and "org" from common metas?
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "document"
- metas["markupAllowShortIssuePattern"] = "true"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsWiki.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsWiki.ShortIssuePattern)
return metas
}
-// ComposeDocumentMetas composes a map of metas for properly rendering documents (repo files)
-func (repo *Repository) ComposeDocumentMetas(ctx context.Context) map[string]string {
+// ComposeRepoFileMetas composes a map of metas for properly rendering documents (repo files)
+func (repo *Repository) ComposeRepoFileMetas(ctx context.Context) map[string]string {
// does document(file) need the "teams" and "org" from common metas?
metas := maps.Clone(repo.composeCommonMetas(ctx))
- metas["markdownLineBreakStyle"] = "document"
+ metas["markdownNewLineHardBreak"] = strconv.FormatBool(setting.Markdown.RenderOptionsRepoFile.NewLineHardBreak)
+ metas["markupAllowShortIssuePattern"] = strconv.FormatBool(setting.Markdown.RenderOptionsRepoFile.ShortIssuePattern)
return metas
}
diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go
index dffbd18261..b2604ab575 100644
--- a/models/repo/repo_test.go
+++ b/models/repo/repo_test.go
@@ -86,7 +86,7 @@ func TestMetas(t *testing.T) {
repo.Units = nil
- metas := repo.ComposeMetas(db.DefaultContext)
+ metas := repo.ComposeCommentMetas(db.DefaultContext)
assert.Equal(t, "testRepo", metas["repo"])
assert.Equal(t, "testOwner", metas["user"])
@@ -100,7 +100,7 @@ func TestMetas(t *testing.T) {
testSuccess := func(expectedStyle string) {
repo.Units = []*RepoUnit{&externalTracker}
repo.commonRenderingMetas = nil
- metas := repo.ComposeMetas(db.DefaultContext)
+ metas := repo.ComposeCommentMetas(db.DefaultContext)
assert.Equal(t, expectedStyle, metas["style"])
assert.Equal(t, "testRepo", metas["repo"])
assert.Equal(t, "testOwner", metas["user"])
@@ -121,7 +121,7 @@ func TestMetas(t *testing.T) {
repo, err := GetRepositoryByID(db.DefaultContext, 3)
assert.NoError(t, err)
- metas = repo.ComposeMetas(db.DefaultContext)
+ metas = repo.ComposeCommentMetas(db.DefaultContext)
assert.Contains(t, metas, "org")
assert.Contains(t, metas, "teams")
assert.Equal(t, "org3", metas["org"])
diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go
index c2b3389245..b28fa9824e 100644
--- a/modules/markup/markdown/goldmark.go
+++ b/modules/markup/markdown/goldmark.go
@@ -9,7 +9,6 @@ import (
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/internal"
- "code.gitea.io/gitea/modules/setting"
"github.com/yuin/goldmark/ast"
east "github.com/yuin/goldmark/extension/ast"
@@ -69,16 +68,8 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
g.transformList(ctx, v, rc)
case *ast.Text:
if v.SoftLineBreak() && !v.HardLineBreak() {
- // TODO: this was a quite unclear part, old code: `if metas["mode"] != "document" { use comment link break setting }`
- // many places render non-comment contents with no mode=document, then these contents also use comment's hard line break setting
- // especially in many tests.
- markdownLineBreakStyle := ctx.RenderOptions.Metas["markdownLineBreakStyle"]
- switch markdownLineBreakStyle {
- case "comment":
- v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInComments)
- case "document":
- v.SetHardLineBreak(setting.Markdown.EnableHardLineBreakInDocuments)
- }
+ newLineHardBreak := ctx.RenderOptions.Metas["markdownNewLineHardBreak"] == "true"
+ v.SetHardLineBreak(newLineHardBreak)
}
case *ast.CodeSpan:
g.transformCodeSpan(ctx, v, reader)
diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go
index b102fdac7d..0d7180c6b1 100644
--- a/modules/markup/markdown/markdown.go
+++ b/modules/markup/markdown/markdown.go
@@ -126,11 +126,11 @@ func SpecializedMarkdown(ctx *markup.RenderContext) *GlodmarkRender {
highlighting.WithWrapperRenderer(r.highlightingRenderer),
),
math.NewExtension(&ctx.RenderInternal, math.Options{
- Enabled: setting.Markdown.EnableMath,
- ParseDollarInline: true,
- ParseDollarBlock: true,
- ParseSquareBlock: true, // TODO: this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping, it should be deprecated in the future (by some config options)
- // ParseBracketInline: true, // TODO: this is also a bad syntax "\( ... \)", it also conflicts, it should be deprecated in the future
+ Enabled: setting.Markdown.EnableMath,
+ ParseInlineDollar: setting.Markdown.MathCodeBlockOptions.ParseInlineDollar,
+ ParseInlineParentheses: setting.Markdown.MathCodeBlockOptions.ParseInlineParentheses, // this is a bad syntax "\( ... \)", it conflicts with normal markdown escaping
+ ParseBlockDollar: setting.Markdown.MathCodeBlockOptions.ParseBlockDollar,
+ ParseBlockSquareBrackets: setting.Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets, // this is a bad syntax "\[ ... \]", it conflicts with normal markdown escaping
}),
meta.Meta,
),
diff --git a/modules/markup/markdown/markdown_math_test.go b/modules/markup/markdown/markdown_math_test.go
index 813f050965..a75f18d36a 100644
--- a/modules/markup/markdown/markdown_math_test.go
+++ b/modules/markup/markdown/markdown_math_test.go
@@ -8,6 +8,8 @@ import (
"testing"
"code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
"github.com/stretchr/testify/assert"
)
@@ -15,6 +17,7 @@ import (
const nl = "\n"
func TestMathRender(t *testing.T) {
+ setting.Markdown.MathCodeBlockOptions = setting.MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseInlineParentheses: true}
testcases := []struct {
testcase string
expected string
@@ -69,7 +72,7 @@ func TestMathRender(t *testing.T) {
},
{
"$$a$$",
- `a
` + nl,
+ `
a
a
$a$
`, `$a$`) + setting.Markdown.MathCodeBlockOptions.ParseInlineDollar = true + test(t, `a
(a)
`, `\(a\)`) + setting.Markdown.MathCodeBlockOptions.ParseInlineParentheses = true + test(t, `a
$$ +a +$$
+`, ` +$$ +a +$$ +`) + setting.Markdown.MathCodeBlockOptions.ParseBlockDollar = true + test(t, `
+a
+
+`, `
+$$
+a
+$$
+`)
+
+ // ParseBlockSquareBrackets
+ test(t, `[ +a +]
+`, ` +\[ +a +\] +`) + setting.Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets = true + test(t, `
+a
+
+`, `
+\[
+a
+\]
+`)
+}
diff --git a/modules/markup/markdown/math/inline_parser.go b/modules/markup/markdown/math/inline_parser.go
index d24fd50955..a711d1e1cd 100644
--- a/modules/markup/markdown/math/inline_parser.go
+++ b/modules/markup/markdown/math/inline_parser.go
@@ -15,26 +15,26 @@ type inlineParser struct {
trigger []byte
endBytesSingleDollar []byte
endBytesDoubleDollar []byte
- endBytesBracket []byte
+ endBytesParentheses []byte
+ enableInlineDollar bool
}
-var defaultInlineDollarParser = &inlineParser{
- trigger: []byte{'$'},
- endBytesSingleDollar: []byte{'$'},
- endBytesDoubleDollar: []byte{'$', '$'},
+func NewInlineDollarParser(enableInlineDollar bool) parser.InlineParser {
+ return &inlineParser{
+ trigger: []byte{'$'},
+ endBytesSingleDollar: []byte{'$'},
+ endBytesDoubleDollar: []byte{'$', '$'},
+ enableInlineDollar: enableInlineDollar,
+ }
}
-func NewInlineDollarParser() parser.InlineParser {
- return defaultInlineDollarParser
+var defaultInlineParenthesesParser = &inlineParser{
+ trigger: []byte{'\\', '('},
+ endBytesParentheses: []byte{'\\', ')'},
}
-var defaultInlineBracketParser = &inlineParser{
- trigger: []byte{'\\', '('},
- endBytesBracket: []byte{'\\', ')'},
-}
-
-func NewInlineBracketParser() parser.InlineParser {
- return defaultInlineBracketParser
+func NewInlineParenthesesParser() parser.InlineParser {
+ return defaultInlineParenthesesParser
}
// Trigger triggers this parser on $ or \
@@ -46,7 +46,7 @@ func isPunctuation(b byte) bool {
return b == '.' || b == '!' || b == '?' || b == ',' || b == ';' || b == ':'
}
-func isBracket(b byte) bool {
+func isParenthesesClose(b byte) bool {
return b == ')'
}
@@ -86,7 +86,11 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
}
} else {
startMarkLen = 2
- stopMark = parser.endBytesBracket
+ stopMark = parser.endBytesParentheses
+ }
+
+ if line[0] == '$' && !parser.enableInlineDollar && (len(line) == 1 || line[1] != '`') {
+ return nil
}
if checkSurrounding {
@@ -110,7 +114,7 @@ func (parser *inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.
succeedingCharacter = line[i+len(stopMark)]
}
// check valid ending character
- isValidEndingChar := isPunctuation(succeedingCharacter) || isBracket(succeedingCharacter) ||
+ isValidEndingChar := isPunctuation(succeedingCharacter) || isParenthesesClose(succeedingCharacter) ||
succeedingCharacter == ' ' || succeedingCharacter == '\n' || succeedingCharacter == 0
if checkSurrounding && !isValidEndingChar {
break
diff --git a/modules/markup/markdown/math/math.go b/modules/markup/markdown/math/math.go
index a6ff593d62..4b74db2d76 100644
--- a/modules/markup/markdown/math/math.go
+++ b/modules/markup/markdown/math/math.go
@@ -14,10 +14,11 @@ import (
)
type Options struct {
- Enabled bool
- ParseDollarInline bool
- ParseDollarBlock bool
- ParseSquareBlock bool
+ Enabled bool
+ ParseInlineDollar bool // inline $$ xxx $$ text
+ ParseInlineParentheses bool // inline \( xxx \) text
+ ParseBlockDollar bool // block $$ multiple-line $$ text
+ ParseBlockSquareBrackets bool // block \[ multiple-line \] text
}
// Extension is a math extension
@@ -42,16 +43,16 @@ func (e *Extension) Extend(m goldmark.Markdown) {
return
}
- inlines := []util.PrioritizedValue{util.Prioritized(NewInlineBracketParser(), 501)}
- if e.options.ParseDollarInline {
- inlines = append(inlines, util.Prioritized(NewInlineDollarParser(), 502))
+ var inlines []util.PrioritizedValue
+ if e.options.ParseInlineParentheses {
+ inlines = append(inlines, util.Prioritized(NewInlineParenthesesParser(), 501))
}
+ inlines = append(inlines, util.Prioritized(NewInlineDollarParser(e.options.ParseInlineDollar), 502))
+
m.Parser().AddOptions(parser.WithInlineParsers(inlines...))
-
m.Parser().AddOptions(parser.WithBlockParsers(
- util.Prioritized(NewBlockParser(e.options.ParseDollarBlock, e.options.ParseSquareBlock), 701),
+ util.Prioritized(NewBlockParser(e.options.ParseBlockDollar, e.options.ParseBlockSquareBrackets), 701),
))
-
m.Renderer().AddOptions(renderer.WithNodeRenderers(
util.Prioritized(NewBlockRenderer(e.renderInternal), 501),
util.Prioritized(NewInlineRenderer(e.renderInternal), 502),
diff --git a/modules/markup/render.go b/modules/markup/render.go
index eb621b30a7..79f1f473c2 100644
--- a/modules/markup/render.go
+++ b/modules/markup/render.go
@@ -8,6 +8,7 @@ import (
"fmt"
"io"
"net/url"
+ "strconv"
"strings"
"time"
@@ -46,7 +47,7 @@ type RenderOptions struct {
// user&repo, format&style®exp (for external issue pattern), teams&org (for mention)
// RefTypeNameSubURL (for iframe&asciicast)
// markupAllowShortIssuePattern
- // markdownLineBreakStyle (comment, document)
+ // markdownNewLineHardBreak
Metas map[string]string
// used by external render. the router "/org/repo/render/..." will output the rendered content in a standalone page
@@ -247,7 +248,8 @@ func Init(renderHelpFuncs *RenderHelperFuncs) {
}
func ComposeSimpleDocumentMetas() map[string]string {
- return map[string]string{"markdownLineBreakStyle": "document"}
+ // TODO: there is no separate config option for "simple document" rendering, so temporarily use the same config as "repo file"
+ return map[string]string{"markdownNewLineHardBreak": strconv.FormatBool(setting.Markdown.RenderOptionsRepoFile.NewLineHardBreak)}
}
type TestRenderHelper struct {
diff --git a/modules/setting/markup.go b/modules/setting/markup.go
index dfce8afa77..3bd368f831 100644
--- a/modules/setting/markup.go
+++ b/modules/setting/markup.go
@@ -8,6 +8,7 @@ import (
"strings"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/util"
)
// ExternalMarkupRenderers represents the external markup renderers
@@ -23,18 +24,33 @@ const (
RenderContentModeIframe = "iframe"
)
+type MarkdownRenderOptions struct {
+ NewLineHardBreak bool
+ ShortIssuePattern bool // Actually it is a "markup" option because it is used in "post processor"
+}
+
+type MarkdownMathCodeBlockOptions struct {
+ ParseInlineDollar bool
+ ParseInlineParentheses bool
+ ParseBlockDollar bool
+ ParseBlockSquareBrackets bool
+}
+
// Markdown settings
var Markdown = struct {
- EnableHardLineBreakInComments bool
- EnableHardLineBreakInDocuments bool
- CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"`
- FileExtensions []string
- EnableMath bool
+ RenderOptionsComment MarkdownRenderOptions `ini:"-"`
+ RenderOptionsWiki MarkdownRenderOptions `ini:"-"`
+ RenderOptionsRepoFile MarkdownRenderOptions `ini:"-"`
+
+ CustomURLSchemes []string `ini:"CUSTOM_URL_SCHEMES"` // Actually it is a "markup" option because it is used in "post processor"
+ FileExtensions []string
+
+ EnableMath bool
+ MathCodeBlockDetection []string
+ MathCodeBlockOptions MarkdownMathCodeBlockOptions `ini:"-"`
}{
- EnableHardLineBreakInComments: true,
- EnableHardLineBreakInDocuments: false,
- FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd,.livemd", ","),
- EnableMath: true,
+ FileExtensions: strings.Split(".md,.markdown,.mdown,.mkd,.livemd", ","),
+ EnableMath: true,
}
// MarkupRenderer defines the external parser configured in ini
@@ -60,6 +76,56 @@ type MarkupSanitizerRule struct {
func loadMarkupFrom(rootCfg ConfigProvider) {
mustMapSetting(rootCfg, "markdown", &Markdown)
+ const none = "none"
+
+ const renderOptionShortIssuePattern = "short-issue-pattern"
+ const renderOptionNewLineHardBreak = "new-line-hard-break"
+ cfgMarkdown := rootCfg.Section("markdown")
+ parseMarkdownRenderOptions := func(key string, defaults []string) (ret MarkdownRenderOptions) {
+ options := cfgMarkdown.Key(key).Strings(",")
+ options = util.IfEmpty(options, defaults)
+ for _, opt := range options {
+ switch opt {
+ case renderOptionShortIssuePattern:
+ ret.ShortIssuePattern = true
+ case renderOptionNewLineHardBreak:
+ ret.NewLineHardBreak = true
+ case none:
+ ret = MarkdownRenderOptions{}
+ case "":
+ default:
+ log.Error("Unknown markdown render option in %s: %s", key, opt)
+ }
+ }
+ return ret
+ }
+ Markdown.RenderOptionsComment = parseMarkdownRenderOptions("RENDER_OPTIONS_COMMENT", []string{renderOptionShortIssuePattern, renderOptionNewLineHardBreak})
+ Markdown.RenderOptionsWiki = parseMarkdownRenderOptions("RENDER_OPTIONS_WIKI", []string{renderOptionShortIssuePattern})
+ Markdown.RenderOptionsRepoFile = parseMarkdownRenderOptions("RENDER_OPTIONS_REPO_FILE", nil)
+
+ const mathCodeInlineDollar = "inline-dollar"
+ const mathCodeInlineParentheses = "inline-parentheses"
+ const mathCodeBlockDollar = "block-dollar"
+ const mathCodeBlockSquareBrackets = "block-square-brackets"
+ Markdown.MathCodeBlockDetection = util.IfEmpty(Markdown.MathCodeBlockDetection, []string{mathCodeInlineDollar, mathCodeBlockDollar})
+ Markdown.MathCodeBlockOptions = MarkdownMathCodeBlockOptions{}
+ for _, s := range Markdown.MathCodeBlockDetection {
+ switch s {
+ case mathCodeInlineDollar:
+ Markdown.MathCodeBlockOptions.ParseInlineDollar = true
+ case mathCodeInlineParentheses:
+ Markdown.MathCodeBlockOptions.ParseInlineParentheses = true
+ case mathCodeBlockDollar:
+ Markdown.MathCodeBlockOptions.ParseBlockDollar = true
+ case mathCodeBlockSquareBrackets:
+ Markdown.MathCodeBlockOptions.ParseBlockSquareBrackets = true
+ case none:
+ Markdown.MathCodeBlockOptions = MarkdownMathCodeBlockOptions{}
+ case "":
+ default:
+ log.Error("Unknown math code block detection option: %s", s)
+ }
+ }
MermaidMaxSourceCharacters = rootCfg.Section("markup").Key("MERMAID_MAX_SOURCE_CHARACTERS").MustInt(5000)
ExternalMarkupRenderers = make([]*MarkupRenderer, 0, 10)
diff --git a/modules/setting/markup_test.go b/modules/setting/markup_test.go
new file mode 100644
index 0000000000..c47a38ce15
--- /dev/null
+++ b/modules/setting/markup_test.go
@@ -0,0 +1,51 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLoadMarkup(t *testing.T) {
+ cfg, _ := NewConfigProviderFromData(``)
+ loadMarkupFrom(cfg)
+ assert.Equal(t, MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseBlockDollar: true}, Markdown.MathCodeBlockOptions)
+ assert.Equal(t, MarkdownRenderOptions{NewLineHardBreak: true, ShortIssuePattern: true}, Markdown.RenderOptionsComment)
+ assert.Equal(t, MarkdownRenderOptions{ShortIssuePattern: true}, Markdown.RenderOptionsWiki)
+ assert.Equal(t, MarkdownRenderOptions{}, Markdown.RenderOptionsRepoFile)
+
+ t.Run("Math", func(t *testing.T) {
+ cfg, _ = NewConfigProviderFromData(`
+[markdown]
+MATH_CODE_BLOCK_DETECTION = none
+`)
+ loadMarkupFrom(cfg)
+ assert.Equal(t, MarkdownMathCodeBlockOptions{}, Markdown.MathCodeBlockOptions)
+
+ cfg, _ = NewConfigProviderFromData(`
+[markdown]
+MATH_CODE_BLOCK_DETECTION = inline-dollar, inline-parentheses, block-dollar, block-square-brackets
+`)
+ loadMarkupFrom(cfg)
+ assert.Equal(t, MarkdownMathCodeBlockOptions{ParseInlineDollar: true, ParseInlineParentheses: true, ParseBlockDollar: true, ParseBlockSquareBrackets: true}, Markdown.MathCodeBlockOptions)
+ })
+
+ t.Run("Render", func(t *testing.T) {
+ cfg, _ = NewConfigProviderFromData(`
+[markdown]
+RENDER_OPTIONS_COMMENT = none
+`)
+ loadMarkupFrom(cfg)
+ assert.Equal(t, MarkdownRenderOptions{}, Markdown.RenderOptionsComment)
+
+ cfg, _ = NewConfigProviderFromData(`
+[markdown]
+RENDER_OPTIONS_REPO_FILE = short-issue-pattern, new-line-hard-break
+`)
+ loadMarkupFrom(cfg)
+ assert.Equal(t, MarkdownRenderOptions{NewLineHardBreak: true, ShortIssuePattern: true}, Markdown.RenderOptionsRepoFile)
+ })
+}
diff --git a/modules/templates/util_render_test.go b/modules/templates/util_render_test.go
index 7b53fdb1e2..26cd1eb348 100644
--- a/modules/templates/util_render_test.go
+++ b/modules/templates/util_render_test.go
@@ -51,7 +51,7 @@ var testMetas = map[string]string{
"user": "user13",
"repo": "repo11",
"repoPath": "../../tests/gitea-repositories-meta/user13/repo11.git/",
- "markdownLineBreakStyle": "comment",
+ "markdownNewLineHardBreak": "true",
"markupAllowShortIssuePattern": "true",
}
diff --git a/modules/util/util.go b/modules/util/util.go
index 72fcddbe13..dd8e073888 100644
--- a/modules/util/util.go
+++ b/modules/util/util.go
@@ -219,6 +219,13 @@ func IfZero[T comparable](v, def T) T {
return v
}
+func IfEmpty[T any](v, def []T) []T {
+ if len(v) == 0 {
+ return def
+ }
+ return v
+}
+
// OptionalArg helps the "optional argument" in Golang:
//
// func foo(optArg ...int) { return OptionalArg(optArg) }
diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go
index ec06c9233a..2ec6389263 100644
--- a/routers/web/repo/actions/view.go
+++ b/routers/web/repo/actions/view.go
@@ -200,9 +200,9 @@ func ViewPost(ctx *context_module.Context) {
}
}
- // TODO: "ComposeMetas" (usually for comment) is not quite right, but it is still the same as what template "RenderCommitMessage" does.
+ // TODO: "ComposeCommentMetas" (usually for comment) is not quite right, but it is still the same as what template "RenderCommitMessage" does.
// need to be refactored together in the future
- metas := ctx.Repo.Repository.ComposeMetas(ctx)
+ metas := ctx.Repo.Repository.ComposeCommentMetas(ctx)
// the title for the "run" is from the commit message
resp.State.Run.Title = run.Title
diff --git a/routers/web/repo/issue_view.go b/routers/web/repo/issue_view.go
index b312f1260a..3ffcdfe676 100644
--- a/routers/web/repo/issue_view.go
+++ b/routers/web/repo/issue_view.go
@@ -278,7 +278,7 @@ func ViewIssue(ctx *context.Context) {
extIssueUnit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker)
if err == nil && extIssueUnit != nil {
if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" {
- metas := ctx.Repo.Repository.ComposeMetas(ctx)
+ metas := ctx.Repo.Repository.ComposeCommentMetas(ctx)
metas["index"] = ctx.PathParam("index")
res, err := vars.Expand(extIssueUnit.ExternalTrackerConfig().ExternalTrackerFormat, metas)
if err != nil {
diff --git a/routers/web/repo/view_file.go b/routers/web/repo/view_file.go
index 3edba8e06e..12083a1ced 100644
--- a/routers/web/repo/view_file.go
+++ b/routers/web/repo/view_file.go
@@ -176,7 +176,7 @@ func prepareToRenderFile(ctx *context.Context, entry *git.TreeEntry) {
if markupType != "" && !shouldRenderSource {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
- metas := ctx.Repo.Repository.ComposeDocumentMetas(ctx)
+ metas := ctx.Repo.Repository.ComposeRepoFileMetas(ctx)
metas["RefTypeNameSubURL"] = ctx.Repo.RefTypeNameSubURL()
rctx := renderhelper.NewRenderContextRepoFile(ctx, ctx.Repo.Repository, renderhelper.RepoFileOptions{
CurrentRefPath: ctx.Repo.RefTypeNameSubURL(),
diff --git a/templates/repo/branch/list.tmpl b/templates/repo/branch/list.tmpl
index c0accf16fa..19797229bf 100644
--- a/templates/repo/branch/list.tmpl
+++ b/templates/repo/branch/list.tmpl
@@ -27,7 +27,7 @@
{{template "repo/commit_statuses" dict "Status" (index $.CommitStatus .DefaultBranchBranch.DBBranch.CommitID) "Statuses" (index $.CommitStatuses .DefaultBranchBranch.DBBranch.CommitID)}}
- {{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime}}{{if .DefaultBranchBranch.DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}
+{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DefaultBranchBranch.DBBranch.CommitID}} · · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DefaultBranchBranch.DBBranch.CommitTime}}{{if .DefaultBranchBranch.DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "user" .DefaultBranchBranch.DBBranch.Pusher}}{{template "shared/user/namelink" .DefaultBranchBranch.DBBranch.Pusher}}{{end}}
{{/* FIXME: here and below, the tw-overflow-visible is not quite right but it is still needed the moment: to show the important buttons when the width is narrow */}}{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DBBranch.CommitTime}}{{if .DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}
+{{svg "octicon-git-commit" 16 "tw-mr-1"}}{{ShortSha .DBBranch.CommitID}} · · {{ctx.Locale.Tr "org.repo_updated"}} {{DateUtils.TimeSince .DBBranch.CommitTime}}{{if .DBBranch.Pusher}} {{template "shared/user/avatarlink" dict "user" .DBBranch.Pusher}} {{template "shared/user/namelink" .DBBranch.Pusher}}{{end}}
{{end}}{{ctx.RenderUtils.RenderCommitBody .Commit.Message ($.Repository.ComposeMetas ctx)}}+
{{ctx.RenderUtils.RenderCommitBody .Commit.Message ($.Repository.ComposeCommentMetas ctx)}}{{end}} {{template "repo/commit_load_branches_and_tags" .}}
{{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeMetas ctx)}}+
{{ctx.RenderUtils.RenderCommitBody .Message ($.Repository.ComposeCommentMetas ctx)}}{{end}} {{if $.CommitsTagsMap}} {{range (index $.CommitsTagsMap .ID.String)}} diff --git a/templates/repo/commits_list_small.tmpl b/templates/repo/commits_list_small.tmpl index 2acf7c58b8..b054ce19a5 100644 --- a/templates/repo/commits_list_small.tmpl +++ b/templates/repo/commits_list_small.tmpl @@ -15,7 +15,7 @@ {{$commitLink:= printf "%s/%s" $commitBaseLink (PathEscape .ID.String)}} - {{- ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} + {{- ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink ($.comment.Issue.PullRequest.BaseRepo.ComposeCommentMetas ctx) -}} {{if IsMultilineCommitMessage .Message}} @@ -29,7 +29,7 @@
- {{- ctx.RenderUtils.RenderCommitBody .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeMetas ctx) -}} + {{- ctx.RenderUtils.RenderCommitBody .Message ($.comment.Issue.PullRequest.BaseRepo.ComposeCommentMetas ctx) -}}{{end}} {{end}} diff --git a/templates/repo/diff/compare.tmpl b/templates/repo/diff/compare.tmpl index 05cfffd2b7..0c9e3f0698 100644 --- a/templates/repo/diff/compare.tmpl +++ b/templates/repo/diff/compare.tmpl @@ -189,7 +189,7 @@