1package util
2
3import (
4 "bytes"
5 "regexp"
6 "strings"
7)
8
9func WordWrap(text string, lineWidth int) (string, int) {
10 words := strings.Fields(strings.TrimSpace(text))
11 if len(words) == 0 {
12 return "", 1
13 }
14 lines := 1
15 wrapped := words[0]
16 spaceLeft := lineWidth - len(wrapped)
17 for _, word := range words[1:] {
18 if len(word)+1 > spaceLeft {
19 wrapped += "\n" + word
20 spaceLeft = lineWidth - len(word)
21 lines++
22 } else {
23 wrapped += " " + word
24 spaceLeft -= 1 + len(word)
25 }
26 }
27
28 return wrapped, lines
29}
30
31func TextWrap(text string, lineWidth int) (string, int) {
32 return TextWrapPadded(text, lineWidth, 0)
33}
34
35func TextWrapPadded(text string, lineWidth int, leftPad int) (string, int) {
36 var textBuffer bytes.Buffer
37 var lineBuffer bytes.Buffer
38 nbLine := 1
39 firstLine := true
40 pad := strings.Repeat(" ", leftPad)
41
42 // tabs are formatted as 4 spaces
43 text = strings.Replace(text, "\t", " ", 4)
44
45 re := regexp.MustCompile(`(\x1b\[\d+m)?([^\x1b]*)(\x1b\[\d+m)?`)
46
47 for _, line := range strings.Split(text, "\n") {
48 spaceLeft := lineWidth - leftPad
49
50 if !firstLine {
51 textBuffer.WriteString("\n")
52 nbLine++
53 }
54
55 firstWord := true
56
57 for _, word := range strings.Split(line, " ") {
58 prefix := ""
59 suffix := ""
60
61 matches := re.FindStringSubmatch(word)
62 if matches != nil && (matches[1] != "" || matches[3] != "") {
63 // we have a color escape sequence
64 prefix = matches[1]
65 word = matches[2]
66 suffix = matches[3]
67 }
68
69 if spaceLeft > len(word) {
70 if !firstWord {
71 lineBuffer.WriteString(" ")
72 spaceLeft -= 1
73 }
74 lineBuffer.WriteString(prefix + word + suffix)
75 spaceLeft -= len(word)
76 firstWord = false
77 } else {
78 if len(word) > lineWidth {
79 for len(word) > 0 {
80 l := minInt(spaceLeft, len(word))
81 part := prefix + word[:l]
82 prefix = ""
83 word = word[l:]
84
85 lineBuffer.WriteString(part)
86 textBuffer.WriteString(pad)
87 textBuffer.Write(lineBuffer.Bytes())
88 lineBuffer.Reset()
89
90 if len(word) > 0 {
91 textBuffer.WriteString("\n")
92 nbLine++
93 }
94
95 spaceLeft = lineWidth - leftPad
96 }
97 } else {
98 textBuffer.WriteString(pad + strings.TrimRight(lineBuffer.String(), " "))
99 textBuffer.WriteString("\n")
100 lineBuffer.Reset()
101 lineBuffer.WriteString(prefix + word + suffix)
102 firstWord = false
103 spaceLeft = lineWidth - len(word)
104 nbLine++
105 }
106 }
107 }
108 textBuffer.WriteString(pad + strings.TrimRight(lineBuffer.String(), " "))
109 lineBuffer.Reset()
110 firstLine = false
111 }
112
113 return textBuffer.String(), nbLine
114}
115
116func minInt(a, b int) int {
117 if a > b {
118 return b
119 }
120 return a
121}