1
0
Fork 0
forked from External/ergo

use ergochat/irc-go instead of goshuirc/irc-go

This commit is contained in:
Shivaram Lingamneni 2021-06-18 02:41:57 -04:00
parent 66af8cd63c
commit 4910aefa37
32 changed files with 95 additions and 53 deletions

86
vendor/github.com/ergochat/irc-go/ircfmt/doc.go generated vendored Normal file
View file

@ -0,0 +1,86 @@
// written by Daniel Oaks <daniel@danieloaks.net>
// released under the ISC license
/*
Package ircfmt handles IRC formatting codes, escaping and unescaping.
This allows for a simpler representation of strings that contain colour codes,
bold codes, and such, without having to write and handle raw bytes when
assembling outgoing messages.
This lets you turn raw IRC messages into our escaped versions, and turn escaped
versions back into raw messages suitable for sending on IRC connections. This
is designed to be used on things like PRIVMSG / NOTICE commands, MOTD blocks,
and such.
The escape character we use in this library is the dollar sign ("$"), along
with the given escape characters:
--------------------------------
Name | Escape | Raw
--------------------------------
Dollarsign | $$ | $
Bold | $b | 0x02
Colour | $c | 0x03
Monospace | $m | 0x11
Reverse Colour | $v | 0x16
Italic | $i | 0x1d
Strikethrough | $s | 0x1e
Underscore | $u | 0x1f
Reset | $r | 0x0f
--------------------------------
Colours are escaped in a slightly different way, using the actual names of them
rather than just the raw numbers.
In our escaped format, the colours for the fore and background are contained in
square brackets after the colour ("$c") escape. For example:
Red foreground:
Escaped: This is a $c[red]cool message!
Raw: This is a 0x034cool message!
Blue foreground, green background:
Escaped: This is a $c[blue,green]rad message!
Raw: This is a 0x032,3rad message!
When assembling a raw message, we make sure to use the full colour code
("02" vs just "2") when it could become confused due to numbers just after the
colour escape code. For instance, lines like this will be unescaped correctly:
No number after colour escape:
Escaped: This is a $c[red]cool message!
Raw: This is a 0x034cool message!
Number after colour escape:
Escaped: This is $c[blue]20% cooler!
Raw: This is 0x030220% cooler
Here are the colour names and codes we recognise:
--------------------
Code | Name
--------------------
00 | white
01 | black
02 | blue
03 | green
04 | red
05 | brown
06 | magenta
07 | orange
08 | yellow
09 | light green
10 | cyan
11 | light cyan
12 | light blue
13 | pink
14 | grey
15 | light grey
99 | default
--------------------
These other colours aren't given names:
https://modern.ircdocs.horse/formatting.html#colors-16-98
*/
package ircfmt

317
vendor/github.com/ergochat/irc-go/ircfmt/ircfmt.go generated vendored Normal file
View file

