summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--go.mod1
-rw-r--r--lib/ui/borders.go16
-rw-r--r--lib/ui/context.go86
-rw-r--r--lib/ui/fill.go4
-rw-r--r--lib/ui/interactive.go6
-rw-r--r--lib/ui/stack.go9
-rw-r--r--lib/ui/tab.go19
-rw-r--r--lib/ui/text.go18
-rw-r--r--lib/ui/ui.go48
-rw-r--r--widgets/aerc.go24
-rw-r--r--widgets/exline.go49
-rw-r--r--widgets/status.go30
12 files changed, 151 insertions, 159 deletions
diff --git a/go.mod b/go.mod
index cc52cd8..c41cca6 100644
--- a/go.mod
+++ b/go.mod
@@ -6,4 +6,5 @@ require (
 	"github.com/mattn/go-isatty" v0.0.3
 	"github.com/mattn/go-runewidth" v0.0.2
 	"github.com/nsf/termbox-go" v0.0.0-20180129072728-88b7b944be8b
+	"github.com/gdamore/tcell" v1.0.0
 )
diff --git a/lib/ui/borders.go b/lib/ui/borders.go
index 08071ad..38b35fd 100644
--- a/lib/ui/borders.go
+++ b/lib/ui/borders.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 const (
@@ -45,27 +45,23 @@ func (bordered *Bordered) Draw(ctx *Context) {
 	y := 0
 	width := ctx.Width()
 	height := ctx.Height()
-	cell := tb.Cell{
-		Ch: ' ',
-		Fg: tb.ColorBlack,
-		Bg: tb.ColorWhite,
-	}
+	style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
 	if bordered.borders&BORDER_LEFT != 0 {
-		ctx.Fill(0, 0, 1, ctx.Height(), cell)
+		ctx.Fill(0, 0, 1, ctx.Height(), ' ', style)
 		x += 1
 		width -= 1
 	}
 	if bordered.borders&BORDER_TOP != 0 {
-		ctx.Fill(0, 0, ctx.Width(), 1, cell)
+		ctx.Fill(0, 0, ctx.Width(), 1, ' ', style)
 		y += 1
 		height -= 1
 	}
 	if bordered.borders&BORDER_RIGHT != 0 {
-		ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), cell)
+		ctx.Fill(ctx.Width()-1, 0, 1, ctx.Height(), ' ', style)
 		width -= 1
 	}
 	if bordered.borders&BORDER_BOTTOM != 0 {
-		ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, cell)
+		ctx.Fill(0, ctx.Height()-1, ctx.Width(), 1, ' ', style)
 		height -= 1
 	}
 	subctx := ctx.Subcontext(x, y, width, height)
diff --git a/lib/ui/context.go b/lib/ui/context.go
index ca3f452..8031689 100644
--- a/lib/ui/context.go
+++ b/lib/ui/context.go
@@ -4,73 +4,77 @@ import (
 	"fmt"
 
 	"github.com/mattn/go-runewidth"
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
+	"github.com/gdamore/tcell/views"
 )
 
 // A context allows you to draw in a sub-region of the terminal
 type Context struct {
-	x      int
-	y      int
-	width  int
-	height int
+	viewport *views.ViewPort
 }
 
 func (ctx *Context) X() int {
-	return ctx.x
+	x, _, _, _ := ctx.viewport.GetPhysical()
+	return x
 }
 
 func (ctx *Context) Y() int {
-	return ctx.y
+	_, y, _, _ := ctx.viewport.GetPhysical()
+	return y
 }
 
 func (ctx *Context) Width() int {
-	return ctx.width
+	width, _ := ctx.viewport.Size()
+	return width
 }
 
 func (ctx *Context) Height() int {
-	return ctx.height
+	_, height := ctx.viewport.Size()
+	return height
 }
 
