Skip to content

Commit 46e0597

Browse files
committed
Merge remote-tracking branch 'upstream/main'
* upstream/main: Display image digest for container packages (go-gitea#21170) Use correct branch for .editorconfig error (go-gitea#21152) Passing command line arguments correctly by string slice (go-gitea#21168) Sort branches and tags by date descending (go-gitea#21136) Skip dirty check for team forms (go-gitea#21154) Add KaTeX rendering to Markdown. (go-gitea#20571)
2 parents 3569321 + ef40324 commit 46e0597

36 files changed

+1101
-195
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,9 @@ ROUTER = console
12621262
;; List of file extensions that should be rendered/edited as Markdown
12631263
;; Separate the extensions with a comma. To render files without any extension as markdown, just put a comma
12641264
;FILE_EXTENSIONS = .md,.markdown,.mdown,.mkd
1265+
;;
1266+
;; Enables math inline and block detection
1267+
;ENABLE_MATH = true
12651268

12661269
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12671270
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
236236
- `CUSTOM_URL_SCHEMES`: Use a comma separated list (ftp,git,svn) to indicate additional
237237
URL hyperlinks to be rendered in Markdown. URLs beginning in http and https are
238238
always displayed
239+
- `ENABLE_MATH`: **true**: Enables detection of `\(...\)`, `\[...\]`, `$...$` and `$$...$$` blocks as math blocks.
239240

240241
## Server (`server`)
241242

docs/content/doc/advanced/external-renderers.en-us.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,13 @@ RENDER_COMMAND = "timeout 30s pandoc +RTS -M512M -RTS -f rst"
7474
IS_INPUT_FILE = false
7575
```
7676

77-
If your external markup relies on additional classes and attributes on the generated HTML elements, you might need to enable custom sanitizer policies. Gitea uses the [`bluemonday`](https://godoc.org/github.com/microcosm-cc/bluemonday) package as our HTML sanitizier. The example below will support [KaTeX](https://katex.org/) output from [`pandoc`](https://pandoc.org/).
77+
If your external markup relies on additional classes and attributes on the generated HTML elements, you might need to enable custom sanitizer policies. Gitea uses the [`bluemonday`](https://godoc.org/github.com/microcosm-cc/bluemonday) package as our HTML sanitizer. The example below could be used to support server-side [KaTeX](https://katex.org/) rendering output from [`pandoc`](https://pandoc.org/).
7878

7979
```ini
8080
[markup.sanitizer.TeX]
8181
; Pandoc renders TeX segments as <span>s with the "math" class, optionally
8282
; with "inline" or "display" classes depending on context.
83+
; - note this is different from the built-in math support in our markdown parser which uses <code>
8384
ELEMENT = span
8485
ALLOW_ATTR = class
8586
REGEXP = ^\s*((math(\s+|$)|inline(\s+|$)|display(\s+|$)))+

docs/content/doc/features/comparison.en-us.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ _Symbols used in table:_
5353
| WebAuthn (2FA) ||||||| ? |
5454
| Built-in CI/CD ||||||||
5555
| Subgroups: groups within groups | [](https://github.com/go-gitea/gitea/issues/1872) |||||||
56+
| Mermaid diagrams in Markdown ||||||||
57+
| Math syntax in Markdown ||||||||
5658

5759
## Code management
5860

docs/content/page/index.en-us.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ You can try it out using [the online demo](https://try.gitea.io/).
131131
- Environment variables
132132
- Command line options
133133
- Multi-language support ([21 languages](https://github.com/go-gitea/gitea/tree/main/options/locale))
134-
- [Mermaid](https://mermaidjs.github.io/) Diagram support
134+
- [Mermaid](https://mermaidjs.github.io/) diagrams in Markdown
135+
- Math syntax in Markdown
135136
- Mail service
136137
- Notifications
137138
- Registration confirmation

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ require (
103103
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
104104
gopkg.in/ini.v1 v1.67.0
105105
gopkg.in/yaml.v2 v2.4.0
106+
gopkg.in/yaml.v3 v3.0.1
106107
mvdan.cc/xurls/v2 v2.4.0
107108
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
108109
xorm.io/builder v0.3.11
@@ -290,7 +291,6 @@ require (
290291
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
291292
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
292293
gopkg.in/warnings.v0 v0.1.2 // indirect
293-
gopkg.in/yaml.v3 v3.0.1 // indirect
294294
sigs.k8s.io/yaml v1.2.0 // indirect
295295
)
296296

modules/git/repo_branch_nogogit.go

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -63,42 +63,40 @@ func (repo *Repository) IsBranchExist(name string) bool {
6363
// GetBranchNames returns branches from the repository, skipping skip initial branches and
6464
// returning at most limit branches, or all branches if limit is 0.
6565
func (repo *Repository) GetBranchNames(skip, limit int) ([]string, int, error) {
66-
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, "--heads", skip, limit)
66+
return callShowRef(repo.Ctx, repo.Path, BranchPrefix, []string{BranchPrefix, "--sort=-committerdate"}, skip, limit)
6767
}
6868

6969
// WalkReferences walks all the references from the repository
7070
func WalkReferences(ctx context.Context, repoPath string, walkfn func(sha1, refname string) error) (int, error) {
71-
return walkShowRef(ctx, repoPath, "", 0, 0, walkfn)
71+
return walkShowRef(ctx, repoPath, nil, 0, 0, walkfn)
7272
}
7373

7474
// WalkReferences walks all the references from the repository
7575
// refType should be empty, ObjectTag or ObjectBranch. All other values are equivalent to empty.
7676
func (repo *Repository) WalkReferences(refType ObjectType, skip, limit int, walkfn func(sha1, refname string) error) (int, error) {
77-
var arg string
77+
var args []string
7878
switch refType {
7979
case ObjectTag:
80-
arg = "--tags"
80+
args = []string{TagPrefix, "--sort=-taggerdate"}
8181
case ObjectBranch:
82-
arg = "--heads"
83-
default:
84-
arg = ""
82+
args = []string{BranchPrefix, "--sort=-committerdate"}
8583
}
8684

87-
return walkShowRef(repo.Ctx, repo.Path, arg, skip, limit, walkfn)
85+
return walkShowRef(repo.Ctx, repo.Path, args, skip, limit, walkfn)
8886
}
8987

9088
// callShowRef return refs, if limit = 0 it will not limit
91-
func callShowRef(ctx context.Context, repoPath, prefix, arg string, skip, limit int) (branchNames []string, countAll int, err error) {
92-
countAll, err = walkShowRef(ctx, repoPath, arg, skip, limit, func(_, branchName string) error {
93-
branchName = strings.TrimPrefix(branchName, prefix)
89+
func callShowRef(ctx context.Context, repoPath, trimPrefix string, extraArgs []string, skip, limit int) (branchNames []string, countAll int, err error) {
90+
countAll, err = walkShowRef(ctx, repoPath, extraArgs, skip, limit, func(_, branchName string) error {
91+
branchName = strings.TrimPrefix(branchName, trimPrefix)
9492
branchNames = append(branchNames, branchName)
9593

9694
return nil
9795
})
9896
return branchNames, countAll, err
9997
}
10098

101-
func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
99+
func walkShowRef(ctx context.Context, repoPath string, extraArgs []string, skip, limit int, walkfn func(sha1, refname string) error) (countAll int, err error) {
102100
stdoutReader, stdoutWriter := io.Pipe()
103101
defer func() {
104102
_ = stdoutReader.Close()
@@ -107,10 +105,8 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
107105

108106
go func() {
109107
stderrBuilder := &strings.Builder{}
110-
args := []string{"show-ref"}
111-
if arg != "" {
112-
args = append(args, arg)
113-
}
108+
args := []string{"for-each-ref", "--format=%(objectname) %(refname)"}
109+
args = append(args, extraArgs...)
114110
err := NewCommand(ctx, args...).Run(&RunOpts{
115111
Dir: repoPath,
116112
Stdout: stdoutWriter,
@@ -194,7 +190,7 @@ func walkShowRef(ctx context.Context, repoPath, arg string, skip, limit int, wal
194190
// GetRefsBySha returns all references filtered with prefix that belong to a sha commit hash
195191
func (repo *Repository) GetRefsBySha(sha, prefix string) ([]string, error) {
196192
var revList []string
197-
_, err := walkShowRef(repo.Ctx, repo.Path, "", 0, 0, func(walkSha, refname string) error {
193+
_, err := walkShowRef(repo.Ctx, repo.Path, nil, 0, 0, func(walkSha, refname string) error {
198194
if walkSha == sha && strings.HasPrefix(refname, prefix) {
199195
revList = append(revList, refname)
200196
}

modules/git/repo_branch_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ func TestRepository_GetBranches(t *testing.T) {
2222
assert.NoError(t, err)
2323
assert.Len(t, branches, 2)
2424
assert.EqualValues(t, 3, countAll)
25-
assert.ElementsMatch(t, []string{"branch1", "branch2"}, branches)
25+
assert.ElementsMatch(t, []string{"master", "branch2"}, branches)
2626

2727
branches, countAll, err = bareRepo1.GetBranchNames(0, 0)
2828

2929
assert.NoError(t, err)
3030
assert.Len(t, branches, 3)
3131
assert.EqualValues(t, 3, countAll)
32-
assert.ElementsMatch(t, []string{"branch1", "branch2", "master"}, branches)
32+
assert.ElementsMatch(t, []string{"master", "branch2", "branch1"}, branches)
3333

3434
branches, countAll, err = bareRepo1.GetBranchNames(5, 1)
3535

modules/git/repo_tag_nogogit.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (repo *Repository) IsTagExist(name string) bool {
2626
// GetTags returns all tags of the repository.
2727
// returning at most limit tags, or all if limit is 0.
2828
func (repo *Repository) GetTags(skip, limit int) (tags []string, err error) {
29-
tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, "--tags", skip, limit)
29+
tags, _, err = callShowRef(repo.Ctx, repo.Path, TagPrefix, []string{TagPrefix, "--sort=-taggerdate"}, skip, limit)
3030
return tags, err
3131
}
3232

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package markdown
6+
7+
import (
8+
"github.com/yuin/goldmark/ast"
9+
east "github.com/yuin/goldmark/extension/ast"
10+
"gopkg.in/yaml.v3"
11+
)
12+
13+
func nodeToTable(meta *yaml.Node) ast.Node {
14+
for {
15+
if meta == nil {
16+
return nil
17+
}
18+
switch meta.Kind {
19+
case yaml.DocumentNode:
20+
meta = meta.Content[0]
21+
continue
22+
default:
23+
}
24+
break
25+
}
26+
switch meta.Kind {
27+
case yaml.MappingNode:
28+
return mappingNodeToTable(meta)
29+
case yaml.SequenceNode:
30+
return sequenceNodeToTable(meta)
31+
default:
32+
return ast.NewString([]byte(meta.Value))
33+
}
34+
}
35+
36+
func mappingNodeToTable(meta *yaml.Node) ast.Node {
37+
table := east.NewTable()
38+
alignments := []east.Alignment{}
39+
for i := 0; i < len(meta.Content); i += 2 {
40+
alignments = append(alignments, east.AlignNone)
41+
}
42+
43+
headerRow := east.NewTableRow(alignments)
44+
valueRow := east.NewTableRow(alignments)
45+
for i := 0; i < len(meta.Content); i += 2 {
46+
cell := east.NewTableCell()
47+
48+
cell.AppendChild(cell, nodeToTable(meta.Content[i]))
49+
headerRow.AppendChild(headerRow, cell)
50+
51+
if i+1 < len(meta.Content) {
52+
cell = east.NewTableCell()
53+
cell.AppendChild(cell, nodeToTable(meta.Content[i+1]))
54+
valueRow.AppendChild(valueRow, cell)
55+
}
56+
}
57+
58+
table.AppendChild(table, east.NewTableHeader(headerRow))
59+
table.AppendChild(table, valueRow)
60+
return table
61+
}
62+
63+
func sequenceNodeToTable(meta *yaml.Node) ast.Node {
64+
table := east.NewTable()
65+
alignments := []east.Alignment{east.AlignNone}
66+
for _, item := range meta.Content {
67+
row := east.NewTableRow(alignments)
68+
cell := east.NewTableCell()
69+
cell.AppendChild(cell, nodeToTable(item))
70+
row.AppendChild(row, cell)
71+
table.AppendChild(table, row)
72+
}
73+
return table
74+
}
75+
76+
func nodeToDetails(meta *yaml.Node, icon string) ast.Node {
77+
details := NewDetails()
78+
summary := NewSummary()
79+
summary.AppendChild(summary, NewIcon(icon))
80+
details.AppendChild(details, summary)
81+
details.AppendChild(details, nodeToTable(meta))
82+
83+
return details
84+
}

modules/markup/markdown/goldmark.go

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import (
1515
"code.gitea.io/gitea/modules/setting"
1616
giteautil "code.gitea.io/gitea/modules/util"
1717

18-
meta "github.com/yuin/goldmark-meta"
1918
"github.com/yuin/goldmark/ast"
2019
east "github.com/yuin/goldmark/extension/ast"
2120
"github.com/yuin/goldmark/parser"
@@ -32,20 +31,12 @@ type ASTTransformer struct{}
3231

3332
// Transform transforms the given AST tree.
3433
func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
35-
metaData := meta.GetItems(pc)
3634
firstChild := node.FirstChild()
3735
createTOC := false
3836
ctx := pc.Get(renderContextKey).(*markup.RenderContext)
39-
rc := &RenderConfig{
40-
Meta: "table",
41-
Icon: "table",
42-
Lang: "",
43-
}
44-
45-
if metaData != nil {
46-
rc.ToRenderConfig(metaData)
47-
48-
metaNode := rc.toMetaNode(metaData)
37+
rc := pc.Get(renderConfigKey).(*RenderConfig)
38+
if rc.yamlNode != nil {
39+
metaNode := rc.toMetaNode()
4940
if metaNode != nil {
5041
node.InsertBefore(node, firstChild, metaNode)
5142
}

modules/markup/markdown/markdown.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"code.gitea.io/gitea/modules/log"
1515
"code.gitea.io/gitea/modules/markup"
1616
"code.gitea.io/gitea/modules/markup/common"
17+
"code.gitea.io/gitea/modules/markup/markdown/math"
1718
"code.gitea.io/gitea/modules/setting"
1819
giteautil "code.gitea.io/gitea/modules/util"
1920

@@ -38,6 +39,7 @@ var (
3839
isWikiKey = parser.NewContextKey()
3940
renderMetasKey = parser.NewContextKey()
4041
renderContextKey = parser.NewContextKey()
42+
renderConfigKey = parser.NewContextKey()
4143
)
4244

4345
type limitWriter struct {
@@ -98,7 +100,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
98100
languageStr := string(language)
99101

100102
preClasses := []string{"code-block"}
101-
if languageStr == "mermaid" {
103+
if languageStr == "mermaid" || languageStr == "math" {
102104
preClasses = append(preClasses, "is-loading")
103105
}
104106

@@ -120,6 +122,9 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
120122
}
121123
}),
122124
),
125+
math.NewExtension(
126+
math.Enabled(setting.Markdown.EnableMath),
127+
),
123128
meta.Meta,
124129
),
125130
goldmark.WithParserOptions(
@@ -167,7 +172,18 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
167172
log.Error("Unable to ReadAll: %v", err)
168173
return err
169174
}
170-
if err := converter.Convert(giteautil.NormalizeEOL(buf), lw, parser.WithContext(pc)); err != nil {
175+
buf = giteautil.NormalizeEOL(buf)
176+
177+
rc := &RenderConfig{
178+
Meta: "table",
179+
Icon: "table",
180+
Lang: "",
181+
}
182+
buf, _ = ExtractMetadataBytes(buf, rc)
183+
184+
pc.Set(renderConfigKey, rc)
185+
186+
if err := converter.Convert(buf, lw, parser.WithContext(pc)); err != nil {
171187
log.Error("Unable to render: %v", err)
172188
return err
173189
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package math
6+
7+
import "github.com/yuin/goldmark/ast"
8+
9+
// Block represents a display math block e.g. $$...$$ or \[...\]
10+
type Block struct {
11+
ast.BaseBlock
12+
Dollars bool
13+
Indent int
14+
Closed bool
15+
}
16+
17+
// KindBlock is the node kind for math blocks
18+
var KindBlock = ast.NewNodeKind("MathBlock")
19+
20+
// NewBlock creates a new math Block
21+
func NewBlock(dollars bool, indent int) *Block {
22+
return &Block{
23+
Dollars: dollars,
24+
Indent: indent,
25+
}
26+
}
27+
28+
// Dump dumps the block to a string
29+
func (n *Block) Dump(source []byte, level int) {
30+
m := map[string]string{}
31+
ast.DumpHelper(n, source, level, m, nil)
32+
}
33+
34+
// Kind returns KindBlock for math Blocks
35+
func (n *Block) Kind() ast.NodeKind {
36+
return KindBlock
37+
}
38+
39+
// IsRaw returns true as this block should not be processed further
40+
func (n *Block) IsRaw() bool {
41+
return true
42+
}

0 commit comments

Comments
 (0)