5
5
"bytes"
6
6
"fmt"
7
7
"io"
8
+ "slices"
8
9
"sync"
10
+ "unicode"
9
11
10
12
"github.com/yuin/goldmark/ast"
11
13
"github.com/yuin/goldmark/renderer"
@@ -243,7 +245,7 @@ func (r *Renderer) renderFencedCodeBlock(node ast.Node, entering bool) ast.WalkS
243
245
r .rc .writer .WriteBytes ([]byte ("```" ))
244
246
if entering {
245
247
if info := n .Info ; info != nil {
246
- r .rc .writer .WriteBytes (info .Text (r .rc .source ))
248
+ r .rc .writer .WriteBytes (info .Value (r .rc .source ))
247
249
}
248
250
r .rc .writer .FlushLine ()
249
251
r .renderLines (node , entering )
@@ -310,7 +312,7 @@ func (r *Renderer) renderRawHTML(node ast.Node, entering bool) ast.WalkStatus {
310
312
func (r * Renderer ) renderText (node ast.Node , entering bool ) ast.WalkStatus {
311
313
n := node .(* ast.Text )
312
314
if entering {
313
- text := n .Text (r .rc .source )
315
+ text := n .Value (r .rc .source )
314
316
315
317
r .rc .writer .WriteBytes (text )
316
318
if n .SoftLineBreak () {
@@ -369,10 +371,64 @@ func (r *Renderer) renderLinkCommon(title, destination []byte, entering bool) as
369
371
}
370
372
371
373
func (r * Renderer ) renderCodeSpan (node ast.Node , entering bool ) ast.WalkStatus {
372
- if bytes .Count (node .Text (r .rc .source ), []byte ("`" ))% 2 != 0 {
373
- r .rc .writer .WriteBytes ([]byte ("``" ))
374
+ if entering {
375
+ // get contents of codespan
376
+ var contentBytes []byte
377
+ for c := node .FirstChild (); c != nil ; c = c .NextSibling () {
378
+ text := c .(* ast.Text ).Segment
379
+ contentBytes = append (contentBytes , text .Value (r .rc .source )... )
380
+ }
381
+ contents := string (contentBytes )
382
+
383
+ //
384
+ var beginsWithSpace bool
385
+ var endsWithSpace bool
386
+ var beginsWithBackTick bool
387
+ var endsWithBackTick bool
388
+ isOnlySpace := true
389
+ backtickLengths := []int {}
390
+ count := 0
391
+ for i , c := range contents {
392
+ if i == 0 {
393
+ beginsWithSpace = unicode .IsSpace (c )
394
+ beginsWithBackTick = c == '`'
395
+ } else if i == len (contents )- 1 {
396
+ endsWithSpace = unicode .IsSpace (c )
397
+ endsWithBackTick = c == '`'
398
+ }
399
+ if ! unicode .IsSpace (c ) {
400
+ isOnlySpace = false
401
+ }
402
+ if c == '`' {
403
+ count ++
404
+ } else if count > 0 {
405
+ backtickLengths = append (backtickLengths , count )
406
+ count = 0
407
+ }
408
+ }
409
+ if count > 0 {
410
+ backtickLengths = append (backtickLengths , count )
411
+ }
412
+
413
+ // Surround the codespan with the minimum number of backticks required to contain the span.
414
+ for i := 1 ; i <= len (contentBytes ); i ++ {
415
+ if ! slices .Contains (backtickLengths , i ) {
416
+ r .rc .codeSpanContext .backtickLength = i
417
+ break
418
+ }
419
+ }
420
+ r .rc .writer .WriteBytes (bytes .Repeat ([]byte ("`" ), r .rc .codeSpanContext .backtickLength ))
421
+
422
+ // Check if the code span needs to be padded with spaces
423
+ if beginsWithSpace && endsWithSpace && ! isOnlySpace || beginsWithBackTick || endsWithBackTick {
424
+ r .rc .codeSpanContext .padSpace = true
425
+ r .rc .writer .WriteBytes ([]byte (" " ))
426
+ }
374
427
} else {
375
- r .rc .writer .WriteBytes ([]byte ("`" ))
428
+ if r .rc .codeSpanContext .padSpace {
429
+ r .rc .writer .WriteBytes ([]byte (" " ))
430
+ }
431
+ r .rc .writer .WriteBytes (bytes .Repeat ([]byte ("`" ), r .rc .codeSpanContext .backtickLength ))
376
432
}
377
433
378
434
return ast .WalkContinue
@@ -389,14 +445,23 @@ type renderContext struct {
389
445
// source is the markdown source
390
446
source []byte
391
447
// listMarkers is the marker character used for the current list
392
- lists []listContext
448
+ lists []listContext
449
+ codeSpanContext codeSpanContext
393
450
}
394
451
395
452
type listContext struct {
396
453
list * ast.List
397
454
num int
398
455
}
399
456
457
+ // codeSpanContext holds state about how the current codespan should be rendererd.
458
+ type codeSpanContext struct {
459
+ // number of backticks to use
460
+ backtickLength int
461
+ // whether to surround the codespan with spaces
462
+ padSpace bool
463
+ }
464
+
400
465
// newRenderContext returns a new renderContext object
401
466
func newRenderContext (writer io.Writer , source []byte , config * Config ) renderContext {
402
467
return renderContext {
0 commit comments