cchat-discord/internal/segments/inline/inline.go

128 lines
3.0 KiB
Go

package inline
import (
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen/v2/md"
"github.com/yuin/goldmark/ast"
)
func init() {
renderer.Register(md.KindInline, inline)
}
// inline parses an inline node. This method at the moment will always create a
// new segment for overlapping attributes.
func inline(r *renderer.Text, node ast.Node, enter bool) ast.WalkStatus {
n := node.(*md.Inline)
// For instructions on how this works, refer to inline_attr.jpg.
// Pop the last segment if it's not empty.
if !r.Inlines.Empty() {
r.Inlines.End = r.Buffer.Len()
// Only use this section if the length is not zero.
if r.Inlines.Start != r.Inlines.End {
r.Append(NewSegmentFromState(r.Inlines))
}
}
if enter {
r.Inlines.Add(n.Attr)
} else {
r.Inlines.Remove(n.Attr)
}
// Update the start pointer of the current segment.
r.Inlines.Start = r.Buffer.Len()
return ast.WalkContinue
}
type Attribute text.Attribute
var _ text.Attributor = (*Attribute)(nil)
func (attr Attribute) Attribute() text.Attribute {
return text.Attribute(attr)
}
// DimSuffix creates a string with the suffix dimmed.
func DimSuffix(prefix, suffix string) text.Rich {
return text.Rich{
Content: prefix + suffix,
Segments: []text.Segment{
Segment{
start: len(prefix),
end: len(prefix) + len(suffix),
attributes: Attribute(text.AttributeDimmed),
},
},
}
}
type Segment struct {
empty.TextSegment
start, end int
attributes Attribute
}
// NewSegmentFromState creates a new rich text segment from the renderer's
// inline attribute state.
func NewSegmentFromState(state renderer.InlineState) Segment {
return NewSegmentFromMD(state.Start, state.End, state.Attributes)
}
// NewSegmentFromMD creates a new rich text segment from the start, end indices
// and the markdown inline attributes.
func NewSegmentFromMD(start, end int, attr md.Attribute) Segment {
var seg = Segment{
start: start,
end: end,
}
if attr.Has(md.AttrBold) {
seg.attributes |= Attribute(text.AttributeBold)
}
if attr.Has(md.AttrItalics) {
seg.attributes |= Attribute(text.AttributeItalics)
}
if attr.Has(md.AttrUnderline) {
seg.attributes |= Attribute(text.AttributeUnderline)
}
if attr.Has(md.AttrStrikethrough) {
seg.attributes |= Attribute(text.AttributeStrikethrough)
}
if attr.Has(md.AttrSpoiler) {
seg.attributes |= Attribute(text.AttributeSpoiler)
}
if attr.Has(md.AttrMonospace) {
seg.attributes |= Attribute(text.AttributeMonospace)
}
return seg
}
func NewSegment(start, end int, attrs ...text.Attribute) Segment {
var attr = text.AttributeNormal
for _, a := range attrs {
attr |= a
}
return Segment{
start: start,
end: end,
attributes: Attribute(attr),
}
}
var _ text.Segment = (*Segment)(nil)
func (i Segment) Bounds() (start, end int) {
return i.start, i.end
}
func (i Segment) AsAttributor() text.Attributor {
return i.attributes
}