Added message reference read support
This commit is contained in:
parent
6beff52250
commit
96e97aa117
|
@ -56,13 +56,6 @@ func richMember(
|
||||||
|
|
||||||
start, end = segutil.Write(rich, displayName)
|
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.
|
// Append the bot prefix if the user is a bot.
|
||||||
if m.User.Bot {
|
if m.User.Bot {
|
||||||
rich.Content += " "
|
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)
|
m, err := s.Cabinet.Member(g.ID, msgref.Author.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.addAuthorReference(msgref, s)
|
a.addAuthorReference(msgref, s)
|
||||||
|
s.MemberState.RequestMember(msgref.GuildID, msgref.Author.ID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/diamondburned/cchat-discord/internal/discord/state"
|
"github.com/diamondburned/cchat-discord/internal/discord/state"
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments"
|
"github.com/diamondburned/cchat-discord/internal/segments"
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments/mention"
|
"github.com/diamondburned/cchat-discord/internal/segments/mention"
|
||||||
|
"github.com/diamondburned/cchat-discord/internal/segments/reference"
|
||||||
"github.com/diamondburned/cchat/text"
|
"github.com/diamondburned/cchat/text"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -101,6 +102,11 @@ func NewMessageUpdateContent(msg discord.Message, s *state.Instance) Message {
|
||||||
func NewMessageUpdateAuthor(
|
func NewMessageUpdateAuthor(
|
||||||
msg discord.Message, member discord.Member, g discord.Guild, s *state.Instance) Message {
|
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{
|
return Message{
|
||||||
messageHeader: newHeader(msg),
|
messageHeader: newHeader(msg),
|
||||||
author: NewGuildMember(member, g, s),
|
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 {
|
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.
|
// 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.
|
// Request members in mentions if we're in a guild.
|
||||||
if m.GuildID.IsValid() {
|
if m.GuildID.IsValid() {
|
||||||
|
@ -206,3 +229,23 @@ func (m Message) Nonce() string {
|
||||||
func (m Message) Mentioned() bool {
|
func (m Message) Mentioned() bool {
|
||||||
return m.mentioned
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -18,10 +18,19 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseMessage(m *discord.Message, s store.Cabinet) text.Rich {
|
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 content = []byte(m.Content)
|
||||||
var node = md.ParseWithMessage(content, s, m, true)
|
var node = md.ParseWithMessage(content, s, m, true)
|
||||||
|
|
||||||
r := renderer.New(content, node)
|
r := renderer.New(content, node)
|
||||||
|
r.Buffer.Grow(len(rich.Content))
|
||||||
|
r.Buffer.WriteString(rich.Content)
|
||||||
|
|
||||||
// Register the needed states for some renderers.
|
// Register the needed states for some renderers.
|
||||||
r.WithState(m, s)
|
r.WithState(m, s)
|
||||||
// Render the main message body.
|
// 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.RenderAttachments(r, m.Attachments)
|
||||||
embed.RenderEmbeds(r, m.Embeds, m, s)
|
embed.RenderEmbeds(r, m.Embeds, m, s)
|
||||||
|
|
||||||
return text.Rich{
|
rich.Content = r.String()
|
||||||
Content: r.String(),
|
rich.Segments = append(rich.Segments, r.Segments...)
|
||||||
Segments: r.Segments,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseWithMessage(b []byte, m *discord.Message, s store.Cabinet, msg bool) text.Rich {
|
func ParseWithMessage(b []byte, m *discord.Message, s store.Cabinet, msg bool) text.Rich {
|
||||||
node := md.ParseWithMessage(b, s, m, msg)
|
node := md.ParseWithMessage(b, s, m, msg)
|
||||||
return renderer.RenderNode(b, node)
|
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)
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package mention
|
package mention
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/diamondburned/arikawa/v2/discord"
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
|
"github.com/diamondburned/cchat-discord/internal/segments/renderer"
|
||||||
"github.com/diamondburned/cchat/text"
|
"github.com/diamondburned/cchat/text"
|
||||||
"github.com/diamondburned/cchat/utils/empty"
|
"github.com/diamondburned/cchat/utils/empty"
|
||||||
|
@ -55,7 +56,7 @@ func (s Segment) Bounds() (start, end int) {
|
||||||
|
|
||||||
func (s Segment) AsColorer() text.Colorer {
|
func (s Segment) AsColorer() text.Colorer {
|
||||||
switch {
|
switch {
|
||||||
case s.User != nil:
|
case s.User != nil && s.User.HasColor():
|
||||||
return s.User
|
return s.User
|
||||||
case s.Role != nil:
|
case s.Role != nil:
|
||||||
return s.Role
|
return s.Role
|
||||||
|
@ -81,3 +82,23 @@ func (s Segment) AsMentioner() text.Mentioner {
|
||||||
}
|
}
|
||||||
return nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments/colored"
|
"github.com/diamondburned/cchat-discord/internal/segments/colored"
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments/inline"
|
"github.com/diamondburned/cchat-discord/internal/segments/inline"
|
||||||
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
|
"github.com/diamondburned/cchat-discord/internal/segments/segutil"
|
||||||
|
"github.com/diamondburned/cchat-discord/internal/urlutils"
|
||||||
"github.com/diamondburned/cchat/text"
|
"github.com/diamondburned/cchat/text"
|
||||||
"github.com/diamondburned/cchat/utils/empty"
|
"github.com/diamondburned/cchat/utils/empty"
|
||||||
"github.com/diamondburned/ningen/v2"
|
"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.
|
// AsColorer only returns User if the user actually has a colored role.
|
||||||
func (m NameSegment) AsColorer() text.Colorer {
|
func (m NameSegment) AsColorer() text.Colorer {
|
||||||
if m.um.HasColor() {
|
if m.um.HasColor() {
|
||||||
return &m.um
|
return m.um
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -82,8 +83,7 @@ var (
|
||||||
_ text.Mentioner = (*User)(nil)
|
_ text.Mentioner = (*User)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewUser creates a new user mention. If state is of type *ningen.State, then
|
// NewUser creates a new user mention.
|
||||||
// it'll fetch additional information asynchronously.
|
|
||||||
func NewUser(store store.Cabinet, guild discord.GuildID, guser discord.GuildUser) *User {
|
func NewUser(store store.Cabinet, guild discord.GuildID, guser discord.GuildUser) *User {
|
||||||
if guser.Member == nil {
|
if guser.Member == nil {
|
||||||
m, err := store.Member(guild, guser.ID)
|
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) {
|
func (um *User) WithState(state *ningen.State) {
|
||||||
um.ningen = state
|
um.ningen = state
|
||||||
|
um.store = state.Cabinet
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasColor returns true if the current user has a color.
|
// HasColor returns true if the current user has a color.
|
||||||
|
@ -125,7 +126,8 @@ func (um User) HasColor() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return discord.MemberColor(*g, um.Member) > 0
|
_, ok := MemberColor(*g, um.Member)
|
||||||
|
return ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (um User) Color() uint32 {
|
func (um User) Color() uint32 {
|
||||||
|
@ -134,12 +136,12 @@ func (um User) Color() uint32 {
|
||||||
return colored.Blurple
|
return colored.Blurple
|
||||||
}
|
}
|
||||||
|
|
||||||
var color = discord.MemberColor(*g, um.Member)
|
color, ok := MemberColor(*g, um.Member)
|
||||||
if color == 0 {
|
if !ok {
|
||||||
return colored.Blurple
|
return colored.Blurple
|
||||||
}
|
}
|
||||||
|
|
||||||
return text.SolidColor(color.Uint32())
|
return text.SolidColor(color)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (um User) AvatarSize() int {
|
func (um User) AvatarSize() int {
|
||||||
|
@ -154,7 +156,7 @@ func (um User) AvatarText() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (um User) Avatar() (url 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 {
|
func (um User) MentionInfo() text.Rich {
|
||||||
|
|
|
@ -21,6 +21,8 @@ func Register(kind ast.NodeKind, r Renderer) {
|
||||||
renderers[kind] = r
|
renderers[kind] = r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var smallRenderers = map[ast.NodeKind]Renderer{}
|
||||||
|
|
||||||
// Parse parses the raw Markdown bytes into a rich text.
|
// Parse parses the raw Markdown bytes into a rich text.
|
||||||
func Parse(b []byte) text.Rich {
|
func Parse(b []byte) text.Rich {
|
||||||
node := md.Parse(b)
|
node := md.Parse(b)
|
||||||
|
@ -188,10 +190,10 @@ func (r *Text) RenderNode(n ast.Node, enter bool) (ast.WalkStatus, error) {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *ast.Document:
|
case *ast.Document:
|
||||||
case *ast.Paragraph:
|
case *ast.Paragraph:
|
||||||
if !enter {
|
// if !enter {
|
||||||
// TODO: investigate
|
// TODO: investigate
|
||||||
// r.Buffer.WriteByte('\n')
|
// r.Buffer.WriteByte('\n')
|
||||||
}
|
// }
|
||||||
case *ast.String:
|
case *ast.String:
|
||||||
if enter {
|
if enter {
|
||||||
r.Buffer.Write(n.Value)
|
r.Buffer.Write(n.Value)
|
||||||
|
|
Loading…
Reference in New Issue