From ef9b16ec9f2e7df0fe62bab0cf4fee2bc3f13d93 Mon Sep 17 00:00:00 2001 From: umlx5h Date: Sat, 6 Jan 2024 20:17:59 +0900 Subject: [PATCH] Add TruncatePrefix --- runewidth.go | 37 +++++++++++++++++++++++++++++++++++++ runewidth_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/runewidth.go b/runewidth.go index 7dfbb3b..038c935 100644 --- a/runewidth.go +++ b/runewidth.go @@ -251,6 +251,38 @@ func (c *Condition) TruncateLeft(s string, w int, prefix string) string { return prefix + s[pos:] } +// Truncate return string truncated with w cells from prefix part (left part) +func (c *Condition) TruncatePrefix(s string, w int, prefix string) string { + if c.StringWidth(prefix) >= w { + return prefix + } + + sw := c.StringWidth(s) + if sw <= w { + return s + } + w -= c.StringWidth(prefix) + var width int + var pos int + g := uniseg.NewGraphemes(s) + for g.Next() { + var chWidth int + for _, r := range g.Runes() { + chWidth = c.RuneWidth(r) + if chWidth > 0 { + break // See StringWidth() for details. + } + } + if sw-(width+chWidth) <= w { + _, pos = g.Positions() + break + } + width += chWidth + } + + return prefix + s[pos:] +} + // Wrap return string wrapped with w cells func (c *Condition) Wrap(s string, w int) string { width := 0 @@ -333,6 +365,11 @@ func TruncateLeft(s string, w int, prefix string) string { return DefaultCondition.TruncateLeft(s, w, prefix) } +// Truncate return string truncated with w cells from prefix part (left part) +func TruncatePrefix(s string, w int, prefix string) string { + return DefaultCondition.TruncatePrefix(s, w, prefix) +} + // Wrap return string wrapped with w cells func Wrap(s string, w int) string { return DefaultCondition.Wrap(s, w) diff --git a/runewidth_test.go b/runewidth_test.go index c3d0fc9..cf07acc 100644 --- a/runewidth_test.go +++ b/runewidth_test.go @@ -406,6 +406,40 @@ func TestTruncateLeft(t *testing.T) { } } +var truncateprefixtests = []struct { + s string + w int + prefix string + out string +}{ + {"source", 4, "*", "*rce"}, + {"source", 6, "*", "source"}, + {"あいうえお", 4, "*", "*お"}, + {"あいうえお", 10, "*", "あいうえお"}, + {"Aあいうえお", 5, "*", "*えお"}, + + {"source", 4, "", "urce"}, + {"source", 4, "...", "...e"}, + {"あいうえお", 6, "", "うえお"}, + {"あいうえお", 6, "...", "...お"}, + {"あいうえお", 10, "", "あいうえお"}, + {"あいうえお", 10, "...", "あいうえお"}, + {"あいうえお", 5, "", "えお"}, + + {"source", 1, "*", "*"}, + {"source", 0, "*", "*"}, // same as Truncate +} + +func TestTruncatePrefix(t *testing.T) { + t.Parallel() + + for _, tt := range truncateprefixtests { + if out := TruncatePrefix(tt.s, tt.w, tt.prefix); out != tt.out { + t.Errorf("TruncatePrefix(%q) = %q, want %q", tt.s, out, tt.out) + } + } +} + var isneutralwidthtests = []struct { in rune out bool