Repository navigation
Expand file tree
/
Copy pathapi_math.go
More file actions
156 lines (142 loc) · 5.06 KB
/
Copy pathapi_math.go
File metadata and controls
156 lines (142 loc) · 5.06 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package marksplice
import "github.com/zoster81/marksplice/internal/splice"
// MathExpressionStyle identifies one reviewed GitHub-compatible mathematical source form.
type MathExpressionStyle uint8
const (
MathExpressionUnknown MathExpressionStyle = iota
MathExpressionInlineDollar
MathExpressionInlineBacktick
MathExpressionBlockDollar
MathExpressionFencedBlock
)
// MathExpression is immutable typed detail for one reviewed mathematical source form.
// Mathematical payload is opaque data; Marksplice does not parse or render LaTeX.
type MathExpression struct {
id NodeID
style MathExpressionStyle
sourceRange Range
payloadRange Range
hasPayload bool
}
// ID returns the snapshot-scoped identity. Fenced math shares the underlying FencedBlock ID.
func (m MathExpression) ID() NodeID { return m.id }
// Style returns the exact reviewed source delimiter/container form.
func (m MathExpression) Style() MathExpressionStyle { return m.style }
// Range returns the complete source-owned mathematical syntax/container.
func (m MathExpression) Range() Range { return m.sourceRange }
// PayloadRange returns one exact contiguous payload span when available.
// Dollar/backtick forms always expose it; fenced math may be non-contiguous or empty.
func (m MathExpression) PayloadRange() (Range, bool) {
if !m.hasPayload {
return Range{}, false
}
return m.payloadRange, true
}
// MathExpressions returns reviewed mathematical expressions in source order.
// Exact-info `math` fenced blocks reuse their existing FencedBlock identity rather
// than creating a second structural node.
func (d *Document) MathExpressions() []MathExpression {
if d == nil || d.document == nil {
return nil
}
result := make([]MathExpression, 0)
for index := 0; index < d.document.NodeCount(); index++ {
summary, ok := d.document.NodeSummaryAt(index)
if !ok {
continue
}
if summary.Kind != splice.KindMathExpression && summary.Kind != splice.KindFencedCode {
continue
}
node, ok := d.document.Node(summary.ID)
if !ok {
continue
}
expression, ok := publicMathExpression(d.document, node)
if ok {
result = append(result, expression)
}
}
return result
}
// MathExpression returns one reviewed mathematical expression by snapshot ID.
func (d *Document) MathExpression(id NodeID) (MathExpression, bool) {
node, ok := d.internalNode(id)
if !ok {
return MathExpression{}, false
}
return publicMathExpression(d.document, node)
}
// PrepareReplaceMathExpression prepares a source-preserving replacement of one
// reviewed mathematical payload while retaining its exact delimiter/container form.
func (d *Document) PrepareReplaceMathExpression(id NodeID, replacement []byte) (ChangeSet, error) {
if d == nil || d.document == nil {
return ChangeSet{}, ErrNodeNotFound
}
node, ok := d.internalNode(id)
if !ok {
return ChangeSet{}, ErrNodeNotFound
}
if _, ok := publicMathExpression(d.document, node); !ok {
return ChangeSet{}, ErrInvalidTargetKind
}
return publicChangeSet(d.document.PrepareReplaceMathExpression(internalNodeID(id), replacement))
}
// MathExpressionPayloadRanges returns caller-owned source-backed payload ranges.
// Fenced math may expose zero, one, or multiple physical payload ranges.
func (d *Document) MathExpressionPayloadRanges(id NodeID) ([]Range, bool) {
if d == nil || d.document == nil {
return nil, false
}
ranges, ok := d.document.MathExpressionPayloadRanges(internalNodeID(id))
if !ok {
return nil, false
}
return publicRanges(ranges), true
}
func publicMathExpression(document *splice.Document, node splice.Node) (MathExpression, bool) {
if node.Kind == splice.KindMathExpression && node.Editable {
style, ok := publicMathExpressionStyle(node.MathStyle)
if !ok || node.Range.Start >= node.Range.End || node.ContentRange.Start >= node.ContentRange.End {
return MathExpression{}, false
}
return MathExpression{
id: publicNodeID(node.ID),
style: style,
sourceRange: publicRange(node.Range),
payloadRange: publicRange(node.ContentRange),
hasPayload: true,
}, true
}
if document == nil || node.Kind != splice.KindFencedCode || !node.TopLevel {
return MathExpression{}, false
}
block, info, _, ok := document.FencedBlockMetadata(node.ID)
if !ok || info != "math" || block.Range.Start >= block.Range.End {
return MathExpression{}, false
}
code, codeOK := document.FencedCodeSource(node.ID)
payload := Range{}
if codeOK {
payload = publicRange(code.ContentRange)
}
return MathExpression{
id: publicNodeID(node.ID),
style: MathExpressionFencedBlock,
sourceRange: publicRange(block.Range),
payloadRange: payload,
hasPayload: codeOK && payload.Start < payload.End,
}, true
}
func publicMathExpressionStyle(style splice.MathExpressionStyle) (MathExpressionStyle, bool) {
switch style {
case splice.MathExpressionInlineDollar:
return MathExpressionInlineDollar, true
case splice.MathExpressionInlineBacktick:
return MathExpressionInlineBacktick, true
case splice.MathExpressionBlockDollar:
return MathExpressionBlockDollar, true
default:
return MathExpressionUnknown, false
}
}