aggressive token saving attempts
This commit is contained in:
143
internal/app/canonical.go
Normal file
143
internal/app/canonical.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
var (
|
||||
statusVolatileRE = regexp.MustCompile(`\b(?:\d+h\s*)?\d+m\s*\d+s\b|\b\d{1,2}:\d{2}(?::\d{2})?\b|\b\d+(?:\.\d+)?s\b`)
|
||||
counterRE = regexp.MustCompile(`\b\d+\s*/\s*\d+\b|\b\d{1,3}%`)
|
||||
spinnerGlyphRE = regexp.MustCompile(`^[\s⠁⠂⠄⡀⢀⠠⠐⠈⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏•·∙◐◓◑◒]+`)
|
||||
)
|
||||
|
||||
func canonicalizeTerminalText(s string, maxLines int) (string, bool, int) {
|
||||
s = string(stripANSIBytes(nil, []byte(s)))
|
||||
s = strings.ReplaceAll(s, "\r\n", "\n")
|
||||
s = carriageReturnToLines(s)
|
||||
s = strings.ReplaceAll(s, "\r", "\n")
|
||||
|
||||
lines := strings.Split(s, "\n")
|
||||
out := make([]string, 0, len(lines))
|
||||
pendingBlank := false
|
||||
for _, raw := range lines {
|
||||
line := strings.TrimRightFunc(stripControlRunes(raw), unicode.IsSpace)
|
||||
if strings.TrimSpace(line) == "" {
|
||||
if len(out) > 0 {
|
||||
pendingBlank = true
|
||||
}
|
||||
continue
|
||||
}
|
||||
if isBorderOnlyLine(line) {
|
||||
continue
|
||||
}
|
||||
line = canonicalStatusLine(line)
|
||||
if len(out) > 0 && out[len(out)-1] == line {
|
||||
pendingBlank = false
|
||||
continue
|
||||
}
|
||||
if pendingBlank {
|
||||
out = append(out, "")
|
||||
pendingBlank = false
|
||||
}
|
||||
out = append(out, line)
|
||||
}
|
||||
|
||||
if maxLines > 0 && len(out) > maxLines {
|
||||
dropped := strings.Join(out[:len(out)-maxLines], "\n")
|
||||
out = out[len(out)-maxLines:]
|
||||
return strings.Join(out, "\n"), true, len(dropped)
|
||||
}
|
||||
return strings.Join(out, "\n"), false, 0
|
||||
}
|
||||
|
||||
func carriageReturnToLines(s string) string {
|
||||
var out []string
|
||||
var current strings.Builder
|
||||
flush := func() {
|
||||
out = append(out, current.String())
|
||||
current.Reset()
|
||||
}
|
||||
for len(s) > 0 {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
s = s[size:]
|
||||
switch r {
|
||||
case '\r':
|
||||
current.Reset()
|
||||
case '\n':
|
||||
flush()
|
||||
default:
|
||||
current.WriteRune(r)
|
||||
}
|
||||
}
|
||||
if current.Len() > 0 || len(out) == 0 {
|
||||
flush()
|
||||
}
|
||||
return strings.Join(out, "\n")
|
||||
}
|
||||
|
||||
func stripControlRunes(s string) string {
|
||||
return strings.Map(func(r rune) rune {
|
||||
if r == '\t' || r == '\n' {
|
||||
return r
|
||||
}
|
||||
if unicode.IsControl(r) {
|
||||
return -1
|
||||
}
|
||||
return r
|
||||
}, s)
|
||||
}
|
||||
|
||||
func isBorderOnlyLine(s string) bool {
|
||||
trimmed := strings.TrimSpace(s)
|
||||
if trimmed == "" {
|
||||
return false
|
||||
}
|
||||
seenBox := false
|
||||
for _, r := range trimmed {
|
||||
if r >= 0x2500 && r <= 0x257f {
|
||||
seenBox = true
|
||||
continue
|
||||
}
|
||||
switch r {
|
||||
case ' ', '\t', '-', '_', '=', '+', '|', ':', '.', '\'', '"', '`', '*':
|
||||
continue
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return seenBox
|
||||
}
|
||||
|
||||
func canonicalStatusLine(s string) string {
|
||||
if !looksStatusLike(s) {
|
||||
return s
|
||||
}
|
||||
leading := len(s) - len(strings.TrimLeftFunc(s, unicode.IsSpace))
|
||||
prefix := s[:leading]
|
||||
body := s[leading:]
|
||||
body = spinnerGlyphRE.ReplaceAllString(body, "")
|
||||
body = statusVolatileRE.ReplaceAllString(body, "[time]")
|
||||
body = counterRE.ReplaceAllString(body, "[count]")
|
||||
return prefix + strings.TrimRightFunc(body, unicode.IsSpace)
|
||||
}
|
||||
|
||||
func looksStatusLike(s string) bool {
|
||||
lower := strings.ToLower(s)
|
||||
for _, token := range []string{
|
||||
"status", "running", "remaining", "progress", "loading",
|
||||
"building", "installing", "downloading", "waiting", "working",
|
||||
} {
|
||||
if strings.Contains(lower, token) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
trimmed := strings.TrimSpace(s)
|
||||
if trimmed == "" {
|
||||
return false
|
||||
}
|
||||
r, _ := utf8.DecodeRuneInString(trimmed)
|
||||
return strings.ContainsRune("⠁⠂⠄⡀⢀⠠⠐⠈⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏•·∙◐◓◑◒", r)
|
||||
}
|
||||
Reference in New Issue
Block a user