text.go

  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}