diff --git a/cui/cui.go b/cui/cui.go index f02ba14..67d8b3a 100644 --- a/cui/cui.go +++ b/cui/cui.go @@ -81,20 +81,22 @@ func Clear(dir string) { } -func wrapLines(s []string, length int) []string { +// takes the document content (as a slice) and modifies any lines that are longer +// than the specified console width, splitting them over two lines. returns the +// amended document content as a slice. +// word wrapping uses a "greedy" algorithm +func wrapLines(s []string, consolewidth int) []string { out := []string{} for _, ln := range s { - if len(ln) <= length { + if len(ln) <= consolewidth { out = append(out, ln) } else { - words := strings.Split(ln, " ") + words := strings.SplitAfter(ln, " ") var subout bytes.Buffer for i, wd := range words { sublen := subout.Len() - if sublen+len(wd)+1 <= length { - if sublen > 0 { - subout.WriteString(" ") - } + wdlen := len(wd) + if sublen+wdlen <= consolewidth { subout.WriteString(wd) if i == len(words)-1 { out = append(out, subout.String()) diff --git a/cui/cui_test.go b/cui/cui_test.go new file mode 100644 index 0000000..1a286d3 --- /dev/null +++ b/cui/cui_test.go @@ -0,0 +1,52 @@ +package cui + +import ( + "reflect" + "testing" +) + +// tests related to issue 31 +func Test_wrapLines_space_preservation(t *testing.T) { + tables := []struct { + testinput []string + expectedoutput []string + linelength int + }{ + { + //normal sentence - 20 characters - should not wrap + []string{"it is her fav thingy"}, + []string{"it is her fav thingy"}, + 20, + }, + { + //normal sentence - more than 20 characters - should wrap with a space at the end of the first line + []string{"it is her favourite thing in the world"}, + []string{ + "it is her favourite ", + "thing in the world", + }, + 20, + }, + } + + for _, table := range tables { + output := wrapLines(table.testinput, table.linelength) + + if !reflect.DeepEqual(output, table.expectedoutput) { + t.Errorf("Expected %v, got %v", table.expectedoutput, output) + } + } +} + +func Benchmark_wrapLines(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++ { + wrapLines(teststring, 20) + } +}