porkbacon/internal/ui/utils/text.go
2026-01-23 16:55:10 +00:00

65 lines
1.6 KiB
Go

package utils
import (
"strings"
)
// WrapText wraps text to a limit, forcing mid-word breaks if a word is too long.
// It uses runes to correctly handle UTF-8 multi-byte characters.
func WrapText(text string, limit int) string {
if limit <= 0 {
return text
}
var result strings.Builder
paragraphs := strings.Split(text, "\n")
for i, paragraph := range paragraphs {
words := strings.Fields(paragraph)
currentLineLen := 0
for _, word := range words {
// Convert to runes to handle UTF-8 characters correctly
wordRunes := []rune(word)
wordLen := len(wordRunes)
// Determine if we need a space before the word
if currentLineLen > 0 {
// If adding the word + space exceeds the limit, push to next line
if currentLineLen+1+wordLen <= limit {
result.WriteString(" ")
currentLineLen++
} else {
result.WriteString("\n")
currentLineLen = 0
}
}
// Write the word, chunking it if it exceeds the remaining line limit
for len(wordRunes) > 0 {
spaceLeft := limit - currentLineLen
// If the line is full, wrap to the next line
if spaceLeft <= 0 {
result.WriteString("\n")
currentLineLen = 0
spaceLeft = limit
}
// Take as much of the word as fits on the current line
take := min(len(wordRunes), spaceLeft)
result.WriteString(string(wordRunes[:take]))
currentLineLen += take
wordRunes = wordRunes[take:] // Advance the rune slice
}
}
// Preserve original paragraph breaks
if i < len(paragraphs)-1 {
result.WriteString("\n")
}
}
return result.String()
}