// Package textutil wraps and clips plain text for a fixed terminal width. package textutil import "strings" // Clip shortens s to at most n runes, replacing tabs and newlines with spaces. func Clip(s string, n int) string { if n <= 0 { return "" } s = strings.ReplaceAll(strings.ReplaceAll(s, "\t", " "), "\n", " ") r := []rune(s) if len(r) <= n { return string(r) } if n == 1 { return "…" } return string(r[:n-1]) + "…" } // Wrap breaks s into lines no wider than width runes, preserving blank lines. func Wrap(s string, width int) []string { if width <= 1 { if s == "" { return []string{""} } return []string{s} } var out []string for _, para := range strings.Split(s, "\n") { if para == "" { out = append(out, "") continue } line := "" for _, word := range strings.Split(para, " ") { for len([]rune(word)) > width { if line != "" { out = append(out, line) line = "" } r := []rune(word) out = append(out, string(r[:width])) word = string(r[width:]) } switch { case line == "": line = word case len([]rune(line))+1+len([]rune(word)) <= width: line += " " + word default: out = append(out, line) line = word } } out = append(out, line) } if len(out) == 0 { return []string{""} } return out } // Pad pads s with spaces on the right until it is n runes wide. func Pad(s string, n int) string { r := []rune(s) if len(r) >= n { return string(r) } return string(r) + strings.Repeat(" ", n-len(r)) }