package terminal import ( "strings" "unicode/utf8" ) const textLimit = 64 << 10 func Text(b []byte) string { out := strings.Builder{} line := []rune{} col := 0 flush := func() { out.WriteString(strings.TrimRight(string(line), " ")) out.WriteByte('\n') line = line[:0] col = 0 } for i := 0; i < len(b); { c := b[i] switch { case c == 0x1b: end, final := skipEscape(b, i) if final == 'K' { line = line[:min(col, len(line))] } i = end + 1 continue case c == '\n': flush() case c == '\r': col = 0 case c == '\b': col = max(0, col-1) case c == '\t' || c >= 0x20 && c != 0x7f: r, n := utf8.DecodeRune(b[i:]) for len(line) < col { line = append(line, ' ') } if col < len(line) { line[col] = r } else { line = append(line, r) } col++ i += n continue } i++ } s := out.String() + strings.TrimRight(string(line), " ") if len(s) > textLimit { s = s[len(s)-textLimit:] s = s[strings.IndexByte(s, '\n')+1:] } return s } func skipEscape(b []byte, i int) (int, byte) { if i+1 >= len(b) { return i, 0 } i++ switch b[i] { case '[': for i++; i < len(b); i++ { if b[i] >= 0x40 && b[i] <= 0x7e { return i, b[i] } } return len(b) - 1, 0 case ']', 'P', '_', '^': for i++; i < len(b); i++ { if b[i] == 0x07 { return i, 0 } if b[i] == 0x1b && i+1 < len(b) && b[i+1] == '\\' { return i + 1, 0 } } return len(b) - 1, 0 case '(', ')', '*', '+', '#', '%': return min(i+1, len(b)-1), 0 } return i, 0 }