Skip to content

Commit 97617ae

Browse files
committed
improve
1 parent 35e562d commit 97617ae

File tree

12 files changed

+127
-117
lines changed

12 files changed

+127
-117
lines changed

modules/markup/markdown/convertyaml.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func nodeToTable(meta *yaml.Node) ast.Node {
3434

3535
func mappingNodeToTable(meta *yaml.Node) ast.Node {
3636
table := east.NewTable()
37-
alignments := []east.Alignment{}
37+
var alignments []east.Alignment
3838
for i := 0; i < len(meta.Content); i += 2 {
3939
alignments = append(alignments, east.AlignNone)
4040
}

modules/markup/markdown/goldmark.go

+20-14
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,17 @@ type ASTTransformer struct{}
3434
// Transform transforms the given AST tree.
3535
func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
3636
firstChild := node.FirstChild()
37-
createTOC := false
37+
tocMode := ""
3838
ctx := pc.Get(renderContextKey).(*markup.RenderContext)
3939
rc := pc.Get(renderConfigKey).(*RenderConfig)
40+
41+
tocList := make([]markup.Header, 0, 20)
4042
if rc.yamlNode != nil {
4143
metaNode := rc.toMetaNode()
4244
if metaNode != nil {
4345
node.InsertBefore(node, firstChild, metaNode)
4446
}
45-
createTOC = rc.TOC
46-
ctx.TableOfContents = make([]markup.Header, 0, 100)
47+
tocMode = rc.TOC
4748
}
4849

4950
attentionMarkedBlockquotes := make(container.Set[*ast.Blockquote])
@@ -59,15 +60,15 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
5960
v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value)))
6061
}
6162
}
62-
text := n.Text(reader.Source())
63+
txt := n.Text(reader.Source())
6364
header := markup.Header{
64-
Text: util.BytesToReadOnlyString(text),
65+
Text: util.BytesToReadOnlyString(txt),
6566
Level: v.Level,
6667
}
6768
if id, found := v.AttributeString("id"); found {
6869
header.ID = util.BytesToReadOnlyString(id.([]byte))
6970
}
70-
ctx.TableOfContents = append(ctx.TableOfContents, header)
71+
tocList = append(tocList, header)
7172
case *ast.Image:
7273
// Images need two things:
7374
//
@@ -201,14 +202,15 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa
201202
return ast.WalkContinue, nil
202203
})
203204

