mirror of
https://github.com/ergochat/ergo.git
synced 2025-12-21 18:41:58 -08:00
use ergochat/irc-go instead of goshuirc/irc-go
This commit is contained in:
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
86
vendor/github.com/ergochat/irc-go/ircfmt/doc.go
generated
vendored
Normal 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
317
vendor/github.com/ergochat/irc-go/ircfmt/ircfmt.go
generated
vendored
Normal 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()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue