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-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…
	
	Add table
		Add a link
		
	
		Reference in a new issue