Skip to content

Commit

Permalink
chore(ansi): add a few more Cut test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
meowgorithm committed Jan 8, 2025
1 parent 48b574a commit 18c3144
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 32 deletions.
19 changes: 10 additions & 9 deletions ansi/truncate.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import (
"github.com/rivo/uniseg"
)

// Cut the string, without adding any prefix or tail strings.
// This function is aware of ANSI escape codes and will not break them, and
// accounts for wide-characters (such as East Asians and emojis).
// Note that the [left] parameter is inclusive, while [right] isn't.
// Cut the string, without adding any prefix or tail strings. This function is
// aware of ANSI escape codes and will not break them, and accounts for
// wide-characters (such as East-Asian characters and emojis). Note that the
// [left] parameter is inclusive, while [right] isn't.
func Cut(s string, left, right int) string {
if left == 0 {
return Truncate(s, right, "")
}
return TruncateLeft(Truncate(s, right, ""), left, "")
}

// Truncate truncates a string to a given length, adding a tail to the
// end 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).
// Truncate truncates a string to a given length, adding a tail to the end 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-Asian characters and emojis).
func Truncate(s string, length int, tail string) string {
if sw := StringWidth(s); sw <= length {
return s
Expand All @@ -44,6 +44,7 @@ func Truncate(s string, length int, tail string) string {
// Here we iterate over the bytes of the string and collect printable
// characters and runes. We also keep track of the width of the string
// in cells.
//
// Once we reach the given length, we start ignoring characters and only
// collect ANSI escape codes until we reach the end of string.
for i < len(b) {
Expand Down Expand Up @@ -120,7 +121,7 @@ func Truncate(s string, length int, tail string) 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).
// accounts for wide-characters (such as East-Asian characters and emojis).
func TruncateLeft(s string, length int, prefix string) string {
if length == 0 {
return ""
Expand Down
68 changes: 45 additions & 23 deletions ansi/truncate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,27 +302,49 @@ func TestTruncateLeft(t *testing.T) {
}

func TestCut(t *testing.T) {
t.Run("simple string", func(t *testing.T) {
got := Cut("This is a long string", 2, 6)
expect := "is i"
if got != expect {
t.Errorf("exptected %q, got %q", expect, got)
}
})

t.Run("with ansi", func(t *testing.T) {
got := Cut("I really \x1B[38;2;249;38;114mlove\x1B[0m Go!", 4, 25)
expect := "ally \x1b[38;2;249;38;114mlove\x1b[0m Go!"
if got != expect {
t.Errorf("exptected %q, got %q", expect, got)
}
})

t.Run("left is 0", func(t *testing.T) {
got := Cut("Foo \x1B[38;2;249;38;114mbar\x1B[0mbaz", 0, 5)
expect := "Foo \x1B[38;2;249;38;114mb\x1B[0m"
if got != expect {
t.Errorf("exptected %q, got %q", expect, got)
}
})
for i, c := range []struct {
desc string
input string
left int
right int
expect string
}{
{
"simple string",
"This is a long string", 2, 6,
"is i",
},
{
"with ansi",
"I really \x1B[38;2;249;38;114mlove\x1B[0m Go!", 4, 25,
"ally \x1b[38;2;249;38;114mlove\x1b[0m Go!",
},
{
"left is 0",
"Foo \x1B[38;2;249;38;114mbar\x1B[0mbaz", 0, 5,
"Foo \x1B[38;2;249;38;114mb\x1B[0m",
},
{
"right is 0",
"\x1b[7mHello\x1b[m", 3, 0,
"\x1b[7m\x1b[m",
},
{
"cut size is 0",
"\x1b[7mHello\x1b[m", 2, 2,
"\x1b[7m\x1b[m",
},
{
"maintains open ansi",
"\x1b[38;5;212;48;5;63mHello, Artichoke!\x1b[m", 7, 16,
"\x1b[38;5;212;48;5;63mArtichoke\x1b[m",
},
} {
t.Run(c.input, func(t *testing.T) {
got := Cut(c.input, c.left, c.right)
if got != c.expect {
t.Errorf("%s (%d):\nexpected: %q\ngot: %q", c.desc, i+1, c.expect, got)
}
})
}
}

0 comments on commit 18c3144

Please sign in to comment.