1
0
Fork 0
golang-github-nicholas-fedo.../pkg/util/partition_message.go
Daniel Baumann c0c4addb85
Adding upstream version 0.8.9.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-22 10:16:14 +02:00

118 lines
2.8 KiB
Go

package util
import (
"strings"
"github.com/nicholas-fedor/shoutrrr/pkg/types"
)
// ellipsis is the suffix appended to truncated strings.
const ellipsis = " [...]"
// PartitionMessage splits a string into chunks of at most chunkSize runes.
// It searches the last distance runes for a whitespace to improve readability,
// adding chunks until reaching maxCount or maxTotal runes, returning the chunks
// and the number of omitted runes.
func PartitionMessage(
input string,
limits types.MessageLimit,
distance int,
) ([]types.MessageItem, int) {
items := make([]types.MessageItem, 0, limits.ChunkCount-1)
runes := []rune(input)
chunkOffset := 0
maxTotal := Min(len(runes), limits.TotalChunkSize)
maxCount := limits.ChunkCount - 1
if len(input) == 0 {
// If the message is empty, return an empty array
return items, 0
}
for range maxCount {
// If no suitable split point is found, use the chunkSize
chunkEnd := chunkOffset + limits.ChunkSize
// ... and start next chunk directly after this one
nextChunkStart := chunkEnd
if chunkEnd >= maxTotal {
// The chunk is smaller than the limit, no need to search
chunkEnd = maxTotal
nextChunkStart = maxTotal
} else {
for r := range distance {
rp := chunkEnd - r
if runes[rp] == '\n' || runes[rp] == ' ' {
// Suitable split point found
chunkEnd = rp
// Since the split is on a whitespace, skip it in the next chunk
nextChunkStart = chunkEnd + 1
break
}
}
}
items = append(items, types.MessageItem{
Text: string(runes[chunkOffset:chunkEnd]),
})
chunkOffset = nextChunkStart
if chunkOffset >= maxTotal {
break
}
}
return items, len(runes) - chunkOffset
}
// Ellipsis truncates a string to maxLength characters, appending an ellipsis if needed.
func Ellipsis(text string, maxLength int) string {
if len(text) > maxLength {
text = text[:maxLength-len(ellipsis)] + ellipsis
}
return text
}
// MessageItemsFromLines creates MessageItem batches compatible with the given limits.
func MessageItemsFromLines(plain string, limits types.MessageLimit) [][]types.MessageItem {
maxCount := limits.ChunkCount
lines := strings.Split(plain, "\n")
batches := make([][]types.MessageItem, 0)
items := make([]types.MessageItem, 0, Min(maxCount, len(lines)))
totalLength := 0
for _, line := range lines {
maxLen := limits.ChunkSize
if len(items) == maxCount || totalLength+maxLen > limits.TotalChunkSize {
batches = append(batches, items)
items = items[:0]
}
runes := []rune(line)
if len(runes) > maxLen {
// Trim and add ellipsis
runes = runes[:maxLen-len(ellipsis)]
line = string(runes) + ellipsis
}
if len(runes) < 1 {
continue
}
items = append(items, types.MessageItem{
Text: line,
})
totalLength += len(runes)
}
if len(items) > 0 {
batches = append(batches, items)
}
return batches
}