diff --git a/example/coloredList.go b/example/coloredList.go index 284d488..6fc6aa2 100644 --- a/example/coloredList.go +++ b/example/coloredList.go @@ -19,8 +19,8 @@ func commonList() *termui.List { list := termui.NewList() list.Items = strs - list.Height = 20 - list.Width = 25 + list.Height = 15 + list.Width = 26 list.RendererFactory = termui.MarkdownTextRendererFactory{} return list diff --git a/list.go b/list.go index f5373a0..e6e5f11 100644 --- a/list.go +++ b/list.go @@ -42,49 +42,54 @@ func NewList() *List { l.Overflow = "hidden" l.ItemFgColor = theme.ListItemFg l.ItemBgColor = theme.ListItemBg - l.RendererFactory = NoopRendererFactory{} + l.RendererFactory = PlainRendererFactory{} return l } // Buffer implements Bufferer interface. func (l *List) Buffer() []Point { - ps := l.Block.Buffer() - switch l.Overflow { - case "wrap": - y := 0 - for _, item := range l.Items { - x := 0 + buffer := l.Block.Buffer() - renderer := l.RendererFactory.TextRenderer(item) - sequence := renderer.Render(l.ItemFgColor, l.ItemBgColor) - for n := range []rune(sequence.NormalizedText) { - point, width := sequence.PointAt(n, x+l.innerX, y+l.innerY) + breakLoop := func(y int) bool { + return y+1 > l.innerHeight + } + y := 0 - if width+x <= l.innerWidth { - ps = append(ps, point) - x += width - } else { +MainLoop: + for _, item := range l.Items { + x := 0 + bg, fg := l.ItemFgColor, l.ItemBgColor + renderer := l.RendererFactory.TextRenderer(item) + sequence := renderer.Render(bg, fg) + + for n := range []rune(sequence.NormalizedText) { + point, width := sequence.PointAt(n, x+l.innerX, y+l.innerY) + + if width+x <= l.innerWidth { + buffer = append(buffer, point) + x += width + } else { + if l.Overflow == "wrap" { y++ + if breakLoop(y) { + break MainLoop + } x = 0 + } else { + dotR := []rune(dot)[0] + dotX := l.innerWidth + l.innerX - charWidth(dotR) + p := newPointWithAttrs(dotR, dotX, y+l.innerY, bg, fg) + buffer = append(buffer, p) + break } } - y++ } - case "hidden": - trimItems := l.Items - if len(trimItems) > l.innerHeight { - trimItems = trimItems[:l.innerHeight] - } - - for y, item := range trimItems { - text := TrimStrIfAppropriate(item, l.innerWidth) - render := l.RendererFactory.TextRenderer(text) - sequence := render.RenderSequence(0, -1, l.ItemFgColor, l.ItemBgColor) - t, _ := sequence.Buffer(l.innerX, y+l.innerY) - ps = append(ps, t...) + y++ + if breakLoop(y) { + break MainLoop } } - return l.Block.chopOverflow(ps) + return l.Block.chopOverflow(buffer) } diff --git a/textRender.go b/textRender.go index df99bac..dd6c96f 100644 --- a/textRender.go +++ b/textRender.go @@ -5,8 +5,8 @@ import ( "strings" ) -// TextRender adds common methods for rendering a text on screeen. -type TextRender interface { +// TextRenderer adds common methods for rendering a text on screeen. +type TextRenderer interface { NormalizedText() string Render(lastColor, background Attribute) RenderedSequence RenderSequence(start, end int, lastColor, background Attribute) RenderedSequence @@ -14,7 +14,7 @@ type TextRender interface { // TextRendererFactory is factory for creating text renderers. type TextRendererFactory interface { - TextRenderer(text string) TextRender + TextRenderer(text string) TextRenderer } // MarkdownRegex is used by MarkdownTextRenderer to determine how to format the @@ -134,7 +134,7 @@ func (r MarkdownTextRenderer) RenderSequence(start, end int, lastColor, backgrou type MarkdownTextRendererFactory struct{} // TextRenderer returns a MarkdownTextRenderer instance. -func (f MarkdownTextRendererFactory) TextRenderer(text string) TextRender { +func (f MarkdownTextRendererFactory) TextRenderer(text string) TextRenderer { return MarkdownTextRenderer{text} } @@ -207,19 +207,19 @@ func (s *RenderedSequence) PointAt(n, x, y int) (Point, int) { return Point{char, s.BackgroundColor, color, x, y}, charWidth(char) } -// A NoopRenderer does not render the text at all. -type NoopRenderer struct { +// A PlainRenderer does not render the text at all. +type PlainRenderer struct { Text string } // NormalizedText returns the text given in -func (r NoopRenderer) NormalizedText() string { +func (r PlainRenderer) NormalizedText() string { return r.Text } // RenderSequence returns a RenderedSequence that does not have any color // sequences. -func (r NoopRenderer) RenderSequence(start, end int, lastColor, background Attribute) RenderedSequence { +func (r PlainRenderer) RenderSequence(start, end int, lastColor, background Attribute) RenderedSequence { runes := []rune(r.Text) if end < 0 { end = len(runes) @@ -231,15 +231,15 @@ func (r NoopRenderer) RenderSequence(start, end int, lastColor, background Attri } // Render just like RenderSequence -func (r NoopRenderer) Render(lastColor, background Attribute) RenderedSequence { +func (r PlainRenderer) Render(lastColor, background Attribute) RenderedSequence { return r.RenderSequence(0, -1, lastColor, background) } -// NoopRendererFactory is a TextRendererFactory for -// the NoopRenderer. -type NoopRendererFactory struct{} +// PlainRendererFactory is a TextRendererFactory for +// the PlainRenderer. +type PlainRendererFactory struct{} -// TextRenderer returns a NoopRenderer instance. -func (f NoopRendererFactory) TextRenderer(text string) TextRender { - return NoopRenderer{text} +// TextRenderer returns a PlainRenderer instance. +func (f PlainRendererFactory) TextRenderer(text string) TextRenderer { + return PlainRenderer{text} } diff --git a/textRender_test.go b/textRender_test.go index 8263d40..c9e372b 100644 --- a/textRender_test.go +++ b/textRender_test.go @@ -10,17 +10,17 @@ import ( ) func TestTextRender_TestInterface(t *testing.T) { - var inter *TextRender + var inter *TextRenderer assert.Implements(t, inter, new(MarkdownTextRenderer)) - assert.Implements(t, inter, new(NoopRenderer)) + assert.Implements(t, inter, new(PlainRenderer)) } func TestTextRendererFactory_TestInterface(t *testing.T) { var inter *TextRendererFactory assert.Implements(t, inter, new(MarkdownTextRendererFactory)) - assert.Implements(t, inter, new(NoopRendererFactory)) + assert.Implements(t, inter, new(PlainRendererFactory)) } func TestMarkdownTextRenderer_normalizeText(t *testing.T) { @@ -232,31 +232,31 @@ func TestRenderedSequence_PointAt(t *testing.T) { AssertPoint(t, pointAt(10, 7, 1), 'd', 7, 1) } -func getTestNoopRenderer() NoopRenderer { - return NoopRenderer{"[Hello](red) \x1b[31mworld"} +func getTestPlainRenderer() PlainRenderer { + return PlainRenderer{"[Hello](red) \x1b[31mworld"} } -func TestNoopRenderer_NormalizedText(t *testing.T) { - r := getTestNoopRenderer() +func TestPlainRenderer_NormalizedText(t *testing.T) { + r := getTestPlainRenderer() assert.Equal(t, "[Hello](red) \x1b[31mworld", r.NormalizedText()) assert.Equal(t, "[Hello](red) \x1b[31mworld", r.Text) } -func TestNoopRenderer_Render(t *testing.T) { - renderer := getTestNoopRenderer() +func TestPlainRenderer_Render(t *testing.T) { + renderer := getTestPlainRenderer() got := renderer.Render(5, 7) assertRenderSequence(t, got, 5, 7, "[Hello](red) \x1b[31mworld", 0) } -func TestNoopRenderer_RenderSequence(t *testing.T) { - renderer := getTestNoopRenderer() +func TestPlainRenderer_RenderSequence(t *testing.T) { + renderer := getTestPlainRenderer() got := renderer.RenderSequence(3, 5, 9, 1) assertRenderSequence(t, got, 9, 1, "ll", 0) } -func TestNoopRendererFactory(t *testing.T) { - factory := NoopRendererFactory{} - expected := NoopRenderer{"Hello world"} +func TestPlainRendererFactory(t *testing.T) { + factory := PlainRendererFactory{} + expected := PlainRenderer{"Hello world"} assert.Equal(t, factory.TextRenderer("Hello world"), expected) }