Added message reference read support

This commit is contained in:
diamondburned 2020-12-30 18:58:36 -08:00
parent 6beff52250
commit 96e97aa117
6 changed files with 99 additions and 25 deletions

View File

@ -56,13 +56,6 @@ func richMember(
start, end = segutil.Write(rich, displayName)
// Update the color.
if c := discord.MemberColor(g, m); c > 0 {
rich.Segments = append(rich.Segments,
colored.NewSegment(start, end, c.Uint32()),
)
}
// Append the bot prefix if the user is a bot.
if m.User.Bot {
rich.Content += " "
@ -157,6 +150,7 @@ func (a *Author) AddMessageReference(msgref discord.Message, s *state.Instance)
m, err := s.Cabinet.Member(g.ID, msgref.Author.ID)
if err != nil {
a.addAuthorReference(msgref, s)
s.MemberState.RequestMember(msgref.GuildID, msgref.Author.ID)
return
}

View File

@ -9,6 +9,7 @@ import (
"github.com/diamondburned/cchat-discord/internal/discord/state"
"github.com/diamondburned/cchat-discord/internal/segments"
"github.com/diamondburned/cchat-discord/internal/segments/mention"
"github.com/diamondburned/cchat-discord/internal/segments/reference"
"github.com/diamondburned/cchat/text"
)
@ -101,6 +102,11 @@ func NewMessageUpdateContent(msg discord.Message, s *state.Instance) Message {
func NewMessageUpdateAuthor(
msg discord.Message, member discord.Member, g discord.Guild, s *state.Instance) Message {
author := NewGuildMember(member, g, s)
if ref := ReferencedMessage(msg, s, true); ref != nil {
author.AddMessageReference(*ref, s)
}
return Message{
messageHeader: newHeader(msg),
author: NewGuildMember(member, g, s),
@ -156,8 +162,25 @@ func NewDirectMessage(m discord.Message, s *state.Instance) Message {
}
func NewMessage(m discord.Message, s *state.Instance, author Author) Message {
var content text.Rich
if ref := ReferencedMessage(m, s, true); ref != nil {
// TODO: markup support
var refmsg = "> " + ref.Content
if len(refmsg) > 120 {
refmsg = refmsg[:120] + "..."
}
content.Content = refmsg + "\n"
content.Segments = []text.Segment{
reference.NewMessageSegment(0, len(refmsg), ref.ID),
}
author.AddMessageReference(*ref, s)
}
// Render the message content.
var content = segments.ParseMessage(&m, s.Cabinet)
segments.ParseMessageRich(&content, &m, s.Cabinet)
// Request members in mentions if we're in a guild.
if m.GuildID.IsValid() {
@ -206,3 +229,23 @@ func (m Message) Nonce() string {
func (m Message) Mentioned() bool {
return m.mentioned
}
// ReferencedMessage searches for the referenced message if needed.
func ReferencedMessage(m discord.Message, s *state.Instance, wait bool) (reply *discord.Message) {
if m.ReferencedMessage != nil {
return m.ReferencedMessage
}
// Deleted or does not exist.
if m.Reference == nil || !m.Reference.MessageID.IsValid() {
return nil
}
if !wait {
reply, _ = s.Cabinet.Message(m.Reference.ChannelID, m.Reference.MessageID)
} else {
reply, _ = s.Message(m.Reference.ChannelID, m.Reference.MessageID)
}
return
}

View File

@ -18,10 +18,19 @@ import (
)
func ParseMessage(m *discord.Message, s store.Cabinet) text.Rich {
var rich text.Rich
ParseMessageRich(&rich, m, s)
return rich
}
func ParseMessageRich(rich *text.Rich, m *discord.Message, s store.Cabinet) {
var content = []byte(m.Content)
var node = md.ParseWithMessage(content, s, m, true)
r := renderer.New(content, node)
r.Buffer.Grow(len(rich.Content))
r.Buffer.WriteString(rich.Content)
// Register the needed states for some renderers.
r.WithState(m, s)
// Render the main message body.
@ -30,13 +39,16 @@ func ParseMessage(m *discord.Message, s store.Cabinet) text.Rich {
embed.RenderAttachments(r, m.Attachments)
embed.RenderEmbeds(r, m.Embeds, m, s)
return text.Rich{
Content: r.String(),
Segments: r.Segments,
}
rich.Content = r.String()
rich.Segments = append(rich.Segments, r.Segments...)
}
func ParseWithMessage(b []byte, m *discord.Message, s store.Cabinet, msg bool) text.Rich {
node := md.ParseWithMessage(b, s, m, msg)
return renderer.RenderNode(b, node)
}
func ParseWithMessageRich(b []byte, m *discord.Message, s store.Cabinet, msg bool) text.Rich {
node := md.ParseWithMessage(b, s, m, msg)
return renderer.RenderNode(b, node)
}

View File

@ -1,6 +1,7 @@
package mention
import (
"github.com/diamondburned/arikawa/v2/discord"
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
@ -55,7 +56,7 @@ func (s Segment) Bounds() (start, end int) {
func (s Segment) AsColorer() text.Colorer {
switch {
case s.User != nil:
case s.User != nil && s.User.HasColor():
return s.User
case s.Role != nil:
return s.Role
@ -81,3 +82,23 @@ func (s Segment) AsMentioner() text.Mentioner {
}
return nil
}
func MemberColor(guild discord.Guild, member discord.Member) (c uint32, ok bool) {
var pos int
for _, r := range guild.Roles {
for _, mr := range member.RoleIDs {
if mr != r.ID {
continue
}
if r.Color > 0 && r.Position > pos {
c = r.Color.Uint32()
ok = true
pos = r.Position
}
}
}
return
}

View File

@ -9,6 +9,7 @@ import (
"github.com/diamondburned/cchat-discord/internal/segments/colored"
"github.com/diamondburned/cchat-discord/internal/segments/inline"
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
"github.com/diamondburned/cchat-discord/internal/urlutils"
"github.com/diamondburned/cchat/text"
"github.com/diamondburned/cchat/utils/empty"
"github.com/diamondburned/ningen/v2"
@ -63,7 +64,7 @@ func (m NameSegment) AsAvatarer() text.Avatarer { return &m.um }
// AsColorer only returns User if the user actually has a colored role.
func (m NameSegment) AsColorer() text.Colorer {
if m.um.HasColor() {
return &m.um
return m.um
}
return nil
}
@ -82,8 +83,7 @@ var (
_ text.Mentioner = (*User)(nil)
)
// NewUser creates a new user mention. If state is of type *ningen.State, then
// it'll fetch additional information asynchronously.
// NewUser creates a new user mention.
func NewUser(store store.Cabinet, guild discord.GuildID, guser discord.GuildUser) *User {
if guser.Member == nil {
m, err := store.Member(guild, guser.ID)
@ -111,6 +111,7 @@ func NewUser(store store.Cabinet, guild discord.GuildID, guser discord.GuildUser
func (um *User) WithState(state *ningen.State) {
um.ningen = state
um.store = state.Cabinet
}
// HasColor returns true if the current user has a color.
@ -125,7 +126,8 @@ func (um User) HasColor() bool {
return false
}
return discord.MemberColor(*g, um.Member) > 0
_, ok := MemberColor(*g, um.Member)
return ok
}
func (um User) Color() uint32 {
@ -134,12 +136,12 @@ func (um User) Color() uint32 {
return colored.Blurple
}
var color = discord.MemberColor(*g, um.Member)
if color == 0 {
color, ok := MemberColor(*g, um.Member)
if !ok {
return colored.Blurple
}
return text.SolidColor(color.Uint32())
return text.SolidColor(color)
}
func (um User) AvatarSize() int {
@ -154,7 +156,7 @@ func (um User) AvatarText() string {
}
func (um User) Avatar() (url string) {
return um.Member.User.AvatarURL()
return urlutils.AvatarURL(um.Member.User.AvatarURL())
}
func (um User) MentionInfo() text.Rich {

View File

@ -21,6 +21,8 @@ func Register(kind ast.NodeKind, r Renderer) {
renderers[kind] = r
}
var smallRenderers = map[ast.NodeKind]Renderer{}
// Parse parses the raw Markdown bytes into a rich text.
func Parse(b []byte) text.Rich {
node := md.Parse(b)
@ -188,10 +190,10 @@ func (r *Text) RenderNode(n ast.Node, enter bool) (ast.WalkStatus, error) {
switch n := n.(type) {
case *ast.Document:
case *ast.Paragraph:
if !enter {
// TODO: investigate
// r.Buffer.WriteByte('\n')
}
// if !enter {
// TODO: investigate
// r.Buffer.WriteByte('\n')
// }
case *ast.String:
if enter {
r.Buffer.Write(n.Value)