-func NewContext(width, height int) *Context {
-	return &Context{0, 0, width, height}
+func NewContext(width, height int, screen tcell.Screen) *Context {
+	vp := views.NewViewPort(screen, 0, 0, width, height)
+	return &Context{vp}
 }
 
 func (ctx *Context) Subcontext(x, y, width, height int) *Context {
-	if x+width > ctx.width || y+height > ctx.height {
-		panic(fmt.Errorf("Attempted to create context larger than parent"))
+	vp_width, vp_height := ctx.viewport.Size()
+	if (x < 0 || y < 0) {
+		panic(fmt.Errorf("Attempted to create context with negative offset"))
 	}
-	return &Context{
-		x:      ctx.x + x,
-		y:      ctx.y + y,
-		width:  width,
-		height: height,
+	if (x + width > vp_width || y + height > vp_height) {
+		panic(fmt.Errorf("Attempted to create context larger than parent"))
 	}
+	vp := views.NewViewPort(ctx.viewport, x, y, width, height)
+	return &Context{vp}
 }
 
-func (ctx *Context) SetCell(x, y int, ch rune, fg, bg tb.Attribute) {
-	if x >= ctx.width || y >= ctx.height {
+func (ctx *Context) SetCell(x, y int, ch rune, style tcell.Style) {
+	width, height := ctx.viewport.Size()
+	if x >= width || y >= height {
 		panic(fmt.Errorf("Attempted to draw outside of context"))
 	}
-	tb.SetCell(ctx.x+x, ctx.y+y, ch, fg, bg)
+	crunes := []rune{}
+	ctx.viewport.SetContent(x, y, ch, crunes, style)
 }
 
-func (ctx *Context) Printf(x, y int, ref tb.Cell,
+func (ctx *Context) Printf(x, y int, style tcell.Style,
 	format string, a ...interface{}) int {
+	width, height := ctx.viewport.Size()
 
-	if x >= ctx.width || y >= ctx.height {
+	if x >= width || y >= height {
 		panic(fmt.Errorf("Attempted to draw outside of context"))
 	}
 
 	str := fmt.Sprintf(format, a...)
 
-	x += ctx.x
-	y += ctx.y
 	old_x := x
 
 	newline := func() bool {
 		x = old_x
 		y++
-		return y < ctx.height
+		return y < height
 	}
 	for _, ch := range str {
 		if str == " こんにちは " {
@@ -84,9 +88,10 @@ func (ctx *Context) Printf(x, y int, ref tb.Cell,
 		case '\r':
 			x = old_x
 		default:
-			tb.SetCell(x, y, ch, ref.Fg, ref.Bg)
+			crunes := []rune{}
+			ctx.viewport.SetContent(x, y, ch, crunes, style)
 			x += runewidth.RuneWidth(ch)
-			if x == old_x+ctx.width {
+			if x == old_x + width {
 				if !newline() {
 					return runewidth.StringWidth(str)
 				}
@@ -97,13 +102,20 @@ func (ctx *Context) Printf(x, y int, ref tb.Cell,
 	return runewidth.StringWidth(str)
 }
 
-func (ctx *Context) Fill(x, y, width, height int, ref tb.Cell) {
-	_x := x
-	_y := y
-	for ; y < _y+height && y < ctx.height; y++ {
-		for ; x < _x+width && x < ctx.width; x++ {
-			ctx.SetCell(x, y, ref.Ch, ref.Fg, ref.Bg)
-		}
-		x = _x
-	}
+//func (ctx *Context) Screen() tcell.Screen {
+//	return ctx.screen
+//}
+
+func (ctx *Context) Fill(x, y, width, height int, rune rune, style tcell.Style) {
+	vp := views.NewViewPort(ctx.viewport, x, y, width, height)
+	vp.Fill(rune, style)
+}
+
+func (ctx *Context) SetCursor(x, y int) {
+	// FIXME: Cursor needs to be set on tcell.Screen, or layout has to
+	// provide a CellModel
+	// cv := views.NewCellView()
+	// cv.Init()
+	// cv.SetView(ctx.viewport)
+	// cv.SetCursor(x, y)
 }
diff --git a/lib/ui/fill.go b/lib/ui/fill.go
index 3c6f0a5..4d36478 100644
--- a/lib/ui/fill.go
+++ b/lib/ui/fill.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Fill rune
@@ -13,7 +13,7 @@ func NewFill(f rune) Fill {
 func (f Fill) Draw(ctx *Context) {
 	for x := 0; x < ctx.Width(); x += 1 {
 		for y := 0; y < ctx.Height(); y += 1 {
-			ctx.SetCell(x, y, rune(f), tb.ColorDefault, tb.ColorDefault)
+			ctx.SetCell(x, y, rune(f), tcell.StyleDefault)
 		}
 	}
 }
diff --git a/lib/ui/interactive.go b/lib/ui/interactive.go
index efab828..2d4f099 100644
--- a/lib/ui/interactive.go
+++ b/lib/ui/interactive.go
@@ -1,17 +1,17 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Interactive interface {
 	// Returns true if the event was handled by this component
-	Event(event tb.Event) bool
+	Event(event tcell.Event) bool
 }
 
 type Simulator interface {
 	// Queues up the given input events for simulation
-	Simulate(events []tb.Event)
+	Simulate(events []tcell.Event)
 }
 
 type DrawableInteractive interface {
diff --git a/lib/ui/stack.go b/lib/ui/stack.go
index 9f81db8..3c66f5a 100644
--- a/lib/ui/stack.go
+++ b/lib/ui/stack.go
@@ -3,7 +3,7 @@ package ui
 import (
 	"fmt"
 
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Stack struct {
@@ -29,12 +29,7 @@ func (stack *Stack) Draw(ctx *Context) {
 	if len(stack.children) > 0 {
 		stack.Peek().Draw(ctx)
 	} else {
-		cell := tb.Cell{
-			Fg: tb.ColorDefault,
-			Bg: tb.ColorDefault,
-			Ch: ' ',
-		}
-		ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
+		ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
 	}
 }
 
diff --git a/lib/ui/tab.go b/lib/ui/tab.go
index e6a8aa5..d0635c7 100644
--- a/lib/ui/tab.go
+++ b/lib/ui/tab.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 type Tabs struct {
@@ -72,21 +72,14 @@ func (tabs *Tabs) Select(index int) {
 func (strip *TabStrip) Draw(ctx *Context) {
 	x := 0
 	for i, tab := range strip.Tabs {
-		cell := tb.Cell{
-			Fg: tb.ColorBlack,
-			Bg: tb.ColorWhite,
-		}
+		style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
 		if strip.Selected == i {
-			cell.Fg = tb.ColorDefault
-			cell.Bg = tb.ColorDefault
+			style = style.Reverse(true)
 		}
-		x += ctx.Printf(x, 0, cell, " %s ", tab.Name)
-	}
-	cell := tb.Cell{
-		Fg: tb.ColorBlack,
-		Bg: tb.ColorWhite,
+		x += ctx.Printf(x, 0, style, " %s ", tab.Name)
 	}
-	ctx.Fill(x, 0, ctx.Width()-x, 1, cell)
+	style := tcell.StyleDefault.Background(tcell.ColorWhite).Foreground(tcell.ColorBlack)
+	ctx.Fill(x, 0, ctx.Width()-x, 1, ' ', style)
 }
 
 func (strip *TabStrip) Invalidate() {
diff --git a/lib/ui/text.go b/lib/ui/text.go
index 6164837..e2e218c 100644
--- a/lib/ui/text.go
+++ b/lib/ui/text.go
@@ -2,7 +2,7 @@ package ui
 
 import (
 	"github.com/mattn/go-runewidth"
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 )
 
 const (
@@ -14,8 +14,8 @@ const (
 type Text struct {
 	text         string
 	strategy     uint
-	fg           tb.Attribute
-	bg           tb.Attribute
+	fg           tcell.Color
+	bg           tcell.Color
 	onInvalidate func(d Drawable)
 }
 
@@ -35,7 +35,7 @@ func (t *Text) Strategy(strategy uint) *Text {
 	return t
 }
 
-func (t *Text) Color(fg tb.Attribute, bg tb.Attribute) *Text {
+func (t *Text) Color(fg tcell.Color, bg tcell.Color) *Text {
 	t.fg = fg
 	t.bg = bg
 	t.Invalidate()
@@ -44,11 +44,6 @@ func (t *Text) Color(fg tb.Attribute, bg tb.Attribute) *Text {
 
 func (t *Text) Draw(ctx *Context) {
 	size := runewidth.StringWidth(t.text)
-	cell := tb.Cell{
-		Ch: ' ',
-		Fg: t.fg,
-		Bg: t.bg,
-	}
 	x := 0
 	if t.strategy == TEXT_CENTER {
 		x = (ctx.Width() - size) / 2
@@ -56,8 +51,9 @@ func (t *Text) Draw(ctx *Context) {
 	if t.strategy == TEXT_RIGHT {
 		x = ctx.Width() - size
 	}
-	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
-	ctx.Printf(x, 0, cell, "%s", t.text)
+	style := tcell.StyleDefault.Background(t.bg).Foreground(t.fg)
+	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style)
+	ctx.Printf(x, 0, style, t.text)
 }
 
 func (t *Text) OnInvalidate(onInvalidate func(d Drawable)) {
diff --git a/lib/ui/ui.go b/lib/ui/ui.go
index e9b4e9b..d3eacf2 100644
--- a/lib/ui/ui.go
+++ b/lib/ui/ui.go
@@ -1,7 +1,7 @@
 package ui
 
 import (
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 
 	"git.sr.ht/~sircmpwn/aerc2/config"
 )
@@ -10,30 +10,41 @@ type UI struct {
 	Exit    bool
 	Content DrawableInteractive
 	ctx     *Context
+	screen  tcell.Screen
 
-	tbEvents      chan tb.Event
+	tcEvents      chan tcell.Event
 	invalidations chan interface{}
 }
 
 func Initialize(conf *config.AercConfig,
 	content DrawableInteractive) (*UI, error) {
 
-	if err := tb.Init(); err != nil {
+	screen, err := tcell.NewScreen()
+	if err != nil {
 		return nil, err
 	}
-	width, height := tb.Size()
+
+	if err = screen.Init(); err != nil {
+		return nil, err
+	}
+
+	screen.Clear()
+	screen.HideCursor()
+
+	width, height := screen.Size()
+
 	state := UI{
 		Content: content,
-		ctx:     NewContext(width, height),
+		ctx:     NewContext(width, height, screen),
+		screen:  screen,
 
-		tbEvents:      make(chan tb.Event, 10),
+		tcEvents:      make(chan tcell.Event, 10),
 		invalidations: make(chan interface{}),
 	}
-	tb.SetInputMode(tb.InputEsc | tb.InputMouse)
-	tb.SetOutputMode(tb.Output256)
+	//tb.SetOutputMode(tb.Output256)
 	go (func() {
 		for !state.Exit {
-			state.tbEvents <- tb.PollEvent()
+			state.tcEvents <- screen.PollEvent()
 		}
 	})()
 	go (func() { state.invalidations <- nil })()
@@ -44,27 +55,28 @@ func Initialize(conf *config.AercConfig,
 }
 
 func (state *UI) Close() {
-	tb.Close()
+	state.screen.Fini()
 }
 
 func (state *UI) Tick() bool {
 	select {
-	case event := <-state.tbEvents:
-		switch event.Type {
-		case tb.EventKey:
+	case event := <-state.tcEvents:
+		switch event := event.(type) {
+		case *tcell.EventKey:
 			// TODO: temporary
-			if event.Key == tb.KeyEsc {
+			if event.Key() == tcell.KeyEsc {
 				state.Exit = true
 			}
-		case tb.EventResize:
-			tb.Clear(tb.ColorDefault, tb.ColorDefault)
-			state.ctx = NewContext(event.Width, event.Height)
+		case *tcell.EventResize:
+			state.screen.Clear()
+			width, height := event.Size()
+			state.ctx = NewContext(width, height, state.screen)
 			state.Content.Invalidate()
 		}
 		state.Content.Event(event)
 	case <-state.invalidations:
 		state.Content.Draw(state.ctx)
-		tb.Flush()
+		state.screen.Show()
 	default:
 		return false
 	}
diff --git a/widgets/aerc.go b/widgets/aerc.go
index 5563275..19ddfdd 100644
--- a/widgets/aerc.go
+++ b/widgets/aerc.go
@@ -5,7 +5,7 @@ import (
 	"log"
 	"time"
 
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 
 	libui "git.sr.ht/~sircmpwn/aerc2/lib/ui"
 )
@@ -35,7 +35,7 @@ func NewAerc(logger *log.Logger) *Aerc {
 	// TODO: move sidebar into tab content, probably
 	grid.AddChild(libui.NewText("aerc").
 		Strategy(libui.TEXT_CENTER).
-		Color(tb.ColorBlack, tb.ColorWhite))
+		Color(tcell.ColorBlack, tcell.ColorWhite))
 	// sidebar placeholder:
 	grid.AddChild(libui.NewBordered(
 		libui.NewFill('.'), libui.BORDER_RIGHT)).At(1, 0).Span(2, 1)
@@ -75,10 +75,10 @@ func (aerc *Aerc) Draw(ctx *libui.Context) {
 	aerc.grid.Draw(ctx)
 }
 
-func (aerc *Aerc) Event(event tb.Event) bool {
-	switch event.Type {
-	case tb.EventKey:
-		if event.Ch == ':' {
+func (aerc *Aerc) Event(event tcell.Event) bool {
+	switch event := event.(type) {
+	case *tcell.EventKey:
+		if event.Rune() == ':' {
 			exline := NewExLine(func(command string) {
 				aerc.statusline.Push(fmt.Sprintf("TODO: execute %s", command),
 					3 * time.Second)
@@ -92,12 +92,10 @@ func (aerc *Aerc) Event(event tb.Event) bool {
 			aerc.statusbar.Push(exline)
 			return true
 		}
-		fallthrough
-	default:
-		if aerc.interactive != nil {
-			return aerc.interactive.Event(event)
-		} else {
-			return false
-		}
+	}
+	if aerc.interactive != nil {
+		return aerc.interactive.Event(event)
+	} else {
+		return false
 	}
 }
diff --git a/widgets/exline.go b/widgets/exline.go
index 0522371..de652ba 100644
--- a/widgets/exline.go
+++ b/widgets/exline.go
@@ -2,7 +2,7 @@ package widgets
 
 import (
 	"github.com/mattn/go-runewidth"
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 
 	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
 )
@@ -40,15 +40,10 @@ func (ex *ExLine) Invalidate() {
 }
 
 func (ex *ExLine) Draw(ctx *ui.Context) {
-	cell := tb.Cell{
-		Fg: tb.ColorDefault,
-		Bg: tb.ColorDefault,
-		Ch: ' ',
-	}
-	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
-	ctx.Printf(0, 0, cell, ":%s", string(ex.command))
+	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', tcell.StyleDefault)
+	ctx.Printf(0, 0, tcell.StyleDefault, ":%s", string(ex.command))
 	cells := runewidth.StringWidth(string(ex.command[:ex.index]))
-	tb.SetCursor(ctx.X()+cells+1, ctx.Y())
+	ctx.SetCursor(cells + 1, 0)
 }
 
 func (ex *ExLine) insert(ch rune) {
@@ -93,43 +88,41 @@ func (ex *ExLine) backspace() {
 	}
 }
 
-func (ex *ExLine) Event(event tb.Event) bool {
-	switch event.Type {
-	case tb.EventKey:
-		switch event.Key {
-		case tb.KeySpace:
-			ex.insert(' ')
-		case tb.KeyBackspace, tb.KeyBackspace2:
+func (ex *ExLine) Event(event tcell.Event) bool {
+	switch event := event.(type) {
+	case *tcell.EventKey:
+		switch event.Key() {
+		case tcell.KeyBackspace, tcell.KeyBackspace2:
 			ex.backspace()
-		case tb.KeyCtrlD, tb.KeyDelete:
+		case tcell.KeyCtrlD, tcell.KeyDelete:
 			ex.deleteChar()
-		case tb.KeyCtrlB, tb.KeyArrowLeft:
+		case tcell.KeyCtrlB, tcell.KeyLeft:
 			if ex.index > 0 {
 				ex.index--
 				ex.Invalidate()
 			}
-		case tb.KeyCtrlF, tb.KeyArrowRight:
+		case tcell.KeyCtrlF, tcell.KeyRight:
 			if ex.index < len(ex.command) {
 				ex.index++
 				ex.Invalidate()
 			}
-		case tb.KeyCtrlA, tb.KeyHome:
+		case tcell.KeyCtrlA, tcell.KeyHome:
 			ex.index = 0
 			ex.Invalidate()
-		case tb.KeyCtrlE, tb.KeyEnd:
+		case tcell.KeyCtrlE, tcell.KeyEnd:
 			ex.index = len(ex.command)
 			ex.Invalidate()
-		case tb.KeyCtrlW:
+		case tcell.KeyCtrlW:
 			ex.deleteWord()
-		case tb.KeyEnter:
-			tb.HideCursor()
+		case tcell.KeyEnter:
+			//ex.ctx.Screen().HideCursor()
 			ex.commit(string(ex.command))
-		case tb.KeyEsc, tb.KeyCtrlC:
-			tb.HideCursor()
+		case tcell.KeyEsc, tcell.KeyCtrlC:
+			//ex.ctx.Screen().HideCursor()
 			ex.cancel()
 		default:
-			if event.Ch != 0 {
-				ex.insert(event.Ch)
+			if event.Rune() != 0 {
+				ex.insert(event.Rune())
 			}
 		}
 	}
diff --git a/widgets/status.go b/widgets/status.go
index bb87d33..3b4dbcc 100644
--- a/widgets/status.go
+++ b/widgets/status.go
@@ -3,7 +3,7 @@ package widgets
 import (
 	"time"
 
-	tb "github.com/nsf/termbox-go"
+	"github.com/gdamore/tcell"
 
 	"git.sr.ht/~sircmpwn/aerc2/lib/ui"
 )
@@ -16,16 +16,16 @@ type StatusLine struct {
 }
 
 type StatusMessage struct {
-	bg      tb.Attribute
-	fg      tb.Attribute
+	bg      tcell.Color
+	fg      tcell.Color
 	message string
 }
 
 func NewStatusLine() *StatusLine {
 	return &StatusLine{
 		fallback: StatusMessage{
-			bg:      tb.ColorWhite,
-			fg:      tb.ColorBlack,
+			bg:      tcell.ColorWhite,
+			fg:      tcell.ColorBlack,
 			message: "Idle",
 		},
 	}
@@ -46,19 +46,15 @@ func (status *StatusLine) Draw(ctx *ui.Context) {
 	if len(status.stack) != 0 {
 		line = status.stack[len(status.stack)-1]
 	}
-	cell := tb.Cell{
-		Fg: line.fg,
-		Bg: line.bg,
-		Ch: ' ',
-	}
-	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), cell)
-	ctx.Printf(0, 0, cell, "%s", line.message)
+	style := tcell.StyleDefault.Background(line.bg).Foreground(line.fg)
+	ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', style)
+	ctx.Printf(0, 0, style, "%s", line.message)
 }
 
 func (status *StatusLine) Set(text string) *StatusMessage {
 	status.fallback = StatusMessage{
-		bg:      tb.ColorWhite,
-		fg:      tb.ColorBlack,
+		bg:      tcell.ColorWhite,
+		fg:      tcell.ColorBlack,
 		message: text,
 	}
 	status.Invalidate()
@@ -67,8 +63,8 @@ func (status *StatusLine) Set(text string) *StatusMessage {
 
 func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage {
 	msg := &StatusMessage{
-		bg:      tb.ColorWhite,
-		fg:      tb.ColorBlack,
+		bg:      tcell.ColorWhite,
+		fg:      tcell.ColorBlack,
 		message: text,
 	}
 	status.stack = append(status.stack, msg)
@@ -85,7 +81,7 @@ func (status *StatusLine) Push(text string, expiry time.Duration) *StatusMessage
 	return msg
 }
 
-func (msg *StatusMessage) Color(bg tb.Attribute, fg tb.Attribute) {
+func (msg *StatusMessage) Color(bg tcell.Color, fg tcell.Color) {
 	msg.bg = bg
 	msg.fg = fg
 }