Using slice of runes for calculating lengths

This commit is contained in:
asdf 2019-09-12 12:49:51 +10:00
parent 38c9721817
commit 45596d4e8d
2 changed files with 9 additions and 91 deletions

View File

@ -7,7 +7,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"strings" "strings"
"unicode/utf8"
) )
var shapes = map[string]string{ var shapes = map[string]string{
@ -82,10 +81,14 @@ func Clear(dir string) {
} }
// takes the document content (as a slice) and modifies any lines that are longer // Takes the document content (as a slice of strings) and wraps any lines that
// than the specified console width, splitting them over two lines. returns the // are longer than the specified console width. returns the amended document
// amended document content as a slice. // content as a slice of strings.
// word wrapping uses a "greedy" algorithm // Word wrapping uses a "greedy" algorithm, where long lines are split in to
// words, and then rebuilt word by word to fill the available space. any
// leftover words overflow to the next line.
// To offer some support for unicode, some lengths are calculated using a slice
// of runes in the following way: len([]rune(string))
func wrapLines(s []string, consolewidth int) []string { func wrapLines(s []string, consolewidth int) []string {
out := []string{} out := []string{}
for _, ln := range s { for _, ln := range s {
@ -172,65 +175,3 @@ func HandleAlternateScreen(opt string) {
// to run // to run
_ = cmd.Run() _ = cmd.Run()
} }
func wrapLines2(s []string, consolewidth int) []string {
out := []string{}
for _, ln := range s {
if utf8.RuneCountInString(ln) <= consolewidth {
out = append(out, ln)
} else {
words := strings.SplitAfter(ln, " ")
var subout bytes.Buffer
for i, wd := range words {
sublen := subout.Len()
wdlen := utf8.RuneCountInString(wd)
if sublen+wdlen <= consolewidth {
subout.WriteString(wd)
if i == len(words)-1 {
out = append(out, subout.String())
}
} else {
out = append(out, subout.String())
subout.Reset()
subout.WriteString(wd)
if i == len(words)-1 {
out = append(out, subout.String())
subout.Reset()
}
}
}
}
}
return out
}
func wrapLines3(s []string, consolewidth int) []string {
out := []string{}
for _, ln := range s {
if len(ln) <= consolewidth {
out = append(out, ln)
} else {
words := strings.SplitAfter(ln, " ")
var subout bytes.Buffer
for i, wd := range words {
sublen := subout.Len()
wdlen := len(wd)
if sublen+wdlen <= consolewidth {
subout.WriteString(wd)
if i == len(words)-1 {
out = append(out, subout.String())
}
} else {
out = append(out, subout.String())
subout.Reset()
subout.WriteString(wd)
if i == len(words)-1 {
out = append(out, subout.String())
subout.Reset()
}
}
}
}
}
return out
}

View File

@ -69,6 +69,7 @@ func Test_wrapLines_incorrect_wrapping_endash(t *testing.T) {
} }
} }
} }
func Benchmark_wrapLines(b *testing.B) { func Benchmark_wrapLines(b *testing.B) {
teststring := []string{ teststring := []string{
"0123456789", "0123456789",
@ -81,27 +82,3 @@ func Benchmark_wrapLines(b *testing.B) {
wrapLines(teststring, 20) wrapLines(teststring, 20)
} }
} }
func Benchmark_wrapLines2(b *testing.B) {
teststring := []string{
"0123456789",
"a really long line that will prolly be wrapped",
"a l i n e w i t h a l o t o f w o r d s",
"onehugelongwordaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
wrapLines2(teststring, 20)
}
}
func Benchmark_wrapLines3(b *testing.B) {
teststring := []string{
"0123456789",
"a really long line that will prolly be wrapped",
"a l i n e w i t h a l o t o f w o r d s",
"onehugelongwordaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
b.ResetTimer()
for n := 0; n < b.N; n++ {
wrapLines3(teststring, 20)
}
}