@@ -6,10 +6,12 @@ package markup
66import (
77 "fmt"
88 "html"
9+ "html/template"
910 "io"
1011 "strings"
1112
1213 "code.gitea.io/gitea/modules/highlight"
14+ "code.gitea.io/gitea/modules/htmlutil"
1315 "code.gitea.io/gitea/modules/log"
1416 "code.gitea.io/gitea/modules/markup"
1517 "code.gitea.io/gitea/modules/setting"
@@ -20,33 +22,36 @@ import (
2022)
2123
2224func init () {
23- markup .RegisterRenderer (Renderer {})
25+ markup .RegisterRenderer (renderer {})
2426}
2527
2628// Renderer implements markup.Renderer for orgmode
27- type Renderer struct {}
29+ type renderer struct {}
2830
29- var _ markup.PostProcessRenderer = (* Renderer )(nil )
31+ var (
32+ _ markup.Renderer = (* renderer )(nil )
33+ _ markup.PostProcessRenderer = (* renderer )(nil )
34+ )
3035
3136// Name implements markup.Renderer
32- func (Renderer ) Name () string {
37+ func (renderer ) Name () string {
3338 return "orgmode"
3439}
3540
3641// NeedPostProcess implements markup.PostProcessRenderer
37- func (Renderer ) NeedPostProcess () bool { return true }
42+ func (renderer ) NeedPostProcess () bool { return true }
3843
3944// Extensions implements markup.Renderer
40- func (Renderer ) Extensions () []string {
45+ func (renderer ) Extensions () []string {
4146 return []string {".org" }
4247}
4348
4449// SanitizerRules implements markup.Renderer
45- func (Renderer ) SanitizerRules () []setting.MarkupSanitizerRule {
50+ func (renderer ) SanitizerRules () []setting.MarkupSanitizerRule {
4651 return []setting.MarkupSanitizerRule {}
4752}
4853
49- // Render renders orgmode rawbytes to HTML
54+ // Render renders orgmode raw bytes to HTML
5055func Render (ctx * markup.RenderContext , input io.Reader , output io.Writer ) error {
5156 htmlWriter := org .NewHTMLWriter ()
5257 htmlWriter .HighlightCodeBlock = func (source , lang string , inline bool , params map [string ]string ) string {
@@ -56,10 +61,7 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
5661 panic (err )
5762 }
5863 }()
59- var w strings.Builder
60- if _ , err := w .WriteString (`<pre>` ); err != nil {
61- return ""
62- }
64+ w := & strings.Builder {}
6365
6466 lexer := lexers .Get (lang )
6567 if lexer == nil && lang == "" {
@@ -70,38 +72,28 @@ func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error
7072 lang = strings .ToLower (lexer .Config ().Name )
7173 }
7274
75+ // include language-x class as part of commonmark spec
76+ if err := ctx .RenderInternal .FormatWithSafeAttrs (w , `<pre><code class="chroma language-%s">` , lang ); err != nil {
77+ return ""
78+ }
7379 if lexer == nil {
74- // include language-x class as part of commonmark spec
75- if _ , err := w .WriteString (`<code class="chroma language-` + lang + `">` ); err != nil {
76- return ""
77- }
7880 if _ , err := w .WriteString (html .EscapeString (source )); err != nil {
7981 return ""
8082 }
8183 } else {
82- // include language-x class as part of commonmark spec
83- if _ , err := w .WriteString (`<code class="chroma language-` + lang + `">` ); err != nil {
84- return ""
85- }
8684 lexer = chroma .Coalesce (lexer )
87-
8885 if _ , err := w .WriteString (string (highlight .CodeFromLexer (lexer , source ))); err != nil {
8986 return ""
9087 }
9188 }
92-
9389 if _ , err := w .WriteString ("</code></pre>" ); err != nil {
9490 return ""
9591 }
9692
9793 return w .String ()
9894 }
9995
100- w := & Writer {
101- HTMLWriter : htmlWriter ,
102- Ctx : ctx ,
103- }
104-
96+ w := & orgWriter {rctx : ctx , HTMLWriter : htmlWriter }
10597 htmlWriter .ExtendingWriter = w
10698
10799 res , err := org .New ().Silent ().Parse (input , "" ).Write (w )
@@ -122,17 +114,18 @@ func RenderString(ctx *markup.RenderContext, content string) (string, error) {
122114}
123115
124116// Render renders orgmode string to HTML string
125- func (Renderer ) Render (ctx * markup.RenderContext , input io.Reader , output io.Writer ) error {
117+ func (renderer ) Render (ctx * markup.RenderContext , input io.Reader , output io.Writer ) error {
126118 return Render (ctx , input , output )
127119}
128120
129- // Writer implements org.Writer
130- type Writer struct {
121+ type orgWriter struct {
131122 * org.HTMLWriter
132- Ctx * markup.RenderContext
123+ rctx * markup.RenderContext
133124}
134125
135- func (r * Writer ) resolveLink (kind , link string ) string {
126+ var _ org.Writer = (* orgWriter )(nil )
127+
128+ func (r * orgWriter ) resolveLink (kind , link string ) string {
136129 link = strings .TrimPrefix (link , "file:" )
137130 if ! strings .HasPrefix (link , "#" ) && // not a URL fragment
138131 ! markup .IsFullURLString (link ) {
@@ -142,39 +135,42 @@ func (r *Writer) resolveLink(kind, link string) string {
142135 kind = org.RegularLink {URL : link }.Kind ()
143136 }
144137 if kind == "image" || kind == "video" {
145- link = r .Ctx .RenderHelper .ResolveLink (link , markup .LinkTypeMedia )
138+ link = r .rctx .RenderHelper .ResolveLink (link , markup .LinkTypeMedia )
146139 } else {
147- link = r .Ctx .RenderHelper .ResolveLink (link , markup .LinkTypeDefault )
140+ link = r .rctx .RenderHelper .ResolveLink (link , markup .LinkTypeDefault )
148141 }
149142 }
150143 return link
151144}
152145
153146// WriteRegularLink renders images, links or videos
154- func (r * Writer ) WriteRegularLink (l org.RegularLink ) {
147+ func (r * orgWriter ) WriteRegularLink (l org.RegularLink ) {
155148 link := r .resolveLink (l .Kind (), l .URL )
156149
150+ printHTML := func (html string , a ... any ) {
151+ _ , _ = fmt .Fprint (r , htmlutil .HTMLFormat (html , a ... ))
152+ }
157153 // Inspired by https://github.com/niklasfasching/go-org/blob/6eb20dbda93cb88c3503f7508dc78cbbc639378f/org/html_writer.go#L406-L427
158154 switch l .Kind () {
159155 case "image" :
160156 if l .Description == nil {
161- _ , _ = fmt . Fprintf ( r , `<img src="%s" alt="%s" / >` , link , link )
157+ printHTML ( `<img src="%s" alt="%s">` , link , link )
162158 } else {
163159 imageSrc := r .resolveLink (l .Kind (), org .String (l .Description ... ))
164- _ , _ = fmt . Fprintf ( r , `<a href="%s"><img src="%s" alt="%s" / ></a>` , link , imageSrc , imageSrc )
160+ printHTML ( `<a href="%s"><img src="%s" alt="%s"></a>` , link , imageSrc , imageSrc )
165161 }
166162 case "video" :
167163 if l .Description == nil {
168- _ , _ = fmt . Fprintf ( r , `<video src="%s">%s</video>` , link , link )
164+ printHTML ( `<video src="%s">%s</video>` , link , link )
169165 } else {
170166 videoSrc := r .resolveLink (l .Kind (), org .String (l .Description ... ))
171- _ , _ = fmt . Fprintf ( r , `<a href="%s"><video src="%s">%s</video></a>` , link , videoSrc , videoSrc )
167+ printHTML ( `<a href="%s"><video src="%s">%s</video></a>` , link , videoSrc , videoSrc )
172168 }
173169 default :
174- description : = link
170+ var description any = link
175171 if l .Description != nil {
176- description = r .WriteNodesAsString (l .Description ... )
172+ description = template . HTML ( r .WriteNodesAsString (l .Description ... )) // orgmode HTMLWriter outputs HTML content
177173 }
178- _ , _ = fmt . Fprintf ( r , `<a href="%s">%s</a>` , link , description )
174+ printHTML ( `<a href="%s">%s</a>` , link , description )
179175 }
180176}
0 commit comments