refact round 2
This commit is contained in:
197
engine/printer.go
Normal file
197
engine/printer.go
Normal file
@@ -0,0 +1,197 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// ANSI color codes
|
||||
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"
|
||||
)
|
||||
|
||||
// W is the default terminal width
|
||||
const W = 70
|
||||
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user