Files
bbs-server/lib/sys.print.go
2026-03-10 21:26:04 +01:00

203 lines
4.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package lib
import (
"bytes"
"fmt"
"net"
"regexp"
"strings"
"time"
"unicode/utf8"
)
// ANSI Colors
const (
R = "\033[0m"
B = "\033[1m"
DIM = "\033[2m"
CY = "\033[1;36m"
YL = "\033[1;33m"
GR = "\033[1;32m"
RD = "\033[1;31m"
MG = "\033[1;35m"
WH = "\033[1;37m"
BL = "\033[1;34m"
GY = "\033[0;37m"
)
const W = 70
type Message struct {
User string
Timestamp string
Text string
}
type Printer struct {
Conn net.Conn
}
func NewPrinter(conn net.Conn) *Printer {
return &Printer{Conn: conn}
}
func (p *Printer) Send(text string) {
normalized := strings.ReplaceAll(text, "\r\n", "\n")
normalized = strings.ReplaceAll(normalized, "\n", "\r\n")
p.Conn.Write([]byte(normalized))
}
func (p *Printer) ReadLine() (string, error) {
var buf bytes.Buffer
for {
b := make([]byte, 1)
_, err := p.Conn.Read(b)
if err != nil {
return "", err
}
ch := b[0]
if ch == 255 {
cmd := make([]byte, 2)
_, err := p.Conn.Read(cmd)
if err != nil {
return "", err
}
if cmd[0] == 250 {
for {
tmp := make([]byte, 1)
_, err := p.Conn.Read(tmp)
if err != nil || tmp[0] == 240 {
break
}
}
}
continue
}
if ch == '\r' || ch == '\n' {
res := buf.String()
p.Send("\r\n")
return res, nil
}
if ch == 8 || ch == 127 {
if buf.Len() > 0 {
curr := buf.Bytes()
buf.Reset()
buf.Write(curr[:len(curr)-1])
p.Send("\b \b")
}
continue
}
if ch >= 32 && ch < 127 {
buf.WriteByte(ch)
p.Send(string(ch))
}
}
}
func (p *Printer) Pause(lang T) {
p.Send(fmt.Sprintf("\r\n%s [ %s ]%s ", GY, lang["Pause"], R))
p.ReadLine()
}
func (p *Printer) VisibleLen(s string) int {
re := regexp.MustCompile(`\033\[[0-9;]*m`)
return utf8.RuneCountInString(re.ReplaceAllString(s, ""))
}
func (p *Printer) PadLine(content string, width int) string {
vLen := p.VisibleLen(content)
padding := width - vLen
if padding < 0 {
padding = 0
}
return content + strings.Repeat(" ", padding)
}
func (p *Printer) BoxHeader(title string, color string) {
line := strings.Repeat("═", W)
titleLen := utf8.RuneCountInString(title)
padding := (W - 2 - titleLen) / 2
if padding < 0 {
padding = 0
}
inner := strings.Repeat(" ", padding) + title + strings.Repeat(" ", W-2-titleLen-padding)
p.Send(fmt.Sprintf(
"\n%s%s%s\n%s║%s %s%s%s %s║%s\n%s%s%s\n",
color, line, R,
color, R, B, inner, R, color, R,
color, line, R,
))
}
func (p *Printer) HR(char string, color string) {
p.Send(fmt.Sprintf("%s%s%s", color, strings.Repeat(char, W), R))
}
func (p *Printer) FmtDate(s string) string {
t, err := time.Parse(time.RFC3339, strings.Replace(s, "Z", "+00:00", 1))
if err != nil {
if len(s) >= 10 {
return s[:10]
}
return ""
}
return t.Format("2006-01-02")
}
func (p *Printer) StripMD(text string) string {
reImg := regexp.MustCompile(`!\[.*?\]\(.*?\)|\[(.*?)\]\(.*?\)|#{1,6}\s*|[*_` + "`" + `~>|]`)
text = reImg.ReplaceAllStringFunc(text, func(s string) string {
if strings.HasPrefix(s, "[") {
sub := regexp.MustCompile(`\[(.*?)\]\(.*?\)` )
matches := sub.FindStringSubmatch(s)
if len(matches) > 1 {
return matches[1]
}
}
if strings.HasPrefix(s, "!") || strings.HasPrefix(s, "#") || strings.ContainsAny(s, "*_`~>|") {
return ""
}
return s
})
return strings.TrimSpace(text)
}
func (p *Printer) Wrapped(text string, indent int, maxChars int) string {
if len(text) > maxChars {
text = text[:maxChars]
}
text = p.StripMD(text)
prefix := strings.Repeat(" ", indent)
var lines []string
paras := strings.Split(text, "\n")
for _, para := range paras {
para = strings.TrimSpace(para)
if para == "" {
lines = append(lines, "")
continue
}
words := strings.Fields(para)
if len(words) == 0 {
continue
}
currentLine := prefix + words[0]
for _, word := range words[1:] {
if len(currentLine)+1+len(word) > W {
lines = append(lines, currentLine)
currentLine = prefix + word
} else {
currentLine += " " + word
}
}
lines = append(lines, currentLine)
}
return strings.Join(lines, "\r\n")
}