diff --git a/commands/help.go b/commands/help.go index 2ed4e10..a0e10d6 100644 --- a/commands/help.go +++ b/commands/help.go @@ -4,24 +4,30 @@ import ( "fmt" "strings" + "github.com/Cynosphere/comcord/state" "github.com/bwmarrin/discordgo" - "github.com/fatih/color" + "github.com/mgutz/ansi" ) +const format string = " %s - %s%s" + func HelpCommand(session *discordgo.Session) { + noColor := state.HasNoColor() + fmt.Println("\r\nCOMcord (c)left 2023\n\r") index := 0 for key, cmd := range GetAllCommands() { - str := fmt.Sprintf(" %s - %s", key, cmd.Description) + str := fmt.Sprintf(format, key, cmd.Description, "") length := len(str) + padding := strings.Repeat(" ", 25 - length) - fmt.Print(" ") - color.Set(color.FgYellow, color.Bold) - fmt.Print(key) - color.Unset() - fmt.Printf(" - %s", cmd.Description) - fmt.Print(strings.Repeat(" ", 25 - length)) + if noColor { + fmt.Printf(format, key, cmd.Description, padding) + } else { + coloredKey := ansi.Color(key, "yellow+b") + fmt.Printf(format, coloredKey, cmd.Description, padding) + } index++ if index % 3 == 0 { diff --git a/commands/send.go b/commands/send.go index 1c50079..2244678 100644 --- a/commands/send.go +++ b/commands/send.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + "github.com/Cynosphere/comcord/lib" "github.com/Cynosphere/comcord/state" "github.com/bwmarrin/discordgo" "github.com/ergochat/readline" @@ -22,7 +23,10 @@ func SendMode(session *discordgo.Session) { length := len(session.State.User.Username) + 2 curLength := state.GetNameLength() - prompt := fmt.Sprintf("%s[%s]%s%s", ansi.ColorCode("cyan+b"), session.State.User.Username, strings.Repeat(" ", (curLength - length) + 1), ansi.ColorCode("reset")) + prompt := fmt.Sprintf("[%s]%s", session.State.User.Username, strings.Repeat(" ", (curLength - length) + 1)) + if !state.HasNoColor() { + prompt = ansi.Color(prompt, "cyan+b") + } input, _ := readline.NewFromConfig(&readline.Config{ Prompt: prompt, @@ -51,4 +55,5 @@ func SendMode(session *discordgo.Session) { // TODO: update afk state } state.SetInPrompt(false) + lib.ProcessQueue(session) } diff --git a/events/messages.go b/events/messages.go index 0b86b30..afbabb7 100644 --- a/events/messages.go +++ b/events/messages.go @@ -1,12 +1,13 @@ package events import ( + "github.com/Cynosphere/comcord/lib" "github.com/Cynosphere/comcord/state" "github.com/bwmarrin/discordgo" ) func MessageCreate(session *discordgo.Session, msg *discordgo.MessageCreate) { - if (msg.Author.ID == session.State.User.ID) { + if msg.Author.ID == session.State.User.ID { return } @@ -15,13 +16,15 @@ func MessageCreate(session *discordgo.Session, msg *discordgo.MessageCreate) { return } + isDM := channel.Type == discordgo.ChannelTypeDM || channel.Type == discordgo.ChannelTypeGroupDM + if state.IsInPrompt() { - state.AddMessageToQueue(*msg.Message) + state.AddMessageToQueue(msg.Message) } else { - // TODO + lib.ProcessMessage(session, msg.Message, lib.MessageOptions{NoColor: state.HasNoColor()}) } - if channel.Type == discordgo.ChannelTypeDM || channel.Type == discordgo.ChannelTypeGroupDM { + if isDM { state.SetLastDM(msg.ChannelID) } } diff --git a/events/ready.go b/events/ready.go index 991bbc4..91e2cc9 100644 --- a/events/ready.go +++ b/events/ready.go @@ -9,23 +9,15 @@ import ( ) func Ready(session *discordgo.Session, event *discordgo.Ready) { - fmt.Printf("\rLogged in as: %s%s (%s)%s\n\r", ansi.ColorCode("yellow"), session.State.User.Username, session.State.User.ID, ansi.ColorCode("reset")) + fmt.Printf("\rLogged in as: %s\n\r", ansi.Color(fmt.Sprintf("%s (%s)", session.State.User.Username, session.State.User.ID), "yellow")) state.SetNameLength(len(session.State.User.Username) + 2) defaultGuild := state.GetConfigValue("defaultGuild") defaultChannel := state.GetConfigValue("defaultChannel") if defaultGuild != "" { - //var guild discordgo.Guild - hasGuild := false - for _, g := range session.State.Guilds { - if g.ID == defaultGuild { - //guild = *g - hasGuild = true - break - } - } - if hasGuild { + _, err := session.State.Guild(defaultGuild) + if err == nil { if defaultChannel != "" { state.SetCurrentChannel(defaultChannel) state.SetLastChannel(defaultGuild, defaultChannel) diff --git a/lib/messages.go b/lib/messages.go new file mode 100644 index 0000000..8913581 --- /dev/null +++ b/lib/messages.go @@ -0,0 +1,209 @@ +package lib + +import ( + "fmt" + "math" + "regexp" + "strings" + "time" + + "github.com/Cynosphere/comcord/state" + "github.com/bwmarrin/discordgo" + "github.com/mgutz/ansi" +) + +var /*const*/ REGEX_CODEBLOCK = regexp.MustCompile(`(?i)\x60\x60\x60(?:([a-z0-9_+\-\.]+?)\n)?\n*([^\n].*?)\n*\x60\x60\x60`) + +type MessageOptions struct { + Content string + Name string + Channel string + Bot bool + Attachments []*discordgo.MessageAttachment + Stickers []*discordgo.Sticker + Reply *discordgo.Message + Timestamp time.Time + IsMention bool + IsDM bool + IsJoin bool + IsPin bool + IsDump bool + NoColor bool + InHistory bool +} + +func FormatMessage(session *discordgo.Session, options MessageOptions) { + + // TODO: timestamps for pin and join + + // TODO: history lines + + nameLength := len(options.Name) + 2 + stateNameLength := state.GetNameLength() + if nameLength > stateNameLength { + state.SetNameLength(nameLength) + } + + // TODO: replies + + if options.IsDump { + if options.InHistory { + // TODO + } else { + wordCount := len(strings.Split(options.Content, " ")) + lineCount := len(strings.Split(options.Content, "\n")) + wordsPlural := "" + linesPlural := "" + + if wordCount > 1 { + wordsPlural = "s" + } + if lineCount > 1 { + linesPlural = "s" + } + + str := fmt.Sprintf("<%s DUMPs in %d characters of %d word%s in %d line%s>", options.Name, len(options.Content), wordCount, wordsPlural, lineCount, linesPlural) + + if options.NoColor { + fmt.Print(str) + } + } + } else { + // TODO: markdown + + if options.IsDM { + name := fmt.Sprintf("*%s*", options.Name) + if !options.NoColor { + name = ansi.Color(name, "red+b") + } + + fmt.Printf("%s %s\x07\n\r", name, options.Content) + } else if len(options.Content) > 1 && + (strings.HasPrefix(options.Content, "*") && strings.HasSuffix(options.Content, "*") && !strings.HasPrefix(options.Content, "**") && !strings.HasSuffix(options.Content, "**")) || + (strings.HasPrefix(options.Content, "_") && strings.HasSuffix(options.Content, "_") && !strings.HasPrefix(options.Content, "__") && !strings.HasSuffix(options.Content, "__")) { + str := fmt.Sprintf("<%s %s>", options.Name, options.Content[1:len(options.Content)-1]) + + if options.NoColor { + fmt.Print(str + "\n\r") + } else { + fmt.Print(ansi.Color(str, "green+b") + "\n\r") + } + } else if options.IsJoin { + // TODO + } else if options.IsPin { + // TODO + } else { + nameColor := "cyan+b" + if options.IsMention { + nameColor = "red+b" + } else if options.Bot { + nameColor = "yellow+b" + } + + name := fmt.Sprintf("[%s]", options.Name) + if !options.NoColor { + name = ansi.Color(name, nameColor) + } + + // FIXME: where is this off by 4 actually from + padding := strings.Repeat(" ", int(math.Abs(float64(stateNameLength) - float64(nameLength) - 4))) + str := fmt.Sprintf("%s%s %s", name, padding, options.Content) + if options.IsMention { + str = str + "\x07" + } + fmt.Print(str + "\n\r") + } + } + + // TODO: attachments + + // TODO: stickers + + // TODO: links + + // TODO: embeds + + // TODO: lines output for history +} + +func ProcessMessage(session *discordgo.Session, msg *discordgo.Message, options MessageOptions) { + channel, err := session.State.Channel(msg.ChannelID) + if err != nil { + return + } + + guild, err := session.State.Guild(channel.GuildID) + if err != nil { + return + } + + selfMember, err := session.State.Member(guild.ID, session.State.User.ID) + if err != nil { + return + } + + hasMentionedRole := false + for _, role := range msg.MentionRoles { + for _, selfRole := range selfMember.Roles { + if role == selfRole { + hasMentionedRole = true + break; + } + } + } + + isDirectlyMentioned := false + for _, user := range msg.Mentions { + if user.ID == session.State.User.ID { + isDirectlyMentioned = true + break; + } + } + + isPing := msg.MentionEveryone || hasMentionedRole || isDirectlyMentioned + isDM := channel.Type == discordgo.ChannelTypeDM || channel.Type == discordgo.ChannelTypeGroupDM + + currentChannel := state.GetCurrentChannel() + isCurrentChannel := currentChannel == msg.ChannelID + + if !isCurrentChannel && !isDM && !isPing { + return + } + + if isPing && !isCurrentChannel && !isDM { + 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) + } + fmt.Print("\x07\n\r") + return + } + + content, _ := msg.ContentWithMoreMentionsReplaced(session) + options.Content = content + options.Name = msg.Author.Username + options.Channel = msg.ChannelID + options.Bot = msg.Author.Bot + 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 = REGEX_CODEBLOCK.MatchString(content) + + FormatMessage(session, options) +} + +func ProcessQueue(session *discordgo.Session) { + queue := state.GetMessageQueue() + + for _, msg := range queue { + ProcessMessage(session, msg, MessageOptions{NoColor: state.HasNoColor()}) + } + + state.EmptyMessageQueue() +} diff --git a/state/main.go b/state/main.go index d821fa0..4499601 100644 --- a/state/main.go +++ b/state/main.go @@ -16,9 +16,10 @@ type ComcordState struct { NameLength int InPrompt bool AFK bool - MessageQueue []discordgo.Message + MessageQueue []*discordgo.Message LastChannel map[string]string LastDM string + NoColor bool } var state ComcordState @@ -34,9 +35,10 @@ func Setup(config map[string]string) { state.NameLength = 2 state.InPrompt = false state.AFK = false - state.MessageQueue = make([]discordgo.Message, 0) + state.MessageQueue = make([]*discordgo.Message, 0) state.LastChannel = make(map[string]string) state.LastDM = "" + state.NoColor = false } func IsConnected() bool { @@ -99,14 +101,18 @@ func SetAFK(value bool) { state.AFK = value } -func GetMessageQueue() []discordgo.Message { +func GetMessageQueue() []*discordgo.Message { return state.MessageQueue } -func AddMessageToQueue(msg discordgo.Message) { +func AddMessageToQueue(msg *discordgo.Message) { state.MessageQueue = append(state.MessageQueue, msg) } +func EmptyMessageQueue() { + state.MessageQueue = make([]*discordgo.Message, 0) +} + func SetLastChannel(guild string, channel string) { state.LastChannel[guild] = channel } @@ -138,3 +144,11 @@ func GetConfigValue(key string) string { return "" } } + +func SetNoColor(value bool) { + state.NoColor = value +} + +func HasNoColor() bool { + return state.NoColor +}