73 lines
1.5 KiB
Go
73 lines
1.5 KiB
Go
// 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))
|
|
}
|