204-
if createTOC && len(ctx.TableOfContents) > 0 {
205-
lang := rc.Lang
206-
if len(lang) == 0 {
207-
lang = setting.Langs[0]
208-
}
209-
tocNode := createTOCNode(ctx.TableOfContents, lang)
210-
if tocNode != nil {
205+
showTocInMain := tocMode == "true" /* old behavior, in main view */ || tocMode == "main"
206+
showTocInSidebar := !showTocInMain && tocMode != "false" // not hidden, not main, then show it in sidebar
207+
if len(tocList) > 0 && (showTocInMain || showTocInSidebar) {
208+
if showTocInMain {
209+
tocNode := createTOCNode(tocList, rc.Lang, nil)
211210
node.InsertBefore(node, firstChild, tocNode)
211+
} else {
212+
tocNode := createTOCNode(tocList, rc.Lang, map[string]string{"open": "open"})
213+
ctx.SidebarTocTree = tocNode
212214
}
213215
}
214216

@@ -373,7 +375,11 @@ func (r *HTMLRenderer) renderDocument(w util.BufWriter, source []byte, node ast.
373375
func (r *HTMLRenderer) renderDetails(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
374376
var err error
375377
if entering {
376-
_, err = w.WriteString("<details>")
378+
if _, err = w.WriteString("<details"); err != nil {
379+
return ast.WalkStop, err
380+
}
381+
html.RenderAttributes(w, node, nil)
382+
_, err = w.WriteString(">")
377383
} else {
378384
_, err = w.WriteString("</details>")
379385
}

modules/markup/markdown/markdown.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ import (
2929
)
3030

3131
var (
32-
converter goldmark.Markdown
33-
once = sync.Once{}
32+
specMarkdown goldmark.Markdown
33+
specMarkdownOnce sync.Once
3434
)
3535

3636
var (
@@ -56,7 +56,7 @@ func (l *limitWriter) Write(data []byte) (int, error) {
5656
if err != nil {
5757
return n, err
5858
}
59-
return n, fmt.Errorf("Rendered content too large - truncating render")
59+
return n, fmt.Errorf("rendered content too large - truncating render")
6060
}
6161
n, err := l.w.Write(data)
6262
l.sum += int64(n)
@@ -73,10 +73,9 @@ func newParserContext(ctx *markup.RenderContext) parser.Context {
7373
return pc
7474
}
7575

76-
// actualRender renders Markdown to HTML without handling special links.
77-
func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
78-
once.Do(func() {
79-
converter = goldmark.New(
76+
func SpecializedMarkdown() goldmark.Markdown {
77+
specMarkdownOnce.Do(func() {
78+
specMarkdown = goldmark.New(
8079
goldmark.WithExtensions(
8180
extension.NewTable(
8281
extension.WithTableCellAlignMethod(extension.TableCellAlignAttribute)),
@@ -139,13 +138,18 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
139138
)
140139

141140
// Override the original Tasklist renderer!
142-
converter.Renderer().AddOptions(
141+
specMarkdown.Renderer().AddOptions(
143142
renderer.WithNodeRenderers(
144143
util.Prioritized(NewHTMLRenderer(), 10),
145144
),
146145
)
147146
})
147+
return specMarkdown
148+
}
148149

150+
// actualRender renders Markdown to HTML without handling special links.
151+
func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
152+
converter := SpecializedMarkdown()
149153
lw := &limitWriter{
150154
w: output,
151155
limit: setting.UI.MaxDisplayFileSize * 3,
@@ -174,7 +178,7 @@ func actualRender(ctx *markup.RenderContext, input io.Reader, output io.Writer)
174178
buf = giteautil.NormalizeEOL(buf)
175179

176180
rc := &RenderConfig{
177-
Meta: "table",
181+
Meta: renderMetaModeFromString(string(ctx.RenderMetaAs)),
178182
Icon: "table",
179183
Lang: "",
180184
}

modules/markup/markdown/renderconfig.go

+38-41
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,42 @@ import (
77
"fmt"
88
"strings"
99

10+
"code.gitea.io/gitea/modules/markup"
11+
1012
"github.com/yuin/goldmark/ast"
1113
"gopkg.in/yaml.v3"
1214
)
1315

1416
// RenderConfig represents rendering configuration for this file
1517
type RenderConfig struct {
16-
Meta string
18+
Meta markup.RenderMetaMode
1719
Icon string
18-
TOC bool
20+
TOC string // "false": hide, "side"/empty: in sidebar, "main"/"true": in main view
1921
Lang string
2022
yamlNode *yaml.Node
2123
}
2224

25+
func renderMetaModeFromString(s string) markup.RenderMetaMode {
26+
switch strings.TrimSpace(strings.ToLower(s)) {
27+
case "none":
28+
return markup.RenderMetaAsNone
29+
case "table":
30+
return markup.RenderMetaAsTable
31+
default: // "details"
32+
return markup.RenderMetaAsDetails
33+
}
34+
}
35+
2336
// UnmarshalYAML implement yaml.v3 UnmarshalYAML
2437
func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
2538
if rc == nil {
26-
rc = &RenderConfig{
27-
Meta: "table",
28-
Icon: "table",
29-
Lang: "",
30-
}
39+
return nil
3140
}
41+
3242
rc.yamlNode = value
3343

3444
type commonRenderConfig struct {
35-
TOC bool `yaml:"include_toc"`
45+
TOC string `yaml:"include_toc"`
3646
Lang string `yaml:"lang"`
3747
}
3848
var basic commonRenderConfig
@@ -54,58 +64,45 @@ func (rc *RenderConfig) UnmarshalYAML(value *yaml.Node) error {
5464

5565
if err := value.Decode(&stringBasic); err == nil {
5666
if stringBasic.Gitea != "" {
57-
switch strings.TrimSpace(strings.ToLower(stringBasic.Gitea)) {
58-
case "none":
59-
rc.Meta = "none"
60-
case "table":
61-
rc.Meta = "table"
62-
default: // "details"
63-
rc.Meta = "details"
64-
}
67+
rc.Meta = renderMetaModeFromString(stringBasic.Gitea)
6568
}
6669
return nil
6770
}
6871

69-
type giteaControl struct {
72+
type yamlRenderConfig struct {
7073
Meta *string `yaml:"meta"`
7174
Icon *string `yaml:"details_icon"`
72-
TOC *bool `yaml:"include_toc"`
75+
TOC *string `yaml:"include_toc"`
7376
Lang *string `yaml:"lang"`
7477
}
7578

76-
type complexGiteaConfig struct {
77-
Gitea *giteaControl `yaml:"gitea"`
79+
type yamlRenderConfigWrapper struct {
80+
Gitea *yamlRenderConfig `yaml:"gitea"`
7881
}
79-
var complex complexGiteaConfig
80-
if err := value.Decode(&complex); err != nil {
81-
return fmt.Errorf("unable to decode into complexRenderConfig %w", err)
82+
83+
var cfg yamlRenderConfigWrapper
84+
if err := value.Decode(&cfg); err != nil {
85+
return fmt.Errorf("unable to decode into yamlRenderConfigWrapper %w", err)
8286
}
8387

84-
if complex.Gitea == nil {
88+
if cfg.Gitea == nil {
8589
return nil
8690
}
8791

88-
if complex.Gitea.Meta != nil {
89-
switch strings.TrimSpace(strings.ToLower(*complex.Gitea.Meta)) {
90-
case "none":
91-
rc.Meta = "none"
92-
case "table":
93-
rc.Meta = "table"
94-
default: // "details"
95-
rc.Meta = "details"
96-
}
92+
if cfg.Gitea.Meta != nil {
93+
rc.Meta = renderMetaModeFromString(*cfg.Gitea.Meta)
9794
}
9895

99-
if complex.Gitea.Icon != nil {
100-
rc.Icon = strings.TrimSpace(strings.ToLower(*complex.Gitea.Icon))
96+
if cfg.Gitea.Icon != nil {
97+
rc.Icon = strings.TrimSpace(strings.ToLower(*cfg.Gitea.Icon))
10198
}
10299

103-
if complex.Gitea.Lang != nil && *complex.Gitea.Lang != "" {
104-
rc.Lang = *complex.Gitea.Lang
100+
if cfg.Gitea.Lang != nil && *cfg.Gitea.Lang != "" {
101+
rc.Lang = *cfg.Gitea.Lang
105102
}
106103

107-
if complex.Gitea.TOC != nil {
108-
rc.TOC = *complex.Gitea.TOC
104+
if cfg.Gitea.TOC != nil {
105+
rc.TOC = *cfg.Gitea.TOC
109106
}
110107

111108
return nil
@@ -116,9 +113,9 @@ func (rc *RenderConfig) toMetaNode() ast.Node {
116113
return nil
117114
}
118115
switch rc.Meta {
119-
case "table":
116+
case markup.RenderMetaAsTable:
120117
return nodeToTable(rc.yamlNode)
121-
case "details":
118+
case markup.RenderMetaAsDetails:
122119
return nodeToDetails(rc.yamlNode, rc.Icon)
123120
default:
124121
return nil

modules/markup/markdown/renderconfig_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
6060
},
6161
{
6262
"toc", &RenderConfig{
63-
TOC: true,
63+
TOC: "true",
6464
Meta: "table",
6565
Icon: "table",
6666
Lang: "",
6767
}, "include_toc: true",
6868
},
6969
{
7070
"tocfalse", &RenderConfig{
71-
TOC: false,
71+
TOC: "false",
7272
Meta: "table",
7373
Icon: "table",
7474
Lang: "",
@@ -78,7 +78,7 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
7878
"toclang", &RenderConfig{
7979
Meta: "table",
8080
Icon: "table",
81-
TOC: true,
81+
TOC: "true",
8282
Lang: "testlang",
8383
}, `
8484
include_toc: true
@@ -120,7 +120,7 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
120120
"complex2", &RenderConfig{
121121
Lang: "two",
122122
Meta: "table",
123-
TOC: true,
123+
TOC: "true",
124124
Icon: "smiley",
125125
}, `
126126
lang: one
@@ -155,7 +155,7 @@ func TestRenderConfig_UnmarshalYAML(t *testing.T) {
155155
t.Errorf("Lang Expected %s Got %s", tt.expected.Lang, got.Lang)
156156
}
157157
if got.TOC != tt.expected.TOC {
158-
t.Errorf("TOC Expected %t Got %t", tt.expected.TOC, got.TOC)
158+
t.Errorf("TOC Expected %q Got %q", tt.expected.TOC, got.TOC)
159159
}
160160
})
161161
}

modules/markup/markdown/toc.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,14 @@ import (
1313
"github.com/yuin/goldmark/ast"
1414
)
1515

16-
func createTOCNode(toc []markup.Header, lang string) ast.Node {
16+
func createTOCNode(toc []markup.Header, lang string, detailsAttrs map[string]string) ast.Node {
1717
details := NewDetails()
1818
summary := NewSummary()
1919

20+
for k, v := range detailsAttrs {
21+
details.SetAttributeString(k, []byte(v))
22+
}
23+
2024
summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).Tr("toc"))))
2125
details.AppendChild(details, summary)
2226
ul := ast.NewList('-')
@@ -40,7 +44,7 @@ func createTOCNode(toc []markup.Header, lang string) ast.Node {
4044
}
4145
li := ast.NewListItem(currentLevel * 2)
4246
a := ast.NewLink()
43-
a.Destination = []byte(fmt.Sprintf("#%s", url.PathEscape(header.ID)))
47+
a.Destination = []byte(fmt.Sprintf("#%s", url.QueryEscape(header.ID)))
4448
a.AppendChild(a, ast.NewString([]byte(header.Text)))
4549
li.AppendChild(li, a)
4650
ul.AppendChild(ul, li)

modules/markup/renderer.go

+12-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ import (
1616

1717
"code.gitea.io/gitea/modules/git"
1818
"code.gitea.io/gitea/modules/setting"
19+
20+
"github.com/yuin/goldmark/ast"
21+
)
22+
23+
type RenderMetaMode string
24+
25+
const (
26+
RenderMetaAsDetails RenderMetaMode = "details" // default
27+
RenderMetaAsNone RenderMetaMode = "none"
28+
RenderMetaAsTable RenderMetaMode = "table"
1929
)
2030

2131
type ProcessorHelper struct {
@@ -63,7 +73,8 @@ type RenderContext struct {
6373
GitRepo *git.Repository
6474
ShaExistCache map[string]bool
6575
cancelFn func()
66-
TableOfContents []Header
76+
SidebarTocTree ast.Node
77+
RenderMetaAs RenderMetaMode
6778
InStandalonePage bool // used by external render. the router "/org/repo/render/..." will output the rendered content in a standalone page
6879
}
6980

modules/templates/helper.go

-7
Original file line numberDiff line numberDiff line change
@@ -172,13 +172,6 @@ func NewFuncMap() []template.FuncMap {
172172
}
173173
return false
174174
},
175-
"Iterate": func(arg interface{}) (items []int64) {
176-
count, _ := util.ToInt64(arg)
177-
for i := int64(0); i < count; i++ {
178-
items = append(items, i)
179-
}
180-
return items
181-
},
182175

183176
// -----------------------------------------------------------------
184177
// setting

0 commit comments

Comments
 (0)