Add FormatSlice function
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>
This commit is contained in:
parent
4896546432
commit
1e88ec55fc
2 changed files with 155 additions and 0 deletions
|
|
@ -2,8 +2,10 @@ package text
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -81,3 +83,64 @@ func RemoveDiacritics(value string) string {
|
|||
func PadRight(maxWidth int, s string) string {
|
||||
return text.PadRight(maxWidth, s)
|
||||
}
|
||||
|
||||
// FormatSlice concatenates elements of the given string slice into a
|
||||
// well-formatted, possibly multiline, string with specific line length limit.
|
||||
// Elements can be optionally surrounded by custom strings (e.g., quotes or
|
||||
// brackets). If the lineLength argument is non-positive, no line length limit
|
||||
// will be applied.
|
||||
func FormatSlice(values []string, lineLength uint, indent uint, prependWith string, appendWith string, sort bool) string {
|
||||
if lineLength <= 0 {
|
||||
lineLength = math.MaxInt
|
||||
}
|
||||
|
||||
sortedValues := values
|
||||
if sort {
|
||||
sortedValues = slices.Clone(values)
|
||||
slices.Sort(sortedValues)
|
||||
}
|
||||
|
||||
pre := strings.Repeat(" ", int(indent))
|
||||
if len(sortedValues) == 0 {
|
||||
return pre
|
||||
} else if len(sortedValues) == 1 {
|
||||
return pre + sortedValues[0]
|
||||
}
|
||||
|
||||
builder := strings.Builder{}
|
||||
currentLineLength := 0
|
||||
sep := ","
|
||||
ws := " "
|
||||
|
||||
for i := 0; i < len(sortedValues); i++ {
|
||||
v := prependWith + sortedValues[i] + appendWith
|
||||
isLast := i == -1+len(sortedValues)
|
||||
|
||||
if currentLineLength == 0 {
|
||||
builder.WriteString(pre)
|
||||
builder.WriteString(v)
|
||||
currentLineLength += len(v)
|
||||
if !isLast {
|
||||
builder.WriteString(sep)
|
||||
currentLineLength += len(sep)
|
||||
}
|
||||
} else {
|
||||
if !isLast && currentLineLength+len(ws)+len(v)+len(sep) > int(lineLength) ||
|
||||
isLast && currentLineLength+len(ws)+len(v) > int(lineLength) {
|
||||
currentLineLength = 0
|
||||
builder.WriteString("\n")
|
||||
i--
|
||||
continue
|
||||
}
|
||||
|
||||
builder.WriteString(ws)
|
||||
builder.WriteString(v)
|
||||
currentLineLength += len(ws) + len(v)
|
||||
if !isLast {
|
||||
builder.WriteString(sep)
|
||||
currentLineLength += len(sep)
|
||||
}
|
||||
}
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,3 +54,95 @@ func TestFuzzyAgoAbbr(t *testing.T) {
|
|||
assert.Equal(t, expected, fuzzy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatSliceDoc(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
values []string
|
||||
indent uint
|
||||
lineLength uint
|
||||
prependWith string
|
||||
appendWith string
|
||||
sort bool
|
||||
wants string
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
lineLength: 10,
|
||||
values: []string{},
|
||||
wants: "",
|
||||
},
|
||||
{
|
||||
name: "empty with indent",
|
||||
lineLength: 10,
|
||||
indent: 2,
|
||||
values: []string{},
|
||||
wants: " ",
|
||||
},
|
||||
{
|
||||
name: "single",
|
||||
lineLength: 10,
|
||||
values: []string{"foo"},
|
||||
wants: "foo",
|
||||
},
|
||||
{
|
||||
name: "single with indent",
|
||||
lineLength: 10,
|
||||
indent: 2,
|
||||
values: []string{"foo"},
|
||||
wants: " foo",
|
||||
},
|
||||
{
|
||||
name: "long single with indent",
|
||||
lineLength: 10,
|
||||
indent: 2,
|
||||
values: []string{"some-long-value"},
|
||||
wants: " some-long-value",
|
||||
},
|
||||
{
|
||||
name: "exact line length",
|
||||
lineLength: 4,
|
||||
values: []string{"a", "b"},
|
||||
wants: "a, b",
|
||||
},
|
||||
{
|
||||
name: "values longer than line length",
|
||||
lineLength: 4,
|
||||
values: []string{"long-value", "long-value"},
|
||||
wants: "long-value,\nlong-value",
|
||||
},
|
||||
{
|
||||
name: "zero line length (no wrapping expected)",
|
||||
lineLength: 0,
|
||||
values: []string{"foo", "bar"},
|
||||
wants: "foo, bar",
|
||||
},
|
||||
{
|
||||
name: "simple",
|
||||
lineLength: 10,
|
||||
values: []string{"foo", "bar", "baz", "foo", "bar", "baz"},
|
||||
wants: "foo, bar,\nbaz, foo,\nbar, baz",
|
||||
},
|
||||
{
|
||||
name: "simple, surrounded",
|
||||
lineLength: 13,
|
||||
prependWith: "<",
|
||||
appendWith: ">",
|
||||
values: []string{"foo", "bar", "baz", "foo", "bar", "baz"},
|
||||
wants: "<foo>, <bar>,\n<baz>, <foo>,\n<bar>, <baz>",
|
||||
},
|
||||
{
|
||||
name: "sort",
|
||||
lineLength: 99,
|
||||
sort: true,
|
||||
values: []string{"c", "b", "a"},
|
||||
wants: "a, b, c",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.wants, FormatSlice(tt.values, tt.lineLength, tt.indent, tt.prependWith, tt.appendWith, tt.sort))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue