From c1296d9822b3129f7f2fe38bda037b5e811b9a9d Mon Sep 17 00:00:00 2001 From: Cynthia Foxwell Date: Sun, 16 Jul 2023 14:58:14 -0600 Subject: [PATCH] history commands --- commands/history.go | 135 ++++++++++++++++++++++++++++++++++++++++++++ commands/main.go | 20 +++++++ events/messages.go | 12 +++- lib/messages.go | 133 ++++++++++++++++++++++++------------------- 4 files changed, 239 insertions(+), 61 deletions(-) create mode 100644 commands/history.go diff --git a/commands/history.go b/commands/history.go new file mode 100644 index 0000000..98fa9bf --- /dev/null +++ b/commands/history.go @@ -0,0 +1,135 @@ +package commands + +import ( + "fmt" + "math" + "strconv" + "strings" + + "github.com/Cynosphere/comcord/lib" + "github.com/Cynosphere/comcord/state" + "github.com/bwmarrin/discordgo" +) + +func GetHistory(session *discordgo.Session, limit int, channel string) { + messages, err := session.ChannelMessages(channel, 100, "", "", "") + if err != nil { + fmt.Print("\n\r") + return + } + + for i, j := 0, len(messages) - 1; i < j; i, j = i + 1, j - 1 { + messages[i], messages[j] = messages[j], messages[i] + } + + fmt.Print("--Beginning-Review", strings.Repeat("-", 62), "\n\r") + + lines := make([]string, 0) + for _, msg := range messages { + msgLines := lib.ProcessMessage(session, msg, lib.MessageOptions{NoColor: true, InHistory: true}) + for _, line := range msgLines { + lines = append(lines, line) + } + } + + length := len(lines) + startIndex := int(math.Max(float64(0), float64(length - limit))) + for _, line := range lines[startIndex:] { + fmt.Print(line) + } + + fmt.Print("--Review-Complete", strings.Repeat("-", 63), "\n\r") +} + +func HistoryCommand(session *discordgo.Session) { + currentChannel := state.GetCurrentChannel() + if currentChannel == "" { + fmt.Print("\n\r") + return + } + + GetHistory(session, 20, currentChannel) +} + +func ExtendedHistoryCommand(session *discordgo.Session) { + currentChannel := state.GetCurrentChannel() + if currentChannel == "" { + fmt.Print("\n\r") + return + } + + lib.MakePrompt(session, ":lines> ", false, func(session *discordgo.Session, input string, interrupt bool) { + fmt.Print("\r") + limit, err := strconv.Atoi(input) + + if err != nil { + fmt.Print("\n\r") + } else { + GetHistory(session, limit, currentChannel) + } + }) +} + +func PeekHistory(session *discordgo.Session, guild, channel string) { + target := "" + + channels := GetSortedChannels(session, guild, false, false) + + for _, c := range channels { + if strings.Index(strings.ToLower(c.Name), strings.ToLower(channel)) > -1 { + target = c.ID + break + } + } + + if target == "" { + fmt.Print("\n\r") + } else { + GetHistory(session, 20, target) + } +} + +func PeekCommand(session *discordgo.Session) { + currentGuild := state.GetCurrentGuild() + if currentGuild == "" { + fmt.Print("\n\r") + return + } + + lib.MakePrompt(session, ":peek> ", false, func(session *discordgo.Session, input string, interrupt bool) { + fmt.Print("\r") + + if input != "" { + PeekHistory(session, currentGuild, input) + } + }) +} + +func CrossPeekCommand(session *discordgo.Session) { + lib.MakePrompt(session, ":guild> ", false, func(session *discordgo.Session, input string, interrupt bool) { + fmt.Print("\r") + + if input != "" { + targetGuild := "" + + for _, guild := range session.State.Guilds { + if strings.Index(strings.ToLower(guild.Name), strings.ToLower(input)) > -1 { + targetGuild = guild.ID + break; + } + } + + if targetGuild == "" { + fmt.Print("\n\r") + } else { + lib.MakePrompt(session, ":peek> ", false, func(session *discordgo.Session, input string, interrupt bool) { + fmt.Print("\r") + + if input != "" { + PeekHistory(session, targetGuild, input) + } + }) + } + } + }) +} diff --git a/commands/main.go b/commands/main.go index 143737b..e9f4a1f 100644 --- a/commands/main.go +++ b/commands/main.go @@ -56,6 +56,26 @@ func Setup() { Run: ListUsersCommand, Description: "who is in channel", } + + commandMap["r"] = Command{ + Run: HistoryCommand, + Description: "channel history", + } + + commandMap["R"] = Command{ + Run: ExtendedHistoryCommand, + Description: "extended history", + } + + commandMap["p"] = Command{ + Run: PeekCommand, + Description: "peek at channel", + } + + commandMap["P"] = Command{ + Run: CrossPeekCommand, + Description: "cross-guild peek", + } } func GetCommand(key string) (Command, bool) { diff --git a/events/messages.go b/events/messages.go index dfc0d76..343d9c6 100644 --- a/events/messages.go +++ b/events/messages.go @@ -1,6 +1,8 @@ package events import ( + "fmt" + "github.com/Cynosphere/comcord/lib" "github.com/Cynosphere/comcord/state" "github.com/bwmarrin/discordgo" @@ -21,7 +23,10 @@ func MessageCreate(session *discordgo.Session, msg *discordgo.MessageCreate) { if state.IsInPrompt() { state.AddMessageToQueue(msg.Message) } else { - lib.ProcessMessage(session, msg.Message, lib.MessageOptions{NoColor: state.HasNoColor()}) + lines := lib.ProcessMessage(session, msg.Message, lib.MessageOptions{NoColor: state.HasNoColor()}) + for _, line := range lines { + fmt.Print(line) + } } if isDM { @@ -52,7 +57,10 @@ func MessageUpdate(session *discordgo.Session, msg *discordgo.MessageUpdate) { if state.IsInPrompt() { state.AddMessageToQueue(msg.Message) } else { - lib.ProcessMessage(session, msg.Message, lib.MessageOptions{NoColor: state.HasNoColor()}) + lines := lib.ProcessMessage(session, msg.Message, lib.MessageOptions{NoColor: state.HasNoColor()}) + for _, line := range lines { + fmt.Print(line) + } } if isDM { diff --git a/lib/messages.go b/lib/messages.go index 36e31d0..b6daddd 100644 --- a/lib/messages.go +++ b/lib/messages.go @@ -35,10 +35,10 @@ type MessageOptions struct { InHistory bool } -func FormatMessage(session *discordgo.Session, options MessageOptions) { - timestamp := options.Timestamp.Format("[15:04:05]") +func FormatMessage(session *discordgo.Session, options MessageOptions) []string { + lines := make([]string, 0) - // TODO: history lines + timestamp := options.Timestamp.Format("[15:04:05]") nameLength := utf8.RuneCountInString(options.Name) + 2 stateNameLength := state.GetNameLength() @@ -102,12 +102,21 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { replyContent = replyContent[:79 - headerLength] + moreContent } - fmt.Print(replySymbol, name, replyContent, "\n\r") + lines = append(lines, replySymbol, name, replyContent, "\n\r") } if options.IsDump { if options.InHistory { - // TODO + headerLength := 80 - (utf8.RuneCountInString(options.Name) + 5) + dumpHeader := fmt.Sprintf("--- %s %s\n\r", options.Name, strings.Repeat("-", headerLength)) + + contentLines := strings.Split(options.Content, "\n") + + lines = append(lines, dumpHeader) + for _, line := range contentLines { + lines = append(lines, line + "\n\r") + } + lines = append(lines, dumpHeader) } else { wordCount := len(strings.Split(options.Content, " ")) lineCount := len(strings.Split(options.Content, "\n")) @@ -127,7 +136,7 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { str = ansi.Color(str, "yellow+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } } else { // TODO: markdown @@ -140,7 +149,7 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { name = ansi.Color(name, "red+b") } - fmt.Printf("%s %s\x07\n\r", name, content) + lines = append(lines, fmt.Sprintf("%s %s\x07\n\r", name, content)) } else if utf8.RuneCountInString(content) > 1 && (strings.HasPrefix(content, "*") && strings.HasSuffix(content, "*") && !strings.HasPrefix(content, "**") && !strings.HasSuffix(content, "**")) || (strings.HasPrefix(content, "_") && strings.HasSuffix(content, "_") && !strings.HasPrefix(content, "__") && !strings.HasSuffix(content, "__")) { @@ -150,15 +159,15 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { str = ansi.Color(str, "green+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } else if options.IsJoin { channel, err := session.State.Channel(options.Channel) if err != nil { - return + return lines } guild, err := session.State.Guild(channel.GuildID) if err != nil { - return + return lines } str := fmt.Sprintf("%s %s has joined %s", timestamp, options.Name, guild.Name) @@ -166,14 +175,14 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { str = ansi.Color(str, "yellow+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } else if options.IsPin { str := fmt.Sprintf("%s %s pinned a message to this channel", timestamp, options.Name) if !options.NoColor { str = ansi.Color(str, "yellow+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } else { nameColor := "cyan+b" if options.IsMention { @@ -194,7 +203,7 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { if options.IsMention { str = str + "\x07" } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } } @@ -205,7 +214,7 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { str = ansi.Color(str, "yellow+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } } @@ -216,7 +225,7 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { str = ansi.Color(str, "yellow+b") } - fmt.Print(str + "\n\r") + lines = append(lines, str + "\n\r") } } @@ -225,22 +234,25 @@ func FormatMessage(session *discordgo.Session, options MessageOptions) { // TODO: embeds // TODO: lines output for history + return lines } -func ProcessMessage(session *discordgo.Session, msg *discordgo.Message, options MessageOptions) { +func ProcessMessage(session *discordgo.Session, msg *discordgo.Message, options MessageOptions) []string { + lines := make([]string, 0) + channel, err := session.State.Channel(msg.ChannelID) if err != nil { - return + return lines } guild, err := session.State.Guild(channel.GuildID) if err != nil { - return + return lines } selfMember, err := session.State.Member(guild.ID, session.State.User.ID) if err != nil { - return + return lines } hasMentionedRole := false @@ -268,72 +280,75 @@ func ProcessMessage(session *discordgo.Session, msg *discordgo.Message, options currentChannel := state.GetCurrentChannel() isCurrentChannel := currentChannel == msg.ChannelID - if !isCurrentChannel && !isDM && !isPing { - return + if !isCurrentChannel && !isDM && !isPing && !options.InHistory { + return lines } - if isPing && !isCurrentChannel && !isDM { + if isPing && !isCurrentChannel && !isDM && !options.InHistory { str := fmt.Sprintf("**mentioned by %s in #%s in %s**", msg.Author.Username, channel.Name, guild.Name) - if options.NoColor { - fmt.Print(ansi.Color(str, "red+b")) - } else { - fmt.Print(str) + if !options.NoColor { + str = ansi.Color(str, "red+b") + } + str = str + "\x07\n\r" + lines = append(lines, str) + } else { + content, _ := msg.ContentWithMoreMentionsReplaced(session) + if isEdit { + content = content + " (edited)" } - fmt.Print("\x07\n\r") - return - } - content, _ := msg.ContentWithMoreMentionsReplaced(session) - if isEdit { - content = content + " (edited)" - } + isDump := REGEX_CODEBLOCK.MatchString(content) - isDump := REGEX_CODEBLOCK.MatchString(content) + if strings.Index(content, "\n") > -1 && !isDump { + for i, line := range strings.Split(content, "\n") { + options.Content = line + options.Name = msg.Author.Username + options.Channel = msg.ChannelID + options.Bot = msg.Author.Bot + options.Webhook = msg.WebhookID != "" + options.Attachments = msg.Attachments + options.Stickers = msg.StickerItems + if i == 0 { + options.Reply = msg.ReferencedMessage + } + options.IsMention = isPing + options.IsDM = isDM + options.IsJoin = msg.Type == discordgo.MessageTypeGuildMemberJoin + options.IsPin = msg.Type == discordgo.MessageTypeChannelPinnedMessage + options.IsDump = false - if strings.Index(content, "\n") > -1 && !isDump { - for i, line := range strings.Split(content, "\n") { - options.Content = line + lines = FormatMessage(session, options) + } + } else { + options.Content = content options.Name = msg.Author.Username options.Channel = msg.ChannelID options.Bot = msg.Author.Bot options.Webhook = msg.WebhookID != "" options.Attachments = msg.Attachments options.Stickers = msg.StickerItems - if i == 0 { - options.Reply = msg.ReferencedMessage - } + options.Reply = msg.ReferencedMessage options.IsMention = isPing options.IsDM = isDM options.IsJoin = msg.Type == discordgo.MessageTypeGuildMemberJoin options.IsPin = msg.Type == discordgo.MessageTypeChannelPinnedMessage - options.IsDump = false + options.IsDump = isDump - FormatMessage(session, options) + lines = FormatMessage(session, options) } - } else { - options.Content = content - options.Name = msg.Author.Username - options.Channel = msg.ChannelID - options.Bot = msg.Author.Bot - options.Webhook = msg.WebhookID != "" - options.Attachments = msg.Attachments - options.Stickers = msg.StickerItems - options.Reply = msg.ReferencedMessage - options.IsMention = isPing - options.IsDM = isDM - options.IsJoin = msg.Type == discordgo.MessageTypeGuildMemberJoin - options.IsPin = msg.Type == discordgo.MessageTypeChannelPinnedMessage - options.IsDump = isDump - - FormatMessage(session, options) } + + return lines } func ProcessQueue(session *discordgo.Session) { queue := state.GetMessageQueue() for _, msg := range queue { - ProcessMessage(session, msg, MessageOptions{NoColor: state.HasNoColor()}) + lines := ProcessMessage(session, msg, MessageOptions{NoColor: state.HasNoColor()}) + for _, line := range lines { + fmt.Print(line) + } } state.EmptyMessageQueue()