markdown
This commit is contained in:
		
							parent
							
								
									976e4f7649
								
							
						
					
					
						commit
						06a5873908
					
				
					 3 changed files with 164 additions and 4 deletions
				
			
		
							
								
								
									
										1
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
					@ -15,6 +15,7 @@ require (
 | 
				
			||||||
	github.com/mattn/go-colorable v0.1.13 // indirect
 | 
						github.com/mattn/go-colorable v0.1.13 // indirect
 | 
				
			||||||
	github.com/mattn/go-isatty v0.0.17 // indirect
 | 
						github.com/mattn/go-isatty v0.0.17 // indirect
 | 
				
			||||||
	github.com/mattn/go-runewidth v0.0.13 // 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/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
 | 
				
			||||||
	github.com/pkg/errors v0.9.1 // indirect
 | 
						github.com/pkg/errors v0.9.1 // indirect
 | 
				
			||||||
	github.com/rivo/uniseg v0.2.0 // 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.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 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
 | 
				
			||||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 | 
					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 h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
 | 
				
			||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
 | 
					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=
 | 
					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"
 | 
						"fmt"
 | 
				
			||||||
	"math"
 | 
						"math"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
	"unicode/utf8"
 | 
						"unicode/utf8"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/Cynosphere/comcord/state"
 | 
						"github.com/Cynosphere/comcord/state"
 | 
				
			||||||
	"github.com/diamondburned/arikawa/v3/discord"
 | 
						"github.com/diamondburned/arikawa/v3/discord"
 | 
				
			||||||
 | 
						"github.com/mergestat/timediff"
 | 
				
			||||||
	"github.com/mgutz/ansi"
 | 
						"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_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_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 {
 | 
					type MessageOptions struct {
 | 
				
			||||||
  Content string
 | 
					  Content string
 | 
				
			||||||
| 
						 | 
					@ -35,6 +51,149 @@ type MessageOptions struct {
 | 
				
			||||||
  InHistory bool
 | 
					  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 {
 | 
					func FormatMessage(options MessageOptions) []string {
 | 
				
			||||||
  client := state.GetClient()
 | 
					  client := state.GetClient()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,8 +219,7 @@ func FormatMessage(options MessageOptions) []string {
 | 
				
			||||||
    content := options.Reply.Content
 | 
					    content := options.Reply.Content
 | 
				
			||||||
    replyContent := strings.ReplaceAll(content, "\n", " ")
 | 
					    replyContent := strings.ReplaceAll(content, "\n", " ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: markdown
 | 
					    replyContent = ReplaceMarkdown(replyContent, options.NoColor)
 | 
				
			||||||
    replyContent = REGEX_EMOTE.ReplaceAllString(replyContent, ":$1:")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    attachmentCount := len(options.Reply.Attachments)
 | 
					    attachmentCount := len(options.Reply.Attachments)
 | 
				
			||||||
    if attachmentCount > 0 {
 | 
					    if attachmentCount > 0 {
 | 
				
			||||||
| 
						 | 
					@ -141,9 +299,8 @@ func FormatMessage(options MessageOptions) []string {
 | 
				
			||||||
      lines = append(lines, str + "\n\r")
 | 
					      lines = append(lines, str + "\n\r")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    // TODO: markdown
 | 
					 | 
				
			||||||
    content := options.Content
 | 
					    content := options.Content
 | 
				
			||||||
    content = REGEX_EMOTE.ReplaceAllString(content, ":$1:")
 | 
					    content = ReplaceMarkdown(content, options.NoColor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if options.IsDM {
 | 
					    if options.IsDM {
 | 
				
			||||||
      name := fmt.Sprintf("*%s*", options.Name)
 | 
					      name := fmt.Sprintf("*%s*", options.Name)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue