@@ -75,7 +75,7 @@ func (h chromaHighlighter) Highlight(code, lang string, opts interface{}) (strin
7575 }
7676 var b strings.Builder
7777
78- if err := highlight (& b , code , lang , nil , cfg ); err != nil {
78+ if _ , _ , err := highlight (& b , code , lang , nil , cfg ); err != nil {
7979 return "" , err
8080 }
8181
@@ -103,13 +103,15 @@ func (h chromaHighlighter) HighlightCodeBlock(ctx hooks.CodeblockContext, opts i
103103 return HightlightResult {}, err
104104 }
105105
106- err := highlight (& b , ctx .Inner (), ctx .Type (), attributes , cfg )
106+ low , high , err := highlight (& b , ctx .Inner (), ctx .Type (), attributes , cfg )
107107 if err != nil {
108108 return HightlightResult {}, err
109109 }
110110
111111 return HightlightResult {
112- Body : template .HTML (b .String ()),
112+ highlighted : template .HTML (b .String ()),
113+ innerLow : low ,
114+ innerHigh : high ,
113115 }, nil
114116}
115117
@@ -127,7 +129,8 @@ func (h chromaHighlighter) RenderCodeblock(w hugio.FlexiWriter, ctx hooks.Codebl
127129
128130 code := text .Puts (ctx .Inner ())
129131
130- return highlight (w , code , ctx .Type (), attributes , cfg )
132+ _ , _ , err := highlight (w , code , ctx .Type (), attributes , cfg )
133+ return err
131134}
132135
133136func (h chromaHighlighter ) IsDefaultCodeBlockRenderer () bool {
@@ -141,14 +144,22 @@ func (h chromaHighlighter) GetIdentity() identity.Identity {
141144}
142145
143146type HightlightResult struct {
144- Body template.HTML
147+ innerLow int
148+ innerHigh int
149+ highlighted template.HTML
145150}
146151
147- func (h HightlightResult ) Highlighted () template.HTML {
148- return h .Body
152+ func (h HightlightResult ) Wrapped () template.HTML {
153+ return h .highlighted
149154}
150155
151- func highlight (w hugio.FlexiWriter , code , lang string , attributes []attributes.Attribute , cfg Config ) error {
156+ func (h HightlightResult ) Inner () template.HTML {
157+ return h .highlighted [h .innerLow :h .innerHigh ]
158+ }
159+
160+ func highlight (fw hugio.FlexiWriter , code , lang string , attributes []attributes.Attribute , cfg Config ) (int , int , error ) {
161+ var low , high int
162+
152163 var lexer chroma.Lexer
153164 if lang != "" {
154165 lexer = lexers .Get (lang )
@@ -162,12 +173,14 @@ func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.A
162173 lang = strings .ToLower (lexer .Config ().Name )
163174 }
164175
176+ w := & byteCountFlexiWriter {delegate : fw }
177+
165178 if lexer == nil {
166- wrapper := getPreWrapper (lang )
179+ wrapper := getPreWrapper (lang , w )
167180 fmt .Fprint (w , wrapper .Start (true , "" ))
168181 fmt .Fprint (w , gohtml .EscapeString (code ))
169182 fmt .Fprint (w , wrapper .End (true ))
170- return nil
183+ return low , high , nil
171184 }
172185
173186 style := styles .Get (cfg .Style )
@@ -178,42 +191,44 @@ func highlight(w hugio.FlexiWriter, code, lang string, attributes []attributes.A
178191
179192 iterator , err := lexer .Tokenise (nil , code )
180193 if err != nil {
181- return err
194+ return 0 , 0 , err
182195 }
183196
184197 options := cfg .ToHTMLOptions ()
185- options = append (options , getHtmlPreWrapper (lang ))
198+ preWrapper := getPreWrapper (lang , w )
199+ options = append (options , html .WithPreWrapper (preWrapper ))
186200
187201 formatter := html .New (options ... )
188202
189203 writeDivStart (w , attributes )
204+
190205 if err := formatter .Format (w , style , iterator ); err != nil {
191- return err
206+ return 0 , 0 , err
192207 }
193208 writeDivEnd (w )
194209
195- return nil
210+ return preWrapper . low , preWrapper . high , nil
196211}
197212
198- func getPreWrapper (language string ) preWrapper {
199- return preWrapper {language : language }
200- }
201-
202- func getHtmlPreWrapper (language string ) html.Option {
203- return html .WithPreWrapper (getPreWrapper (language ))
213+ func getPreWrapper (language string , writeCounter * byteCountFlexiWriter ) * preWrapper {
214+ return & preWrapper {language : language , writeCounter : writeCounter }
204215}
205216
206217type preWrapper struct {
207- language string
218+ low int
219+ high int
220+ writeCounter * byteCountFlexiWriter
221+ language string
208222}
209223
210- func (p preWrapper ) Start (code bool , styleAttr string ) string {
224+ func (p * preWrapper ) Start (code bool , styleAttr string ) string {
211225 var language string
212226 if code {
213227 language = p .language
214228 }
215229 w := & strings.Builder {}
216230 WritePreStart (w , language , styleAttr )
231+ p .low = p .writeCounter .counter + w .Len ()
217232 return w .String ()
218233}
219234
@@ -229,7 +244,8 @@ func WritePreStart(w io.Writer, language, styleAttr string) {
229244
230245const preEnd = "</code></pre>"
231246
232- func (p preWrapper ) End (code bool ) string {
247+ func (p * preWrapper ) End (code bool ) string {
248+ p .high = p .writeCounter .counter
233249 return preEnd
234250}
235251
@@ -258,3 +274,31 @@ func writeDivStart(w hugio.FlexiWriter, attrs []attributes.Attribute) {
258274func writeDivEnd (w hugio.FlexiWriter ) {
259275 w .WriteString ("</div>" )
260276}
277+
278+ type byteCountFlexiWriter struct {
279+ delegate hugio.FlexiWriter
280+ counter int
281+ }
282+
283+ func (w * byteCountFlexiWriter ) Write (p []byte ) (int , error ) {
284+ n , err := w .delegate .Write (p )
285+ w .counter += n
286+ return n , err
287+ }
288+
289+ func (w * byteCountFlexiWriter ) WriteByte (c byte ) error {
290+ w .counter ++
291+ return w .delegate .WriteByte (c )
292+ }
293+
294+ func (w * byteCountFlexiWriter ) WriteString (s string ) (int , error ) {
295+ n , err := w .delegate .WriteString (s )
296+ w .counter += n
297+ return n , err
298+ }
299+
300+ func (w * byteCountFlexiWriter ) WriteRune (r rune ) (int , error ) {
301+ n , err := w .delegate .WriteRune (r )
302+ w .counter += n
303+ return n , err
304+ }
0 commit comments