1
0
Fork 0
mirror of https://github.com/diamondburned/cchat-discord.git synced 2024-11-01 12:24:15 +00:00
cchat-discord/segments/mention.go

218 lines
4.9 KiB
Go
Raw Normal View History

2020-06-19 01:00:24 +00:00
package segments
import (
"bytes"
"fmt"
"sort"
"strings"
"github.com/diamondburned/arikawa/discord"
"github.com/diamondburned/cchat-discord/urlutils"
2020-06-19 01:00:24 +00:00
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/ningen/md"
"github.com/yuin/goldmark/ast"
)
const blurple = 0x7289DA
type roleInfo struct {
name string
color uint32
position int // used for sorting
}
func (r *TextRenderer) userRoles(user *discord.GuildUser) []roleInfo {
if user.Member == nil || r.msg == nil || !r.msg.GuildID.Valid() {
return nil
}
var roles = make([]roleInfo, 0, len(user.Member.RoleIDs))
for _, roleID := range user.Member.RoleIDs {
r, err := r.store.Role(r.msg.GuildID, roleID)
if err != nil {
continue
}
roles = append(roles, roleInfo{
name: r.Name,
color: r.Color.Uint32(), // default 0
position: r.Position,
})
}
// Sort the roles so the first roles stay in front. We need to do this to
// both render properly and to get the right role color.
sort.Slice(roles, func(i, j int) bool {
return roles[i].position < roles[j].position
})
return roles
}
2020-06-19 01:00:24 +00:00
type MentionSegment struct {
start, end int
*md.Mention
// only non-nil if GuildUser is not nil and is in a guild.
roles []roleInfo
2020-06-19 01:00:24 +00:00
}
var (
_ text.Segment = (*MentionSegment)(nil)
_ text.Colorer = (*MentionSegment)(nil)
_ text.Mentioner = (*MentionSegment)(nil)
)
2020-06-19 01:00:24 +00:00
func (r *TextRenderer) mention(n *md.Mention, enter bool) ast.WalkStatus {
if enter {
var seg = MentionSegment{Mention: n}
2020-06-19 01:00:24 +00:00
switch {
case n.Channel != nil:
seg.start, seg.end = r.writeString("#" + n.Channel.Name)
2020-06-19 01:00:24 +00:00
case n.GuildUser != nil:
seg.start, seg.end = r.writeString("@" + n.GuildUser.Username)
seg.roles = r.userRoles(n.GuildUser) // get roles as well
2020-06-19 01:00:24 +00:00
case n.GuildRole != nil:
seg.start, seg.end = r.writeString("@" + n.GuildRole.Name)
default:
// Unexpected error; skip.
return ast.WalkSkipChildren
2020-06-19 01:00:24 +00:00
}
r.append(seg)
}
return ast.WalkContinue
}
func (m MentionSegment) Bounds() (start, end int) {
return m.start, m.end
}
// Color tries to return the color of the mention segment, or it returns the
// usual blurple if none.
func (m MentionSegment) Color() uint32 {
// Try digging through what we have for a color.
switch {
case len(m.roles) > 0:
for _, role := range m.roles {
if role.color > 0 {
return role.color
}
}
case m.GuildRole != nil && m.GuildRole.Color > 0:
return m.GuildRole.Color.Uint32()
}
return blurple
}
2020-06-19 01:00:24 +00:00
// TODO
func (m MentionSegment) MentionInfo() text.Rich {
switch {
case m.Channel != nil:
return m.channelInfo()
case m.GuildUser != nil:
return m.userInfo()
case m.GuildRole != nil:
return m.roleInfo()
}
// Unknown; return an empty text.
2020-06-19 01:00:24 +00:00
return text.Rich{}
}
func (m MentionSegment) channelInfo() text.Rich {
content := strings.Builder{}
content.WriteByte('#')
content.WriteString(m.Channel.Name)
if m.Channel.NSFW {
content.WriteString(" (NSFW)")
}
if m.Channel.Topic != "" {
content.WriteByte('\n')
content.WriteString(m.Channel.Topic)
}
return text.Rich{
Content: content.String(),
}
}
func (m MentionSegment) userInfo() text.Rich {
var content bytes.Buffer
var segment text.Rich
// Make a large avatar if there's one.
if m.GuildUser != nil {
segment.Segments = append(segment.Segments, AvatarSegment{
start: 0,
url: urlutils.AvatarURL(m.GuildUser.AvatarURL()),
text: "Avatar",
})
// Space out.
content.WriteByte(' ')
}
// Write the nickname if there's one; else, write the username only.
if m.GuildUser.Member != nil && m.GuildUser.Member.Nick != "" {
content.WriteString(m.GuildUser.Member.Nick)
content.WriteByte(' ')
start, end := writestringbuf(&content, fmt.Sprintf(
"(%s#%s)",
m.GuildUser.Username,
m.GuildUser.Discriminator,
))
segmentadd(&segment, InlineSegment{
start: start,
end: end,
attributes: text.AttrDimmed,
})
} else {
content.WriteString(m.GuildUser.Username)
content.WriteByte('#')
content.WriteString(m.GuildUser.Discriminator)
}
// Write roles, if any.
if len(m.roles) > 0 {
// Write a prepended new line, as role writes will always prepend a new
// line. This is to prevent a trailing new line.
content.WriteString("\n---\nRoles")
for _, role := range m.roles {
// Prepend a new line before each item.
content.WriteByte('\n')
// Write exactly the role name, then grab the segment and color it.
start, end := writestringbuf(&content, role.name)
segmentadd(&segment, NewColoredSegment(start, end, role.color))
}
}
// Assign the written content into the text segment and return it.
segment.Content = content.String()
return segment
}
func (m MentionSegment) roleInfo() text.Rich {
// We don't have much to write here.
var segment = text.Rich{
Content: m.GuildRole.Name,
}
// Maybe add a color if we have any.
if c := m.GuildRole.Color.Uint32(); c > 0 {
segment.Segments = []text.Segment{
NewColored(len(m.GuildRole.Name), m.GuildRole.Color.Uint32()),
}
}
return segment
}