Skip to content

Commit

Permalink
feat(ansi): TruncateLeft (#301)
Browse files Browse the repository at this point in the history
Truncate returns the first N chars of the string.
TruncateLeft skips the first N chars of the string, returning the rest.
  • Loading branch information
caarlos0 authored Dec 10, 2024
1 parent 7755dca commit e41b682
Show file tree
Hide file tree
Showing 2 changed files with 352 additions and 39 deletions.
78 changes: 78 additions & 0 deletions ansi/truncate.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,81 @@ func Truncate(s string, length int, tail string) string {

return buf.String()
}

// TruncateLeft truncates a string from the left side to a given length, adding
// a prefix to the beginning if the string is longer than the given length.
// This function is aware of ANSI escape codes and will not break them, and
// accounts for wide-characters (such as East Asians and emojis).
func TruncateLeft(s string, length int, prefix string) string {
if length == 0 {
return ""
}

var cluster []byte
var buf bytes.Buffer
curWidth := 0
ignoring := true
pstate := parser.GroundState
b := []byte(s)
i := 0

for i < len(b) {
if !ignoring {
buf.Write(b[i:])
break
}

state, action := parser.Table.Transition(pstate, b[i])
if state == parser.Utf8State {
var width int
cluster, _, width, _ = uniseg.FirstGraphemeCluster(b[i:], -1)

i += len(cluster)
curWidth += width

if curWidth > length && ignoring {
ignoring = false
buf.WriteString(prefix)
}

if ignoring {
continue
}

if curWidth > length {
buf.Write(cluster)
}

pstate = parser.GroundState
continue
}

switch action {
case parser.PrintAction:
curWidth++

if curWidth > length && ignoring {
ignoring = false
buf.WriteString(prefix)
}

if ignoring {
i++
continue
}

fallthrough
default:
buf.WriteByte(b[i])
i++
}

pstate = state
if curWidth > length && ignoring {
ignoring = false
buf.WriteString(prefix)
}
}

return buf.String()
}
Loading

0 comments on commit e41b682

Please sign in to comment.