1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-25 13:48:50 +08:00

Allowing container.Option to report an error.

This commit is contained in:
Jakub Sobon 2019-01-14 00:08:20 -05:00
parent d39112bbad
commit 964d676e31
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
12 changed files with 181 additions and 101 deletions

View File

@ -64,7 +64,7 @@ func (c *Container) String() string {
// New returns a new root container that will use the provided terminal and
// applies the provided options.
func New(t terminalapi.Terminal, opts ...Option) *Container {
func New(t terminalapi.Terminal, opts ...Option) (*Container, error) {
size := t.Size()
root := &Container{
term: t,
@ -75,8 +75,10 @@ func New(t terminalapi.Terminal, opts ...Option) *Container {
// Initially the root is focused.
root.focusTracker = newFocusTracker(root)
applyOptions(root, opts...)
return root
if err := applyOptions(root, opts...); err != nil {
return nil, err
}
return root, nil
}
// newChild creates a new child container of the given parent.

View File

@ -33,7 +33,7 @@ import (
// Example demonstrates how to use the Container API.
func Example() {
New(
if _, err := New(
/* terminal = */ nil,
SplitVertical(
Left(
@ -58,20 +58,23 @@ func Example() {
PlaceWidget(fakewidget.New(widgetapi.Options{})),
),
),
)
); err != nil {
panic(err)
}
}
func TestNew(t *testing.T) {
tests := []struct {
desc string
termSize image.Point
container func(ft *faketerm.Terminal) *Container
container func(ft *faketerm.Terminal) (*Container, error)
wantContainerErr bool
want func(size image.Point) *faketerm.Terminal
}{
{
desc: "empty container",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(ft)
},
want: func(size image.Point) *faketerm.Terminal {
@ -81,7 +84,7 @@ func TestNew(t *testing.T) {
{
desc: "container with a border",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -102,7 +105,7 @@ func TestNew(t *testing.T) {
{
desc: "horizontal split, children have borders",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitHorizontal(
@ -127,7 +130,7 @@ func TestNew(t *testing.T) {
{
desc: "horizontal split, parent and children have borders",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -158,7 +161,7 @@ func TestNew(t *testing.T) {
{
desc: "vertical split, children have borders",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitVertical(
@ -183,7 +186,7 @@ func TestNew(t *testing.T) {
{
desc: "vertical split, parent and children have borders",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -214,7 +217,7 @@ func TestNew(t *testing.T) {
{
desc: "multi level split",
termSize: image.Point{10, 16},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitVertical(
@ -255,7 +258,7 @@ func TestNew(t *testing.T) {
{
desc: "inherits border and focused color",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -296,7 +299,7 @@ func TestNew(t *testing.T) {
{
desc: "splitting a container removes the widget",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -328,7 +331,7 @@ func TestNew(t *testing.T) {
{
desc: "placing a widget removes container split",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitVertical(
@ -360,7 +363,14 @@ func TestNew(t *testing.T) {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
if err := tc.container(got).Draw(); err != nil {
cont, err := tc.container(got)
if (err != nil) != tc.wantContainerErr {
t.Errorf("tc.container => unexpected error:%v, wantErr:%v", err, tc.wantContainerErr)
}
if err != nil {
return
}
if err := cont.Draw(); err != nil {
t.Fatalf("Draw => unexpected error: %v", err)
}
@ -376,7 +386,7 @@ func TestKeyboard(t *testing.T) {
tests := []struct {
desc string
termSize image.Point
container func(ft *faketerm.Terminal) *Container
container func(ft *faketerm.Terminal) (*Container, error)
events []terminalapi.Event
want func(size image.Point) *faketerm.Terminal
wantErr bool
@ -384,7 +394,7 @@ func TestKeyboard(t *testing.T) {
{
desc: "event not forwarded if container has no widget",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(ft)
},
events: []terminalapi.Event{
@ -397,7 +407,7 @@ func TestKeyboard(t *testing.T) {
{
desc: "event forwarded to focused container only",
termSize: image.Point{40, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitVertical(
@ -450,7 +460,7 @@ func TestKeyboard(t *testing.T) {
{
desc: "event not forwarded if the widget didn't request it",
termSize: image.Point{40, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{WantKeyboard: false})),
@ -473,7 +483,7 @@ func TestKeyboard(t *testing.T) {
{
desc: "widget returns an error when processing the event",
termSize: image.Point{40, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{WantKeyboard: true})),
@ -503,7 +513,10 @@ func TestKeyboard(t *testing.T) {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
c := tc.container(got)
c, err := tc.container(got)
if err != nil {
t.Fatalf("tc.container => unexpected error: %v", err)
}
for _, ev := range tc.events {
switch e := ev.(type) {
case *terminalapi.Mouse:
@ -537,7 +550,7 @@ func TestMouse(t *testing.T) {
tests := []struct {
desc string
termSize image.Point
container func(ft *faketerm.Terminal) *Container
container func(ft *faketerm.Terminal) (*Container, error)
events []terminalapi.Event
want func(size image.Point) *faketerm.Terminal
wantErr bool
@ -545,7 +558,7 @@ func TestMouse(t *testing.T) {
{
desc: "mouse click outside of the terminal is ignored",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{WantMouse: true})),
@ -569,7 +582,7 @@ func TestMouse(t *testing.T) {
{
desc: "event not forwarded if container has no widget",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(ft)
},
events: []terminalapi.Event{
@ -583,7 +596,7 @@ func TestMouse(t *testing.T) {
{
desc: "event forwarded to container at that point",
termSize: image.Point{50, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
SplitVertical(
@ -636,7 +649,7 @@ func TestMouse(t *testing.T) {
{
desc: "event not forwarded if the widget didn't request it",
termSize: image.Point{20, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{WantMouse: false})),
@ -659,7 +672,7 @@ func TestMouse(t *testing.T) {
{
desc: "event not forwarded if it falls on the container's border",
termSize: image.Point{20, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -693,7 +706,7 @@ func TestMouse(t *testing.T) {
{
desc: "event not forwarded if it falls outside of widget's canvas",
termSize: image.Point{20, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(
@ -723,7 +736,7 @@ func TestMouse(t *testing.T) {
{
desc: "mouse poisition adjusted relative to widget's canvas, vertical offset",
termSize: image.Point{20, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(
@ -754,7 +767,7 @@ func TestMouse(t *testing.T) {
{
desc: "mouse poisition adjusted relative to widget's canvas, horizontal offset",
termSize: image.Point{30, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(
@ -785,7 +798,7 @@ func TestMouse(t *testing.T) {
{
desc: "widget returns an error when processing the event",
termSize: image.Point{40, 20},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{WantMouse: true})),
@ -815,7 +828,10 @@ func TestMouse(t *testing.T) {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
c := tc.container(got)
c, err := tc.container(got)
if err != nil {
t.Fatalf("tc.container => unexpected error: %v", err)
}
for _, ev := range tc.events {
switch e := ev.(type) {
case *terminalapi.Mouse:

View File

@ -32,14 +32,14 @@ func TestDrawWidget(t *testing.T) {
tests := []struct {
desc string
termSize image.Point
container func(ft *faketerm.Terminal) *Container
container func(ft *faketerm.Terminal) (*Container, error)
want func(size image.Point) *faketerm.Terminal
wantErr bool
}{
{
desc: "draws widget with container border",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -66,7 +66,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "draws widget with container border and title aligned on the left",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -100,7 +100,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "draws widget with container border and title aligned in the center",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -135,7 +135,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "draws widget with container border and title aligned on the right",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -170,7 +170,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "draws widget with container border and title that is trimmed",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -205,7 +205,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "draws widget without container border",
termSize: image.Point{9, 5},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{})),
@ -225,7 +225,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget.Draw returns an error",
termSize: image.Point{5, 5}, // Too small for the widget's box.
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -240,7 +240,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "container with border and no space isn't drawn",
termSize: image.Point{1, 1},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -257,7 +257,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "container without the requested space for its widget isn't drawn",
termSize: image.Point{1, 1},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
PlaceWidget(fakewidget.New(widgetapi.Options{
@ -276,7 +276,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget's canvas is limited to the requested maximum size",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -308,7 +308,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget's canvas is limited to the requested maximum width",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -340,7 +340,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget's canvas is limited to the requested maximum height",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -372,7 +372,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget gets the requested aspect ratio",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -404,7 +404,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "widget's canvas is limited to the requested maximum size and ratio",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -436,7 +436,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "horizontal left align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -467,7 +467,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "horizontal center align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -498,7 +498,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "horizontal right align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -529,7 +529,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "vertical top align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -560,7 +560,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "vertical middle align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -591,7 +591,7 @@ func TestDrawWidget(t *testing.T) {
{
desc: "vertical bottom align for the widget",
termSize: image.Point{22, 22},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -624,8 +624,11 @@ func TestDrawWidget(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
got := faketerm.MustNew(tc.termSize)
c := tc.container(got)
err := c.Draw()
c, err := tc.container(got)
if err != nil {
t.Fatalf("tc.container => unexpected error: %v", err)
}
err = c.Draw()
if (err != nil) != tc.wantErr {
t.Errorf("Draw => unexpected error: %v, wantErr: %v", err, tc.wantErr)
}
@ -647,7 +650,7 @@ func TestDrawHandlesTerminalResize(t *testing.T) {
t.Errorf("faketerm.New => unexpected error: %v", err)
}
cont := New(
cont, err := New(
got,
SplitVertical(
Left(
@ -672,6 +675,9 @@ func TestDrawHandlesTerminalResize(t *testing.T) {
),
),
)
if err != nil {
t.Fatalf("New => unexpected error: %v", err)
}
// The following tests aren't hermetic, they all access the same container
// and fake terminal in order to retain state between resizes.

View File

@ -37,13 +37,13 @@ func TestPointCont(t *testing.T) {
tests := []struct {
desc string
termSize image.Point
container func(ft *faketerm.Terminal) *Container
container func(ft *faketerm.Terminal) (*Container, error)
cases []pointCase
}{
{
desc: "single container, no border",
termSize: image.Point{3, 3},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
BorderColor(cell.ColorBlue),
@ -90,7 +90,7 @@ func TestPointCont(t *testing.T) {
{
desc: "single container, border",
termSize: image.Point{3, 3},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -113,7 +113,7 @@ func TestPointCont(t *testing.T) {
{
desc: "split containers, parent has no border",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
BorderColor(cell.ColorBlack),
@ -160,7 +160,7 @@ func TestPointCont(t *testing.T) {
{
desc: "split containers, parent has border",
termSize: image.Point{10, 10},
container: func(ft *faketerm.Terminal) *Container {
container: func(ft *faketerm.Terminal) (*Container, error) {
return New(
ft,
Border(draw.LineStyleLight),
@ -229,7 +229,10 @@ func TestPointCont(t *testing.T) {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
cont := tc.container(ft)
cont, err := tc.container(ft)
if err != nil {
t.Fatalf("tc.container => unexpected error: %v", err)
}
for _, pc := range tc.cases {
gotCont := pointCont(cont, pc.point)
if (gotCont == nil) != pc.wantNil {
@ -382,13 +385,16 @@ func TestFocusTrackerMouse(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
root := New(
root, err := New(
ft,
SplitVertical(
Left(),
Right(),
),
)
if err != nil {
t.Fatalf("New => unexpected error: %v", err)
}
for _, ev := range tc.events {
root.Mouse(ev)

View File

@ -24,16 +24,19 @@ import (
)
// applyOptions applies the options to the container.
func applyOptions(c *Container, opts ...Option) {
func applyOptions(c *Container, opts ...Option) error {
for _, opt := range opts {
opt.set(c)
if err := opt.set(c); err != nil {
return err
}
}
return nil
}
// Option is used to provide options to a container.
type Option interface {
// set sets the provided option.
set(*Container)
set(*Container) error
}
// options stores the options provided to the container.
@ -85,22 +88,24 @@ func newOptions(parent *options) *options {
}
// option implements Option.
type option func(*Container)
type option func(*Container) error
// set implements Option.set.
func (o option) set(c *Container) {
o(c)
func (o option) set(c *Container) error {
return o(c)
}
// SplitVertical splits the container along the vertical axis into two sub
// containers. The use of this option removes any widget placed at this
// container, containers with sub containers cannot contain widgets.
func SplitVertical(l LeftOption, r RightOption) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.split = splitTypeVertical
c.opts.widget = nil
applyOptions(c.createFirst(), l.lOpts()...)
applyOptions(c.createSecond(), r.rOpts()...)
if err := applyOptions(c.createFirst(), l.lOpts()...); err != nil {
return err
}
return applyOptions(c.createSecond(), r.rOpts()...)
})
}
@ -108,11 +113,13 @@ func SplitVertical(l LeftOption, r RightOption) Option {
// containers. The use of this option removes any widget placed at this
// container, containers with sub containers cannot contain widgets.
func SplitHorizontal(t TopOption, b BottomOption) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.split = splitTypeHorizontal
c.opts.widget = nil
applyOptions(c.createFirst(), t.tOpts()...)
applyOptions(c.createSecond(), b.bOpts()...)
if err := applyOptions(c.createFirst(), t.tOpts()...); err != nil {
return err
}
return applyOptions(c.createSecond(), b.bOpts()...)
})
}
@ -120,10 +127,11 @@ func SplitHorizontal(t TopOption, b BottomOption) Option {
// The use of this option removes any sub containers. Containers with sub
// containers cannot have widgets.
func PlaceWidget(w widgetapi.Widget) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.widget = w
c.first = nil
c.second = nil
return nil
})
}
@ -131,8 +139,9 @@ func PlaceWidget(w widgetapi.Widget) Option {
// container. Has no effect if the container contains no widget.
// Defaults alignment in the center.
func AlignHorizontal(h align.Horizontal) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.hAlign = h
return nil
})
}
@ -140,51 +149,58 @@ func AlignHorizontal(h align.Horizontal) Option {
// Has no effect if the container contains no widget.
// Defaults to alignment in the middle.
func AlignVertical(v align.Vertical) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.vAlign = v
return nil
})
}
// Border configures the container to have a border of the specified style.
func Border(ls draw.LineStyle) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.border = ls
return nil
})
}
// BorderTitle sets a text title within the border.
func BorderTitle(title string) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.borderTitle = title
return nil
})
}
// BorderTitleAlignLeft aligns the border title on the left.
func BorderTitleAlignLeft() Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.borderTitleHAlign = align.HorizontalLeft
return nil
})
}
// BorderTitleAlignCenter aligns the border title in the center.
func BorderTitleAlignCenter() Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.borderTitleHAlign = align.HorizontalCenter
return nil
})
}
// BorderTitleAlignRight aligns the border title on the right.
func BorderTitleAlignRight() Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.borderTitleHAlign = align.HorizontalRight
return nil
})
}
// BorderColor sets the color of the border around the container.
// This option is inherited to sub containers created by container splits.
func BorderColor(color cell.Color) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.inherited.borderColor = color
return nil
})
}
@ -192,8 +208,9 @@ func BorderColor(color cell.Color) Option {
// keyboard focus.
// This option is inherited to sub containers created by container splits.
func FocusedColor(color cell.Color) Option {
return option(func(c *Container) {
return option(func(c *Container) error {
c.opts.inherited.focusedColor = color
return nil
})
}

View File

@ -30,7 +30,7 @@ func TestRoot(t *testing.T) {
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
want := New(
want, err := New(
ft,
SplitHorizontal(
Top(
@ -42,6 +42,9 @@ func TestRoot(t *testing.T) {
Bottom(),
),
)
if err != nil {
t.Fatalf("New => unexpected error: %v", err)
}
if got := rootCont(want); got != want {
t.Errorf("rootCont(root) => got %p, want %p", got, want)
@ -58,7 +61,7 @@ func TestTraversal(t *testing.T) {
if err != nil {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
cont := New(
cont, err := New(
ft,
BorderColor(cell.ColorBlack),
SplitVertical(
@ -86,6 +89,9 @@ func TestTraversal(t *testing.T) {
),
),
)
if err != nil {
t.Fatalf("New => unexpected error: %v", err)
}
tests := []struct {
desc string

View File

@ -50,7 +50,7 @@ func Example() {
}
// Create the container with two fake widgets.
c := container.New(
c, err := container.New(
t,
container.SplitVertical(
container.Left(
@ -61,6 +61,9 @@ func Example() {
),
),
)
if err != nil {
panic(err)
}
// Termdash runs until the context expires.
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
@ -86,10 +89,13 @@ func Example_triggered() {
}
// Create the container with a widget.
c := container.New(
c, err := container.New(
t,
container.PlaceWidget(fakewidget.New(wOpts)),
)
if err != nil {
panic(err)
}
// Create the controller and disable periodic redraw.
ctrl, err := NewController(t, c)
@ -332,13 +338,16 @@ func TestRun(t *testing.T) {
t.Fatalf("faketerm.New => unexpected error: %v", err)
}
cont := container.New(
cont, err := container.New(
got,
container.PlaceWidget(fakewidget.New(widgetapi.Options{
WantKeyboard: true,
WantMouse: true,
})),
)
if err != nil {
t.Fatalf("container.New => unexpected error: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Millisecond)
err = Run(ctx, got, cont, tc.opts...)
@ -511,10 +520,13 @@ func TestController(t *testing.T) {
WantKeyboard: true,
WantMouse: true,
})
cont := container.New(
cont, err := container.New(
got,
container.PlaceWidget(mi),
)
if err != nil {
t.Fatalf("container.New => unexpected error: %v", err)
}
ctrl, err := NewController(got, cont, tc.opts...)
if (err != nil) != tc.wantErr {

View File

@ -93,12 +93,15 @@ func main() {
)
go playBarChart(ctx, bc, 1*time.Second)
c := container.New(
c, err := container.New(
t,
container.Border(draw.LineStyleLight),
container.BorderTitle("PRESS Q TO QUIT"),
container.PlaceWidget(bc),
)
if err != nil {
panic(err)
}
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {

View File

@ -115,7 +115,7 @@ func main() {
)
go playGauge(ctx, withLabel, 3, 500*time.Millisecond, playTypePercent)
c := container.New(
c, err := container.New(
t,
container.SplitVertical(
container.Left(
@ -147,6 +147,9 @@ func main() {
),
),
)
if err != nil {
panic(err)
}
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {

View File

@ -88,12 +88,15 @@ func main() {
linechart.XLabelCellOpts(cell.FgColor(cell.ColorCyan)),
)
go playLineChart(ctx, lc, redrawInterval/3)
c := container.New(
c, err := container.New(
t,
container.Border(draw.LineStyleLight),
container.BorderTitle("PRESS Q TO QUIT"),
container.PlaceWidget(lc),
)
if err != nil {
panic(err)
}
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {

View File

@ -75,7 +75,7 @@ func main() {
)
go playSparkLine(ctx, yellow, 1*time.Second)
c := container.New(
c, err := container.New(
t,
container.Border(draw.LineStyleLight),
container.BorderTitle("PRESS Q TO QUIT"),
@ -103,6 +103,9 @@ func main() {
),
),
)
if err != nil {
panic(err)
}
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {

View File

@ -106,7 +106,7 @@ func main() {
}
go writeLines(ctx, rolled, 1*time.Second)
c := container.New(
c, err := container.New(
t,
container.Border(draw.LineStyleLight),
container.BorderTitle("PRESS Q TO QUIT"),
@ -148,6 +148,9 @@ func main() {
),
),
)
if err != nil {
panic(err)
}
quitter := func(k *terminalapi.Keyboard) {
if k.Key == 'q' || k.Key == 'Q' {