Bugfixes and refactoring

Bugfixes:

 - Fixes a bug which placed the tree dots (…) for overflown list on the wrong position.

Refactoring

 - Renamed `TextRender` to `TextRenderer`
 - Renamed `NoopRenderer` to `PlainRenderer`
 - Renamed `NoopRendererFactory` to `PlainRendererFactory`
This commit is contained in:
Matteo Kloiber 2015-04-06 00:15:11 +02:00
parent 769ce01ae8
commit 3c08053c57
4 changed files with 65 additions and 60 deletions

View File

@ -19,8 +19,8 @@ func commonList() *termui.List {
list := termui.NewList() list := termui.NewList()
list.Items = strs list.Items = strs
list.Height = 20 list.Height = 15
list.Width = 25 list.Width = 26
list.RendererFactory = termui.MarkdownTextRendererFactory{} list.RendererFactory = termui.MarkdownTextRendererFactory{}
return list return list

63
list.go
View File

@ -42,49 +42,54 @@ func NewList() *List {
l.Overflow = "hidden" l.Overflow = "hidden"
l.ItemFgColor = theme.ListItemFg l.ItemFgColor = theme.ListItemFg
l.ItemBgColor = theme.ListItemBg l.ItemBgColor = theme.ListItemBg
l.RendererFactory = NoopRendererFactory{} l.RendererFactory = PlainRendererFactory{}
return l return l
} }
// Buffer implements Bufferer interface. // Buffer implements Bufferer interface.
func (l *List) Buffer() []Point { func (l *List) Buffer() []Point {
ps := l.Block.Buffer() buffer := l.Block.Buffer()
switch l.Overflow {
case "wrap":
y := 0
for _, item := range l.Items {
x := 0
renderer := l.RendererFactory.TextRenderer(item) breakLoop := func(y int) bool {
sequence := renderer.Render(l.ItemFgColor, l.ItemBgColor) return y+1 > l.innerHeight
for n := range []rune(sequence.NormalizedText) { }
point, width := sequence.PointAt(n, x+l.innerX, y+l.innerY) y := 0
if width+x <= l.innerWidth { MainLoop:
ps = append(ps, point) for _, item := range l.Items {
x += width x := 0
} else { 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++ y++
if breakLoop(y) {
break MainLoop
}
x = 0 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": y++
trimItems := l.Items if breakLoop(y) {
if len(trimItems) > l.innerHeight { break MainLoop
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...)
} }
} }
return l.Block.chopOverflow(ps) return l.Block.chopOverflow(buffer)
} }

View File

@ -5,8 +5,8 @@ import (
"strings" "strings"
) )
// TextRender adds common methods for rendering a text on screeen. // TextRenderer adds common methods for rendering a text on screeen.
type TextRender interface { type TextRenderer interface {
NormalizedText() string NormalizedText() string
Render(lastColor, background Attribute) RenderedSequence Render(lastColor, background Attribute) RenderedSequence
RenderSequence(start, end int, 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. // TextRendererFactory is factory for creating text renderers.
type TextRendererFactory interface { type TextRendererFactory interface {
TextRenderer(text string) TextRender TextRenderer(text string) TextRenderer
} }
// MarkdownRegex is used by MarkdownTextRenderer to determine how to format the // 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{} type MarkdownTextRendererFactory struct{}
// TextRenderer returns a MarkdownTextRenderer instance. // TextRenderer returns a MarkdownTextRenderer instance.
func (f MarkdownTextRendererFactory) TextRenderer(text string) TextRender { func (f MarkdownTextRendererFactory) TextRenderer(text string) TextRenderer {
return MarkdownTextRenderer{text} 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) return Point{char, s.BackgroundColor, color, x, y}, charWidth(char)
} }
// A NoopRenderer does not render the text at all. // A PlainRenderer does not render the text at all.
type NoopRenderer struct { type PlainRenderer struct {
Text string Text string
} }
// NormalizedText returns the text given in // NormalizedText returns the text given in
func (r NoopRenderer) NormalizedText() string { func (r PlainRenderer) NormalizedText() string {
return r.Text return r.Text
} }
// RenderSequence returns a RenderedSequence that does not have any color // RenderSequence returns a RenderedSequence that does not have any color
// sequences. // 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) runes := []rune(r.Text)
if end < 0 { if end < 0 {
end = len(runes) end = len(runes)
@ -231,15 +231,15 @@ func (r NoopRenderer) RenderSequence(start, end int, lastColor, background Attri
} }
// Render just like RenderSequence // 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) return r.RenderSequence(0, -1, lastColor, background)
} }
// NoopRendererFactory is a TextRendererFactory for // PlainRendererFactory is a TextRendererFactory for
// the NoopRenderer. // the PlainRenderer.
type NoopRendererFactory struct{} type PlainRendererFactory struct{}
// TextRenderer returns a NoopRenderer instance. // TextRenderer returns a PlainRenderer instance.
func (f NoopRendererFactory) TextRenderer(text string) TextRender { func (f PlainRendererFactory) TextRenderer(text string) TextRenderer {
return NoopRenderer{text} return PlainRenderer{text}
} }

View File

@ -10,17 +10,17 @@ import (
) )
func TestTextRender_TestInterface(t *testing.T) { func TestTextRender_TestInterface(t *testing.T) {
var inter *TextRender var inter *TextRenderer
assert.Implements(t, inter, new(MarkdownTextRenderer)) assert.Implements(t, inter, new(MarkdownTextRenderer))
assert.Implements(t, inter, new(NoopRenderer)) assert.Implements(t, inter, new(PlainRenderer))
} }
func TestTextRendererFactory_TestInterface(t *testing.T) { func TestTextRendererFactory_TestInterface(t *testing.T) {
var inter *TextRendererFactory var inter *TextRendererFactory
assert.Implements(t, inter, new(MarkdownTextRendererFactory)) assert.Implements(t, inter, new(MarkdownTextRendererFactory))
assert.Implements(t, inter, new(NoopRendererFactory)) assert.Implements(t, inter, new(PlainRendererFactory))
} }
func TestMarkdownTextRenderer_normalizeText(t *testing.T) { 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) AssertPoint(t, pointAt(10, 7, 1), 'd', 7, 1)
} }
func getTestNoopRenderer() NoopRenderer { func getTestPlainRenderer() PlainRenderer {
return NoopRenderer{"[Hello](red) \x1b[31mworld"} return PlainRenderer{"[Hello](red) \x1b[31mworld"}
} }
func TestNoopRenderer_NormalizedText(t *testing.T) { func TestPlainRenderer_NormalizedText(t *testing.T) {
r := getTestNoopRenderer() r := getTestPlainRenderer()
assert.Equal(t, "[Hello](red) \x1b[31mworld", r.NormalizedText()) assert.Equal(t, "[Hello](red) \x1b[31mworld", r.NormalizedText())
assert.Equal(t, "[Hello](red) \x1b[31mworld", r.Text) assert.Equal(t, "[Hello](red) \x1b[31mworld", r.Text)
} }
func TestNoopRenderer_Render(t *testing.T) { func TestPlainRenderer_Render(t *testing.T) {
renderer := getTestNoopRenderer() renderer := getTestPlainRenderer()
got := renderer.Render(5, 7) got := renderer.Render(5, 7)
assertRenderSequence(t, got, 5, 7, "[Hello](red) \x1b[31mworld", 0) assertRenderSequence(t, got, 5, 7, "[Hello](red) \x1b[31mworld", 0)
} }
func TestNoopRenderer_RenderSequence(t *testing.T) { func TestPlainRenderer_RenderSequence(t *testing.T) {
renderer := getTestNoopRenderer() renderer := getTestPlainRenderer()
got := renderer.RenderSequence(3, 5, 9, 1) got := renderer.RenderSequence(3, 5, 9, 1)
assertRenderSequence(t, got, 9, 1, "ll", 0) assertRenderSequence(t, got, 9, 1, "ll", 0)
} }
func TestNoopRendererFactory(t *testing.T) { func TestPlainRendererFactory(t *testing.T) {
factory := NoopRendererFactory{} factory := PlainRendererFactory{}
expected := NoopRenderer{"Hello world"} expected := PlainRenderer{"Hello world"}
assert.Equal(t, factory.TextRenderer("Hello world"), expected) assert.Equal(t, factory.TextRenderer("Hello world"), expected)
} }