gitea-tea/vendor/github.com/muesli/reflow/wordwrap/wordwrap.go
6543 d5058b3b20 Update Vendors (#250)
update go min version

Update Vendors:
 * code.gitea.io/gitea-vet v0.2.0 -> v0.2.1
 * code.gitea.io/sdk/gitea v0.13.0 -> v0.13.1
 * github.com/AlecAivazis/survey v2.1.1 -> v2.2.2
 * github.com/adrg/xdg v0.2.1 -> v0.2.2
 * github.com/araddon/dateparse d820a6159ab1 -> 8aadafed4dc4
 * github.com/go-git/go-git v5.1.0 -> v5.2.0
 * github.com/muesli/termenv v0.7.2 -> v0.7.4
 * github.com/stretchr/testify v1.5.1 -> v1.6.1
 * github.com/urfave/cli v2.2.0 -> v2.3.0

Co-authored-by: 6543 <6543@obermui.de>
Reviewed-on: https://gitea.com/gitea/tea/pulls/250
Reviewed-by: Andrew Thornton <art27@cantab.net>
Reviewed-by: mrsdizzie <info@mrsdizzie.com>
Co-Authored-By: 6543 <6543@noreply.gitea.io>
Co-Committed-By: 6543 <6543@noreply.gitea.io>
2020-11-09 23:25:54 +08:00

168 lines
3.5 KiB
Go

package wordwrap
import (
"bytes"
"strings"
"unicode"
"github.com/muesli/reflow/ansi"
)
var (
defaultBreakpoints = []rune{'-'}
defaultNewline = []rune{'\n'}
)
// WordWrap contains settings and state for customisable text reflowing with
// support for ANSI escape sequences. This means you can style your terminal
// output without affecting the word wrapping algorithm.
type WordWrap struct {
Limit int
Breakpoints []rune
Newline []rune
KeepNewlines bool
buf bytes.Buffer
space bytes.Buffer
word ansi.Buffer
lineLen int
ansi bool
}
// NewWriter returns a new instance of a word-wrapping writer, initialized with
// default settings.
func NewWriter(limit int) *WordWrap {
return &WordWrap{
Limit: limit,
Breakpoints: defaultBreakpoints,
Newline: defaultNewline,
KeepNewlines: true,
}
}
// Bytes is shorthand for declaring a new default WordWrap instance,
// used to immediately word-wrap a byte slice.
func Bytes(b []byte, limit int) []byte {
f := NewWriter(limit)
_, _ = f.Write(b)
f.Close()
return f.Bytes()
}
// String is shorthand for declaring a new default WordWrap instance,
// used to immediately word-wrap a string.
func String(s string, limit int) string {
return string(Bytes([]byte(s), limit))
}
func (w *WordWrap) addSpace() {
w.lineLen += w.space.Len()
w.buf.Write(w.space.Bytes())
w.space.Reset()
}
func (w *WordWrap) addWord() {
if w.word.Len() > 0 {
w.addSpace()
w.lineLen += w.word.PrintableRuneWidth()
w.buf.Write(w.word.Bytes())
w.word.Reset()
}
}
func (w *WordWrap) addNewLine() {
w.buf.WriteRune('\n')
w.lineLen = 0
w.space.Reset()
}
func inGroup(a []rune, c rune) bool {
for _, v := range a {
if v == c {
return true
}
}
return false
}
// Write is used to write more content to the word-wrap buffer.
func (w *WordWrap) Write(b []byte) (int, error) {
if w.Limit == 0 {
return w.buf.Write(b)
}
s := string(b)
if !w.KeepNewlines {
s = strings.Replace(strings.TrimSpace(s), "\n", " ", -1)
}
for _, c := range s {
if c == '\x1B' {
// ANSI escape sequence
w.word.WriteRune(c)
w.ansi = true
} else if w.ansi {
w.word.WriteRune(c)
if (c >= 0x40 && c <= 0x5a) || (c >= 0x61 && c <= 0x7a) {
// ANSI sequence terminated
w.ansi = false
}
} else if inGroup(w.Newline, c) {
// end of current line
// see if we can add the content of the space buffer to the current line
if w.word.Len() == 0 {
if w.lineLen+w.space.Len() > w.Limit {
w.lineLen = 0
} else {
// preserve whitespace
w.buf.Write(w.space.Bytes())
}
w.space.Reset()
}
w.addWord()
w.addNewLine()
} else if unicode.IsSpace(c) {
// end of current word
w.addWord()
w.space.WriteRune(c)
} else if inGroup(w.Breakpoints, c) {
// valid breakpoint
w.addSpace()
w.addWord()
w.buf.WriteRune(c)
} else {
// any other character
w.word.WriteRune(c)
// add a line break if the current word would exceed the line's
// character limit
if w.lineLen+w.space.Len()+w.word.PrintableRuneWidth() > w.Limit &&
w.word.PrintableRuneWidth() < w.Limit {
w.addNewLine()
}
}
}
return len(b), nil
}
// Close will finish the word-wrap operation. Always call it before trying to
// retrieve the final result.
func (w *WordWrap) Close() error {
w.addWord()
return nil
}
// Bytes returns the word-wrapped result as a byte slice.
func (w *WordWrap) Bytes() []byte {
return w.buf.Bytes()
}
// String returns the word-wrapped result as a string.
func (w *WordWrap) String() string {
return w.buf.String()
}