From b8c92a56d89ba261dcccc3ce241e9e5f956466d4 Mon Sep 17 00:00:00 2001 From: diamondburned Date: Sat, 11 Jul 2020 23:37:36 -0700 Subject: [PATCH] Minor appearance tweaks and bug fixes --- go.mod | 2 +- go.sum | 2 + segments/blockquote.go | 17 +++++++- segments/embed.go | 4 ++ segments/mention.go | 92 +++++++++++++++++------------------------- 5 files changed, 59 insertions(+), 58 deletions(-) diff --git a/go.mod b/go.mod index c6e2906..21db12d 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.14 require ( github.com/diamondburned/arikawa v0.10.2 github.com/diamondburned/cchat v0.0.43 - github.com/diamondburned/ningen v0.1.1-0.20200711215126-d4b8a17e818d + github.com/diamondburned/ningen v0.1.1-0.20200712031630-349ee2c3f01c github.com/dustin/go-humanize v1.0.0 github.com/go-test/deep v1.0.6 github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum index c449ac2..4c2d682 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/diamondburned/ningen v0.1.1-0.20200708211706-57c712372ede h1:qRmfQCOS github.com/diamondburned/ningen v0.1.1-0.20200708211706-57c712372ede/go.mod h1:FNezDLQIhoDS+RkXLSQ7dJNrt6BW/nVl1krzDgWMQwg= github.com/diamondburned/ningen v0.1.1-0.20200711215126-d4b8a17e818d h1:XgG/KRbAwu8v2/YZWimjXo0dgdD69E38ollCfbFtU7s= github.com/diamondburned/ningen v0.1.1-0.20200711215126-d4b8a17e818d/go.mod h1:NVneOJDUDEIC3cnyeh2vpeAPVtBdC2Kcy+uwDy4o2qk= +github.com/diamondburned/ningen v0.1.1-0.20200712031630-349ee2c3f01c h1:CpYhIGiRzee7Jm0H4c0fLvRe/08QitDNo8KHYtrOmFE= +github.com/diamondburned/ningen v0.1.1-0.20200712031630-349ee2c3f01c/go.mod h1:NVneOJDUDEIC3cnyeh2vpeAPVtBdC2Kcy+uwDy4o2qk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= diff --git a/segments/blockquote.go b/segments/blockquote.go index d690172..a886924 100644 --- a/segments/blockquote.go +++ b/segments/blockquote.go @@ -34,8 +34,15 @@ func (r *TextRenderer) blockquote(n *ast.Blockquote, enter bool) ast.WalkStatus }) } - // Write the end of the segment. - seg.end = r.buf.Len() + // Search until the last non-whitespace. + var i = r.buf.Len() - 1 + for bytes := r.buf.Bytes(); i > 0 && isSpace(bytes[i]); i-- { + } + + // The ending will have a trailing character that's not covered, so + // we'll need to do that ourselves. + // End the codeblock at that non-whitespace location. + seg.end = i + 1 r.append(seg) } @@ -47,3 +54,9 @@ func (b BlockquoteSegment) Bounds() (start, end int) { } func (b BlockquoteSegment) Quote() {} + +// isSpace is a quick function that matches if the byte is a space, a new line +// or a return carriage. +func isSpace(b byte) bool { + return b == ' ' || b == '\n' || b == '\r' +} diff --git a/segments/embed.go b/segments/embed.go index a6979e1..4a1ae23 100644 --- a/segments/embed.go +++ b/segments/embed.go @@ -168,6 +168,7 @@ type AvatarSegment struct { start int url string text string + size int } func EmbedAuthor(start int, a discord.EmbedAuthor) AvatarSegment { @@ -198,6 +199,9 @@ func (a AvatarSegment) Avatar() (url string) { // AvatarSize returns the size of a small emoji. func (a AvatarSegment) AvatarSize() int { + if a.size > 0 { + return a.size + } return InlineEmojiSize } diff --git a/segments/mention.go b/segments/mention.go index 69c455d..e0487fa 100644 --- a/segments/mention.go +++ b/segments/mention.go @@ -3,11 +3,10 @@ package segments import ( "bytes" "fmt" - "sort" "strings" "github.com/diamondburned/arikawa/discord" - "github.com/diamondburned/cchat-discord/urlutils" + "github.com/diamondburned/arikawa/state" "github.com/diamondburned/cchat/text" "github.com/diamondburned/ningen/md" "github.com/yuin/goldmark/ast" @@ -15,47 +14,12 @@ import ( 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 -} - type MentionSegment struct { start, end int *md.Mention - // only non-nil if GuildUser is not nil and is in a guild. - roles []roleInfo + store state.Store + guild discord.Snowflake } var ( @@ -66,14 +30,17 @@ var ( func (r *TextRenderer) mention(n *md.Mention, enter bool) ast.WalkStatus { if enter { - var seg = MentionSegment{Mention: n} + var seg = MentionSegment{ + Mention: n, + store: r.store, + guild: r.msg.GuildID, + } switch { case n.Channel != nil: seg.start, seg.end = r.writeString("#" + n.Channel.Name) case n.GuildUser != nil: seg.start, seg.end = r.writeString("@" + n.GuildUser.Username) - seg.roles = r.userRoles(n.GuildUser) // get roles as well case n.GuildRole != nil: seg.start, seg.end = r.writeString("@" + n.GuildRole.Name) default: @@ -96,12 +63,14 @@ func (m MentionSegment) Bounds() (start, end int) { 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.GuildUser != nil && m.GuildUser.Member != nil: + g, err := m.store.Guild(m.guild) + if err != nil { + return blurple } + + return discord.MemberColor(*g, *m.GuildUser.Member).Uint32() + case m.GuildRole != nil && m.GuildRole.Color > 0: return m.GuildRole.Color.Uint32() } @@ -148,16 +117,24 @@ func (m MentionSegment) userInfo() text.Rich { var segment text.Rich // Make a large avatar if there's one. - if m.GuildUser != nil { - segment.Segments = append(segment.Segments, AvatarSegment{ + if m.GuildUser.Avatar != "" { + segmentadd(&segment, AvatarSegment{ start: 0, - url: urlutils.AvatarURL(m.GuildUser.AvatarURL()), + url: m.GuildUser.AvatarURL(), // full URL text: "Avatar", + size: 72, // large }) // Space out. content.WriteByte(' ') } + // We should have a member if there's nil. Sometimes when the members aren't + // prefetched, the markdown parser can miss them. We can check this again. + if m.GuildUser.Member == nil && m.guild.Valid() { + // Best effort; fine if it's nil. + m.GuildUser.Member, _ = m.store.Member(m.guild, m.GuildUser.ID) + } + // 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) @@ -180,18 +157,23 @@ func (m MentionSegment) userInfo() text.Rich { content.WriteString(m.GuildUser.Discriminator) } - // Write roles, if any. - if len(m.roles) > 0 { + // Write extra information if any. + if m.GuildUser.Member != nil && len(m.GuildUser.Member.RoleIDs) > 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") + content.WriteString("\n\n--- Roles ---") + + for _, id := range m.GuildUser.Member.RoleIDs { + r, err := m.store.Role(m.guild, id) + if err != nil { + continue + } - 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)) + start, end := writestringbuf(&content, "@"+r.Name) + segmentadd(&segment, NewColoredSegment(start, end, r.Color.Uint32())) } }