This commit is contained in:
Cynthia Foxwell 2023-07-27 21:00:08 -06:00
parent 976e4f7649
commit 06a5873908
3 changed files with 164 additions and 4 deletions

1
go.mod
View File

@ -15,6 +15,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/mergestat/timediff v0.0.3 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect

2
go.sum
View File

@ -113,6 +113,8 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mergestat/timediff v0.0.3 h1:ucCNh4/ZrTPjFZ081PccNbhx9spymCJkFxSzgVuPU+Y=
github.com/mergestat/timediff v0.0.3/go.mod h1:yvMUaRu2oetc+9IbPLYBJviz6sA7xz8OXMDfhBl7YSI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/peterh/liner v1.2.2 h1:aJ4AOodmL+JxOZZEL2u9iJf8omNRpqHc/EbrK+3mAXw=

View File

@ -4,17 +4,33 @@ import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
"time"
"unicode/utf8"
"github.com/Cynosphere/comcord/state"
"github.com/diamondburned/arikawa/v3/discord"
"github.com/mergestat/timediff"
"github.com/mgutz/ansi"
)
var REGEX_CODEBLOCK = regexp.MustCompile(`(?i)\x60\x60\x60(?:([a-z0-9_+\-\.]+?)\n)?\n*([^\n](?:.|\n)*?)\n*\x60\x60\x60`)
var REGEX_MENTION = regexp.MustCompile(`<@!?(\d+)>`)
var REGEX_ROLE_MENTION = regexp.MustCompile(`<@&(\d+)>`)
var REGEX_CHANNEL = regexp.MustCompile(`<#(\d+)>`)
var REGEX_EMOTE = regexp.MustCompile(`<(?:\x{200b}|&)?a?:(\w+):(\d+)>`)
var REGEX_COMMAND = regexp.MustCompile(`</([^\s]+?):(\d+)>`)
var REGEX_BLOCKQUOTE = regexp.MustCompile(`^ *>>?>? +`)
var REGEX_GREENTEXT = regexp.MustCompile(`^(>.+?)(?:\n|$)`)
var REGEX_SPOILER = regexp.MustCompile(`\|\|(.+?)\|\|`)
var REGEX_BOLD = regexp.MustCompile(`\*\*(.+?)\*\*`)
var REGEX_UNDERLINE = regexp.MustCompile(`__(.+?)__`)
var REGEX_ITALIC_1 = regexp.MustCompile(`\*(.+?)\*`)
var REGEX_ITALIC_2 = regexp.MustCompile(`_(.+?)_`)
var REGEX_STRIKE = regexp.MustCompile(`~~(.+?)~~`)
var REGEX_3Y3 = regexp.MustCompile(`[\x{e0020}-\x{e007e}]{1,}`)
var REGEX_TIMESTAMP = regexp.MustCompile(`<t:(-?\d{1,17})(?::(t|T|d|D|f|F|R))?>`)
type MessageOptions struct {
Content string
@ -35,6 +51,149 @@ type MessageOptions struct {
InHistory bool
}
func Parse3y3(content string) string {
out := []rune{}
for i, w := 0, 0; i < len(content); i += w {
runeValue, width := utf8.DecodeRuneInString(content[i:])
w = width
out = append(out, rune(int(runeValue) - 0xe0000))
}
return string(out)
}
func ReplaceStyledMarkdown(content string) string {
content = REGEX_BLOCKQUOTE.ReplaceAllString(content, ansi.Color("\u258e", "black+h"))
content = REGEX_GREENTEXT.ReplaceAllStringFunc(content, func(match string) string {
return ansi.Color(match, "green")
})
if state.GetConfigValue("enable3y3") == "true" {
parsed := REGEX_3Y3.FindString(content)
parsed = Parse3y3(parsed)
parsed = "\033[3m" + parsed + "\033[23m"
content = REGEX_3Y3.ReplaceAllString(content, ansi.Color(parsed, "magenta"))
}
content = REGEX_SPOILER.ReplaceAllString(content, "\033[30m\033[40m$1\033[39m\033[49m")
content = REGEX_STRIKE.ReplaceAllString(content, "\033[9m$1\033[29m")
content = REGEX_BOLD.ReplaceAllString(content, "\033[1m$1\033[22m")
content = REGEX_UNDERLINE.ReplaceAllString(content, "\033[4m$1\033[24m")
content = REGEX_ITALIC_1.ReplaceAllString(content, "\033[3m$1\033[23m")
content = REGEX_ITALIC_2.ReplaceAllString(content, "\033[3m$1\033[23m")
return content
}
func replaceAllWithCallback(re regexp.Regexp, content string, callback func(matches []string) string) string {
return re.ReplaceAllStringFunc(content, func(match string) string {
matches := re.FindStringSubmatch(match)
return callback(matches)
})
}
func ReplaceMarkdown(content string, noColor bool) string {
client := state.GetClient()
content = replaceAllWithCallback(*REGEX_MENTION, content, func(matches []string) string {
id := matches[1]
parsedId, err := discord.ParseSnowflake(id)
if err != nil {
return "@Unknown User"
}
user, err := client.User(discord.UserID(parsedId))
if err != nil {
return "@Unknown User"
}
return "@" + user.Username
})
content = replaceAllWithCallback(*REGEX_ROLE_MENTION, content, func(matches []string) string {
id := matches[1]
parsedId, err := discord.ParseSnowflake(id)
if err != nil {
return "[@Unknown Role]"
}
currentGuild := state.GetCurrentGuild()
if currentGuild == "" {
return "[@Unknown Role]"
}
parsedGuildId, err := discord.ParseSnowflake(currentGuild)
if err != nil {
return "[@Unknown Role]"
}
role, err := client.RoleStore.Role(discord.GuildID(parsedGuildId), discord.RoleID(parsedId))
if err != nil {
return "[@Unknown Role]"
}
return fmt.Sprintf("[@%s]", role.Name)
})
content = replaceAllWithCallback(*REGEX_CHANNEL, content, func(matches []string) string {
id := matches[1]
parsedId, err := discord.ParseSnowflake(id)
if err != nil {
return "#Unknown"
}
channel, err := client.ChannelStore.Channel(discord.ChannelID(parsedId))
if err != nil {
return "#Unknown"
}
return "#" + channel.Name
})
content = REGEX_EMOTE.ReplaceAllString(content, ":$1:")
content = REGEX_COMMAND.ReplaceAllString(content, "/$1")
content = replaceAllWithCallback(*REGEX_TIMESTAMP, content, func (matches []string) string {
timestamp, err := strconv.Atoi(matches[1])
if err != nil {
return "Invalid Date"
}
timeObj := time.Unix(int64(timestamp), 0).UTC()
format := matches[2]
switch format {
case "t":
return timeObj.Format("15:04")
case "T":
return timeObj.Format("15:04:05")
case "d":
return timeObj.Format("2006/01/02")
case "D":
return timeObj.Format("2 January 2006")
case "f":
return timeObj.Format("2 January 2006 15:04")
case "F":
return timeObj.Format("Monday, 2 January 2006 15:04")
case "R":
return timediff.TimeDiff(timeObj)
}
return "Invalid Date"
})
if !noColor {
content = ReplaceStyledMarkdown(content)
} else {
if state.GetConfigValue("enable3y3") == "true" {
parsed := REGEX_3Y3.FindString(content)
parsed = Parse3y3(parsed)
content = REGEX_3Y3.ReplaceAllString(content, "<3y3:" + parsed + ">")
}
}
return content
}
func FormatMessage(options MessageOptions) []string {
client := state.GetClient()
@ -60,8 +219,7 @@ func FormatMessage(options MessageOptions) []string {
content := options.Reply.Content
replyContent := strings.ReplaceAll(content, "\n", " ")
// TODO: markdown
replyContent = REGEX_EMOTE.ReplaceAllString(replyContent, ":$1:")
replyContent = ReplaceMarkdown(replyContent, options.NoColor)
attachmentCount := len(options.Reply.Attachments)
if attachmentCount > 0 {
@ -141,9 +299,8 @@ func FormatMessage(options MessageOptions) []string {
lines = append(lines, str + "\n\r")
}
} else {
// TODO: markdown
content := options.Content
content = REGEX_EMOTE.ReplaceAllString(content, ":$1:")
content = ReplaceMarkdown(content, options.NoColor)
if options.IsDM {
name := fmt.Sprintf("*%s*", options.Name)