Files
tia-love/internal/app/ansi.go
T

78 lines
1.3 KiB
Go

package app
import (
"strings"
"charm.land/lipgloss/v2"
)
// ansiTruncate — potong string ber-ANSI ke lebar tampilan w (sel), aman
// terhadap escape sequence; bila terpotong ditutup reset + "…".
// Dipakai panel() agar konten tidak pernah wrap (tinggi panel tetap).
func ansiTruncate(s string, w int) string {
if w <= 0 {
return ""
}
if lipgloss.Width(s) <= w {
return s
}
const (
stNormal = iota
stEsc
stCSI
stOSC
stOSCEsc
)
state := stNormal
width := 0
var b strings.Builder
for _, r := range s {
switch state {
case stNormal:
if r == 0x1b {
state = stEsc
b.WriteRune(r)
continue
}
if width >= w-1 { // sisakan satu sel untuk "…"
b.WriteString("\x1b[0m…")
return b.String()
}
b.WriteRune(r)
width++
case stEsc:
b.WriteRune(r)
switch {
case r == '[':
state = stCSI
case r == ']':
state = stOSC
case r >= 0x20 && r <= 0x2f:
// intermediate — tunggu final byte
default:
state = stNormal
}
case stCSI:
b.WriteRune(r)
if r >= 0x40 && r <= 0x7e {
state = stNormal
}
case stOSC:
b.WriteRune(r)
if r == 0x07 {
state = stNormal
} else if r == 0x1b {
state = stOSCEsc
}
case stOSCEsc:
b.WriteRune(r)
if r == '\\' {
state = stNormal
} else {
state = stOSC
}
}
}
return b.String()
}