@ -0,0 +1,317 @@
// written by Daniel Oaks <daniel@danieloaks.net>
// released under the ISC license
package ircfmt
import (
"regexp"
"strings"
)
const (
// raw bytes and strings to do replacing with
bold string = "\x02"
colour string = "\x03"
monospace string = "\x11"
reverseColour string = "\x16"
italic string = "\x1d"
strikethrough string = "\x1e"
underline string = "\x1f"
reset string = "\x0f"
runecolour rune = '\x03'
runebold rune = '\x02'
runemonospace rune = '\x11'
runereverseColour rune = '\x16'
runeitalic rune = '\x1d'
runestrikethrough rune = '\x1e'
runereset rune = '\x0f'
runeunderline rune = '\x1f'
// valid characters in a colour code character, for speed
colours1 string = "0123456789"
)
var (
// valtoescape replaces most of IRC characters with our escapes.
valtoescape = strings.NewReplacer("$", "$$", colour, "$c", reverseColour, "$v", bold, "$b", italic, "$i", strikethrough, "$s", underline, "$u", monospace, "$m", reset, "$r")
// valToStrip replaces most of the IRC characters with nothing
valToStrip = strings.NewReplacer(colour, "$c", reverseColour, "", bold, "", italic, "", strikethrough, "", underline, "", monospace, "", reset, "")
// escapetoval contains most of our escapes and how they map to real IRC characters.
// intentionally skips colour, since that's handled elsewhere.
escapetoval = map[rune]string{
'$': "$",
'b': bold,
'i': italic,
'v': reverseColour,
's': strikethrough,
'u': underline,
'm': monospace,
'r': reset,
}
// valid colour codes
numtocolour = map[string]string{
"99": "default",
"15": "light grey",
"14": "grey",
"13": "pink",
"12": "light blue",
"11": "light cyan",
"10": "cyan",
"09": "light green",
"08": "yellow",
"07": "orange",
"06": "magenta",
"05": "brown",
"04": "red",
"03": "green",
"02": "blue",
"01": "black",
"00": "white",
"9": "light green",
"8": "yellow",
"7": "orange",
"6": "magenta",
"5": "brown",
"4": "red",
"3": "green",
"2": "blue",
"1": "black",
"0": "white",
}
colourcodesTruncated = map[string]string{
"white": "0",
"black": "1",
"blue": "2",
"green": "3",
"red": "4",
"brown": "5",
"magenta": "6",
"orange": "7",
"yellow": "8",
"light green": "9",
"cyan": "10",
"light cyan": "11",
"light blue": "12",
"pink": "13",
"grey": "14",
"light grey": "15",
"default": "99",
}
bracketedExpr = regexp.MustCompile(`^\[.*?\]`)
colourDigits = regexp.MustCompile(`^[0-9]{1,2}$`)
)
// Escape takes a raw IRC string and returns it with our escapes.
//
// IE, it turns this: "This is a \x02cool\x02, \x034red\x0f message!"
// into: "This is a $bcool$b, $c[red]red$r message!"
func Escape(in string) string {
// replace all our usual escapes
in = valtoescape.Replace(in)
inRunes := []rune(in)
//var out string
out := strings.Builder{}
for 0 < len(inRunes) {
if 1 < len(inRunes) && inRunes[0] == '$' && inRunes[1] == 'c' {
// handle colours
out.WriteString("$c")
inRunes = inRunes[2:] // strip colour code chars
if len(inRunes) < 1 || !strings.Contains(colours1, string(inRunes[0])) {
out.WriteString("[]")
continue
}
var foreBuffer, backBuffer string
foreBuffer += string(inRunes[0])
inRunes = inRunes[1:]
if 0 < len(inRunes) && strings.Contains(colours1, string(inRunes[0])) {
foreBuffer += string(inRunes[0])
inRunes = inRunes[1:]
}
if 1 < len(inRunes) && inRunes[0] == ',' && strings.Contains(colours1, string(inRunes[1])) {
backBuffer += string(inRunes[1])
inRunes = inRunes[2:]
if 0 < len(inRunes) && strings.Contains(colours1, string(inRunes[0])) {
backBuffer += string(inRunes[0])
inRunes = inRunes[1:]
}
}
foreName, exists := numtocolour[foreBuffer]
if !exists {
foreName = foreBuffer
}
backName, exists := numtocolour[backBuffer]
if !exists {
backName = backBuffer
}
out.WriteRune('[')
out.WriteString(foreName)
if backName != "" {
out.WriteRune(',')
out.WriteString(backName)
}
out.WriteRune(']')
} else {
// special case for $$c
if len(inRunes) > 2 && inRunes[0] == '$' && inRunes[1] == '$' && inRunes[2] == 'c' {
out.WriteRune(inRunes[0])
out.WriteRune(inRunes[1])
out.WriteRune(inRunes[2])
inRunes = inRunes[3:]
} else {
out.WriteRune(inRunes[0])
inRunes = inRunes[1:]
}
}
}
return out.String()
}
// Strip takes a raw IRC string and removes it with all formatting codes removed
// IE, it turns this: "This is a \x02cool\x02, \x034red\x0f message!"
// into: "This is a cool, red message!"
func Strip(in string) string {
out := strings.Builder{}
runes := []rune(in)
if out.Len() < len(runes) { // Reduce allocations where needed
out.Grow(len(in) - out.Len())
}
for len(runes) > 0 {
switch runes[0] {
case runebold, runemonospace, runereverseColour, runeitalic, runestrikethrough, runeunderline, runereset:
runes = runes[1:]
case runecolour:
runes = removeColour(runes)
default:
out.WriteRune(runes[0])
runes = runes[1:]
}
}
return out.String()
}
func removeNumber(runes []rune) []rune {
if len(runes) > 0 && runes[0] >= '0' && runes[0] <= '9' {
runes = runes[1:]
}
return runes
}
func removeColour(runes []rune) []rune {
if runes[0] != runecolour {
return runes
}
runes = runes[1:]
runes = removeNumber(runes)
runes = removeNumber(runes)
if len(runes) > 1 && runes[0] == ',' && runes[1] >= '0' && runes[1] <= '9' {
runes = runes[2:]
} else {
return runes // Nothing else because we dont have a comma
}
runes = removeNumber(runes)
return runes
}
// resolve "light blue" to "12", "12" to "12", "asdf" to "", etc.
func resolveToColourCode(str string) (result string) {
str = strings.ToLower(strings.TrimSpace(str))
if colourDigits.MatchString(str) {
return str
}
return colourcodesTruncated[str]
}
// resolve "[light blue, black]" to ("13, "1")
func resolveToColourCodes(namedColors string) (foreground, background string) {
// cut off the brackets
namedColors = strings.TrimPrefix(namedColors, "[")
namedColors = strings.TrimSuffix(namedColors, "]")
var foregroundStr, backgroundStr string
commaIdx := strings.IndexByte(namedColors, ',')
if commaIdx != -1 {
foregroundStr = namedColors[:commaIdx]
backgroundStr = namedColors[commaIdx+1:]
} else {
foregroundStr = namedColors
}
return resolveToColourCode(foregroundStr), resolveToColourCode(backgroundStr)
}
// Unescape takes our escaped string and returns a raw IRC string.
//
// IE, it turns this: "This is a $bcool$b, $c[red]red$r message!"
// into this: "This is a \x02cool\x02, \x034red\x0f message!"
func Unescape(in string) string {
var out strings.Builder
remaining := in
for len(remaining) != 0 {
char := remaining[0]
remaining = remaining[1:]
if char != '$' || len(remaining) == 0 {
// not an escape
out.WriteByte(char)
continue
}
// ingest the next character of the escape
char = remaining[0]
remaining = remaining[1:]
if char == 'c' {
out.WriteString(colour)
namedColors := bracketedExpr.FindString(remaining)
if namedColors == "" {
// for a non-bracketed color code, output the following characters directly,
// e.g., `$c1,8` will become `\x031,8`
continue
}
// process bracketed color codes:
remaining = remaining[len(namedColors):]
followedByDigit := len(remaining) != 0 && ('0' <= remaining[0] && remaining[0] <= '9')
foreground, background := resolveToColourCodes(namedColors)
if foreground != "" {
if len(foreground) == 1 && background == "" && followedByDigit {
out.WriteByte('0')
}
out.WriteString(foreground)
if background != "" {
out.WriteByte(',')
if len(background) == 1 && followedByDigit {
out.WriteByte('0')
}
out.WriteString(background)
}
}
} else {
val, exists := escapetoval[rune(char)]
if exists {
out.WriteString(val)
} else {
// invalid escape, use the raw char
out.WriteByte(char)
}
}
}
return out.String()
}