2020-06-19 01:00:24 +00:00
|
|
|
package segments
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/diamondburned/cchat/text"
|
|
|
|
"github.com/diamondburned/ningen/md"
|
|
|
|
"github.com/yuin/goldmark/ast"
|
|
|
|
)
|
|
|
|
|
|
|
|
type inlineState struct {
|
|
|
|
// TODO: use a stack to allow overlapping
|
|
|
|
InlineSegment
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *inlineState) add(attr md.Attribute) {
|
|
|
|
if attr.Has(md.AttrBold) {
|
|
|
|
i.attributes |= text.AttrBold
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrItalics) {
|
|
|
|
i.attributes |= text.AttrItalics
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrUnderline) {
|
|
|
|
i.attributes |= text.AttrUnderline
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrStrikethrough) {
|
|
|
|
i.attributes |= text.AttrStrikethrough
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrSpoiler) {
|
|
|
|
i.attributes |= text.AttrSpoiler
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrMonospace) {
|
|
|
|
i.attributes |= text.AttrMonospace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *inlineState) remove(attr md.Attribute) {
|
|
|
|
if attr.Has(md.AttrBold) {
|
|
|
|
i.attributes &= ^text.AttrBold
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrItalics) {
|
|
|
|
i.attributes &= ^text.AttrItalics
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrUnderline) {
|
|
|
|
i.attributes &= ^text.AttrUnderline
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrStrikethrough) {
|
|
|
|
i.attributes &= ^text.AttrStrikethrough
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrSpoiler) {
|
|
|
|
i.attributes &= ^text.AttrSpoiler
|
|
|
|
}
|
|
|
|
if attr.Has(md.AttrMonospace) {
|
|
|
|
i.attributes &= ^text.AttrMonospace
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i inlineState) copy() InlineSegment {
|
|
|
|
return i.InlineSegment
|
|
|
|
}
|
|
|
|
|
|
|
|
type InlineSegment struct {
|
|
|
|
start, end int
|
|
|
|
attributes text.Attribute
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ text.Attributor = (*InlineSegment)(nil)
|
|
|
|
|
|
|
|
// inline parses an inline node. This method at the moment will always create a
|
|
|
|
// new segment for overlapping attributes.
|
|
|
|
func (r *TextRenderer) inline(n *md.Inline, enter bool) ast.WalkStatus {
|
|
|
|
// For instructions on how this works, refer to inline_attr.jpg.
|
|
|
|
|
|
|
|
// Pop the last segment if it's not empty.
|
|
|
|
if !r.inls.empty() {
|
2020-07-08 08:35:30 +00:00
|
|
|
r.inls.end = r.buf.Len()
|
2020-06-19 01:00:24 +00:00
|
|
|
|
|
|
|
// Only use this section if the length is not zero.
|
|
|
|
if r.inls.start != r.inls.end {
|
|
|
|
r.append(r.inls.copy())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if enter {
|
|
|
|
r.inls.add(n.Attr)
|
|
|
|
} else {
|
|
|
|
r.inls.remove(n.Attr)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the start pointer of the current segment.
|
2020-07-08 08:35:30 +00:00
|
|
|
r.inls.start = r.buf.Len()
|
2020-06-19 01:00:24 +00:00
|
|
|
|
|
|
|
return ast.WalkContinue
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i InlineSegment) Bounds() (start, end int) {
|
|
|
|
return i.start, i.end
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i InlineSegment) Attribute() text.Attribute {
|
|
|
|
return i.attributes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i InlineSegment) empty() bool {
|
|
|
|
return i.attributes == 0 || i.start < i.end
|
|
|
|
}
|