A vibe coded tangled fork which supports pijul.

appview/pages: clone rctx before transforming markdown

avoid global mutation and weird cross-request interactions.

Signed-off-by: oppiliappan <me@oppi.li>

authored by

oppiliappan and committed by tangled.org 76c5d8a9 73c7f95d

+41 -30
+12 -9
appview/pages/funcmap.go
··· 265 265 return v.Slice(0, min(n, v.Len())).Interface() 266 266 }, 267 267 "markdown": func(text string) template.HTML { 268 - p.rctx.RendererType = markup.RendererTypeDefault 269 - htmlString := p.rctx.RenderMarkdown(text) 270 - sanitized := p.rctx.SanitizeDefault(htmlString) 268 + rctx := p.rctx.Clone() 269 + rctx.RendererType = markup.RendererTypeDefault 270 + htmlString := rctx.RenderMarkdown(text) 271 + sanitized := rctx.SanitizeDefault(htmlString) 271 272 return template.HTML(sanitized) 272 273 }, 273 274 "description": func(text string) template.HTML { 274 - p.rctx.RendererType = markup.RendererTypeDefault 275 - htmlString := p.rctx.RenderMarkdownWith(text, goldmark.New( 275 + rctx := p.rctx.Clone() 276 + rctx.RendererType = markup.RendererTypeDefault 277 + htmlString := rctx.RenderMarkdownWith(text, goldmark.New( 276 278 goldmark.WithExtensions( 277 279 emoji.Emoji, 278 280 ), 279 281 )) 280 - sanitized := p.rctx.SanitizeDescription(htmlString) 282 + sanitized := rctx.SanitizeDescription(htmlString) 281 283 return template.HTML(sanitized) 282 284 }, 283 285 "readme": func(text string) template.HTML { 284 - p.rctx.RendererType = markup.RendererTypeRepoMarkdown 285 - htmlString := p.rctx.RenderMarkdown(text) 286 - sanitized := p.rctx.SanitizeDefault(htmlString) 286 + rctx := p.rctx.Clone() 287 + rctx.RendererType = markup.RendererTypeRepoMarkdown 288 + htmlString := rctx.RenderMarkdown(text) 289 + sanitized := rctx.SanitizeDefault(htmlString) 287 290 return template.HTML(sanitized) 288 291 }, 289 292 "code": func(content, path string) string {
+9
appview/pages/markup/markdown.go
··· 86 86 return md 87 87 } 88 88 89 + // clone creates a shallow copy of the RenderContext 90 + func (rctx *RenderContext) Clone() *RenderContext { 91 + if rctx == nil { 92 + return nil 93 + } 94 + clone := *rctx 95 + return &clone 96 + } 97 + 89 98 // NewMarkdownWith is an alias for NewMarkdown with extra extensions. 90 99 func NewMarkdownWith(hostname string, extra ...goldmark.Extender) goldmark.Markdown { 91 100 return NewMarkdown(hostname, extra...)
+20 -21
appview/pages/pages.go
··· 350 350 return fmt.Errorf("failed to read %s: %w", filename, err) 351 351 } 352 352 353 - p.rctx.RendererType = markup.RendererTypeDefault 354 - htmlString := p.rctx.RenderMarkdown(string(markdownBytes)) 355 - sanitized := p.rctx.SanitizeDefault(htmlString) 353 + rctx := p.rctx.Clone() 354 + rctx.RendererType = markup.RendererTypeDefault 355 + htmlString := rctx.RenderMarkdown(string(markdownBytes)) 356 + sanitized := rctx.SanitizeDefault(htmlString) 356 357 params.Content = template.HTML(sanitized) 357 358 358 359 return p.execute("legal/terms", w, params) ··· 378 379 return fmt.Errorf("failed to read %s: %w", filename, err) 379 380 } 380 381 381 - p.rctx.RendererType = markup.RendererTypeDefault 382 - htmlString := p.rctx.RenderMarkdown(string(markdownBytes)) 383 - sanitized := p.rctx.SanitizeDefault(htmlString) 382 + rctx := p.rctx.Clone() 383 + rctx.RendererType = markup.RendererTypeDefault 384 + htmlString := rctx.RenderMarkdown(string(markdownBytes)) 385 + sanitized := rctx.SanitizeDefault(htmlString) 384 386 params.Content = template.HTML(sanitized) 385 387 386 388 return p.execute("legal/privacy", w, params) ··· 796 798 return p.executeRepo("repo/knotUnreachable", w, params) 797 799 } 798 800 799 - p.rctx.RepoInfo = params.RepoInfo 800 - p.rctx.RepoInfo.Ref = params.Ref 801 - p.rctx.RendererType = markup.RendererTypeRepoMarkdown 801 + rctx := p.rctx.Clone() 802 + rctx.RepoInfo = params.RepoInfo 803 + rctx.RepoInfo.Ref = params.Ref 804 + rctx.RendererType = markup.RendererTypeRepoMarkdown 802 805 803 806 if params.ReadmeFileName != "" { 804 807 ext := filepath.Ext(params.ReadmeFileName) 805 808 switch ext { 806 809 case ".md", ".markdown", ".mdown", ".mkdn", ".mkd": 807 810 params.Raw = false 808 - htmlString := p.rctx.RenderMarkdown(params.Readme) 809 - sanitized := p.rctx.SanitizeDefault(htmlString) 811 + htmlString := rctx.RenderMarkdown(params.Readme) 812 + sanitized := rctx.SanitizeDefault(htmlString) 810 813 params.HTMLReadme = template.HTML(sanitized) 811 814 default: 812 815 params.Raw = true ··· 889 892 func (p *Pages) RepoTree(w io.Writer, params RepoTreeParams) error { 890 893 params.Active = "overview" 891 894 892 - p.rctx.RepoInfo = params.RepoInfo 893 - p.rctx.RepoInfo.Ref = params.Ref 894 - p.rctx.RendererType = markup.RendererTypeRepoMarkdown 895 + rctx := p.rctx.Clone() 896 + rctx.RepoInfo = params.RepoInfo 897 + rctx.RepoInfo.Ref = params.Ref 898 + rctx.RendererType = markup.RendererTypeRepoMarkdown 895 899 896 900 if params.ReadmeFileName != "" { 897 901 ext := filepath.Ext(params.ReadmeFileName) 898 902 switch ext { 899 903 case ".md", ".markdown", ".mdown", ".mkdn", ".mkd": 900 904 params.Raw = false 901 - htmlString := p.rctx.RenderMarkdown(params.Readme) 902 - sanitized := p.rctx.SanitizeDefault(htmlString) 905 + htmlString := rctx.RenderMarkdown(params.Readme) 906 + sanitized := rctx.SanitizeDefault(htmlString) 903 907 params.HTMLReadme = template.HTML(sanitized) 904 908 default: 905 909 params.Raw = true ··· 971 975 } 972 976 973 977 func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error { 974 - switch params.BlobView.ContentType { 975 - case models.BlobContentTypeMarkup: 976 - p.rctx.RepoInfo = params.RepoInfo 977 - } 978 - 979 978 params.Active = "overview" 980 979 return p.executeRepo("repo/blob", w, params) 981 980 }