• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

yuin / goldmark / 30431627644

29 Jul 2026 07:24AM UTC coverage: 82.966% (-0.03%) from 82.991%
30431627644

push

github

yuin
feat: `goldmark_v1_attribute` build tag

154 of 236 new or added lines in 13 files covered. (65.25%)

17 existing lines in 3 files now uncovered.

6400 of 7714 relevant lines covered (82.97%)

348703.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.44
/parser/fcode_block.go
1
package parser
2

3
import (
4
        "bytes"
5

6
        "github.com/yuin/goldmark/v2/ast"
7
        "github.com/yuin/goldmark/v2/text"
8
        "github.com/yuin/goldmark/v2/util"
9
)
10

11
type fencedCodeBlockParser struct {
12
}
13

14
var defaultFencedCodeBlockParser = &fencedCodeBlockParser{}
15

16
// NewFencedCodeBlockParser returns a new BlockParser that
17
// parses fenced code blocks.
18
func NewFencedCodeBlockParser() BlockParser {
2,118✔
19
        return defaultFencedCodeBlockParser
2,118✔
20
}
2,118✔
21

22
type fenceData struct {
23
        char   byte
24
        indent int
25
        length int
26
        node   ast.Node
27
}
28

29
var fencedCodeBlockInfoKey = NewContextKey()
30

31
func (b *fencedCodeBlockParser) Trigger() []byte {
2,118✔
32
        return []byte{'~', '`'}
2,118✔
33
}
2,118✔
34

35
func (b *fencedCodeBlockParser) Open(_ ast.Node, reader text.Reader, pc Context) (ast.Node, State) {
873✔
36
        line, segment := reader.PeekLine()
873✔
37
        pos := pc.BlockOffset()
873✔
38
        if pos < 0 || (line[pos] != '`' && line[pos] != '~') {
873✔
NEW
39
                return nil, NoChildren
×
NEW
40
        }
×
41
        findent := pos
873✔
42
        fenceChar := line[pos]
873✔
43
        i := pos
873✔
44
        for i < len(line) && line[i] == fenceChar {
2,721✔
45
                i++
1,848✔
46
        }
1,848✔
47
        oFenceLength := i - pos
873✔
48
        if oFenceLength < 3 {
1,317✔
49
                return nil, NoChildren
444✔
50
        }
444✔
51
        var info text.Value
429✔
52
        if i < len(line)-1 {
636✔
53
                rest := line[i:]
207✔
54
                left := util.TrimLeftSpaceLength(rest)
207✔
55
                right := util.TrimRightSpaceLength(rest)
207✔
56
                if left < len(rest)-right {
414✔
57
                        infoStart, infoStop := segment.Start-segment.Padding+i+left, segment.Stop-right
207✔
58
                        value := rest[left : len(rest)-right]
207✔
59
                        if fenceChar == '`' && bytes.IndexByte(value, '`') > -1 {
225✔
60
                                return nil, NoChildren
18✔
61
                        } else if infoStart != infoStop {
396✔
62
                                info = text.NewIndexValue(text.NewIndex(infoStart, infoStop))
189✔
63
                        }
189✔
64
                }
65
        }
66
        node := ast.NewCodeBlock(ast.CodeBlockKindFenced, text.Lines{}, ast.WithCodeBlockInfo(info))
411✔
67
        pc.Set(fencedCodeBlockInfoKey, &fenceData{fenceChar, findent, oFenceLength, node})
411✔
68
        return node, NoChildren
411✔
69

70
}
71

72
func (b *fencedCodeBlockParser) Continue(node ast.Node, reader text.Reader, pc Context) State {
2,148✔
73
        line, segment := reader.PeekLine()
2,148✔
74
        fdata := pc.Get(fencedCodeBlockInfoKey).(*fenceData)
2,148✔
75

2,148✔
76
        w, pos := util.IndentWidth(line, reader.LineOffset())
2,148✔
77
        if w < 4 {
3,639✔
78
                i := pos
1,491✔
79
                for i < len(line) && line[i] == fdata.char {
2,697✔
80
                        i++
1,206✔
81
                }
1,206✔
82
                length := i - pos
1,491✔
83
                if length >= fdata.length && util.IsBlank(line[i:]) {
1,845✔
84
                        reader.AdvanceToEOL()
354✔
85
                        return Close
354✔
86
                }
354✔
87
        }
88
        pos, padding := util.IndentPositionPadding(line, reader.LineOffset(), segment.Padding, fdata.indent)
1,794✔
89
        if pos < 0 {
1,830✔
90
                pos = max(0, util.FirstNonSpacePosition(line)) - segment.Padding
36✔
91
                padding = 0
36✔
92
        }
36✔
93
        seg := text.NewSegmentPadding(segment.Start+pos, segment.Stop, padding)
1,794✔
94
        // if code block line starts with a tab, keep a tab as it is.
1,794✔
95
        if padding != 0 {
1,803✔
96
                preserveLeadingTabInCodeBlock(&seg, reader, fdata.indent)
9✔
97
        }
9✔
98
        seg.ForceNewline = true // EOF as newline
1,794✔
99
        node.(*ast.CodeBlock).Value.AppendSegment(seg)
1,794✔
100
        reader.AdvanceToEOL()
1,794✔
101
        return Continue | NoChildren
1,794✔
102
}
103

104
func (b *fencedCodeBlockParser) Close(node ast.Node, _ text.Reader, pc Context) {
411✔
105
        fdata := pc.Get(fencedCodeBlockInfoKey).(*fenceData)
411✔
106
        if fdata.node == node {
822✔
107
                pc.Set(fencedCodeBlockInfoKey, nil)
411✔
108
        }
411✔
109
}
110

111
func (b *fencedCodeBlockParser) CanInterruptParagraph() bool {
84✔
112
        return true
84✔
113
}
84✔
114

115
func (b *fencedCodeBlockParser) CanAcceptIndentedLine() bool {
6✔
116
        return false
6✔
117
}
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc