markdown
This commit is contained in:
parent
976e4f7649
commit
06a5873908
1
go.mod
1
go.mod
|
@ -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
2
go.sum
|
@ -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=
|
||||
|
|
165
lib/messages.go
165
lib/messages.go
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue