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 var textBuffer bytes.Buffer
33 var lineBuffer bytes.Buffer
34 nbLine := 1
35 firstLine := true
36
37 // tabs are formatted as 4 spaces
38 text = strings.Replace(text, "\t", " ", 4)
39
40 re := regexp.MustCompile(`(\x1b\[\d+m)?([^\x1b]*)(\x1b\[\d+m)?`)
41
42 for _, line := range strings.Split(text, "\n") {
43 spaceLeft := lineWidth
44
45 if !firstLine {
46 textBuffer.WriteString("\n")
47 nbLine++
48 }
49
50 firstWord := true
51
52 for _, word := range strings.Split(line, " ") {
53 prefix := ""
54 suffix := ""
55
56 matches := re.FindStringSubmatch(word)
57 if matches != nil && (matches[1] != "" || matches[3] != "") {
58 // we have a color escape sequence
59 prefix = matches[1]
60 word = matches[2]
61 suffix = matches[3]
62 }
63
64 if spaceLeft > len(word) {
65 if !firstWord {
66 lineBuffer.WriteString(" ")
67 spaceLeft -= 1
68 }
69 lineBuffer.WriteString(prefix + word + suffix)
70 spaceLeft -= len(word)
71 firstWord = false
72 } else {
73 if len(word) > lineWidth {
74 for len(word) > 0 {
75 l := minInt(spaceLeft, len(word))
76 part := prefix + word[:l]
77 prefix = ""
78 word = word[l:]
79
80 lineBuffer.WriteString(part)
81 textBuffer.Write(lineBuffer.Bytes())
82 lineBuffer.Reset()
83
84 if len(word) > 0 {
85 textBuffer.WriteString("\n")
86 nbLine++
87 }
88
89 spaceLeft = lineWidth
90 }
91 } else {
92 textBuffer.WriteString(strings.TrimRight(lineBuffer.String(), " "))
93 textBuffer.WriteString("\n")
94 lineBuffer.Reset()
95 lineBuffer.WriteString(prefix + word + suffix)
96 firstWord = false
97 spaceLeft = lineWidth - len(word)
98 nbLine++
99 }
100 }
101 }
102 textBuffer.WriteString(strings.TrimRight(lineBuffer.String(), " "))
103 lineBuffer.Reset()
104 firstLine = false
105 }
106
107 return textBuffer.String(), nbLine
108}
109
110func minInt(a, b int) int {
111 if a > b {
112 return b
113 }
114 return a
115}