aerc/widgets/exline.go
Markus Ongyerth 80e891a802 switch to tcell from termbox
This is a simple mostly straight forward switch to tcell in favor of
termbox.
It uses the tcell native api (not the compat layer) but does not make
use of most features.

Further changes should include moving to tcell's views.TextArea and the
general built in widget behaviour instead of the current ad hoc
implementation.

Regression: Cursor isn't shown in ex-line
2018-06-01 16:04:43 -07:00

130 lines
2.7 KiB
Go

package widgets
import (
"github.com/mattn/go-runewidth"
"github.com/gdamore/tcell"
"git.sr.ht/~sircmpwn/aerc2/lib/ui"
)
// TODO: history
// TODO: tab completion
// TODO: scrolling
type ExLine struct {
command []rune
commit func(cmd string)
cancel func()
index int
scroll int
onInvalidate func(d ui.Drawable)
}
func NewExLine(commit func (cmd string), cancel func()) *ExLine {
return &ExLine{
cancel: cancel,
commit: commit,
command: []rune{},
}
}
func (ex *ExLine) OnInvalidate(onInvalidate func(d ui.Drawable)) {
ex.onInvalidate = onInvalidate
}
func (ex *ExLine) Invalidate() {
if ex.onInvalidate != nil {
ex.onInvalidate(ex)
}
}
func (ex *ExLine) Draw(ctx *ui.Context) {
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]))
ctx.SetCursor(cells + 1, 0)
}
func (ex *ExLine) insert(ch rune) {
left := ex.command[:ex.index]
right := ex.command[ex.index:]
ex.command = append(left, append([]rune{ch}, right...)...)
ex.index++
ex.Invalidate()
}
func (ex *ExLine) deleteWord() {
// TODO: Break on any of / " '
if len(ex.command) == 0 {
return
}
i := ex.index - 1
if ex.command[i] == ' ' {
i--
}
for ; i >= 0; i-- {
if ex.command[i] == ' ' {
break
}
}
ex.command = append(ex.command[:i+1], ex.command[ex.index:]...)
ex.index = i + 1
ex.Invalidate()
}
func (ex *ExLine) deleteChar() {
if len(ex.command) > 0 && ex.index != len(ex.command) {
ex.command = append(ex.command[:ex.index], ex.command[ex.index+1:]...)
ex.Invalidate()
}
}
func (ex *ExLine) backspace() {
if len(ex.command) > 0 && ex.index != 0 {
ex.command = append(ex.command[:ex.index-1], ex.command[ex.index:]...)
ex.index--
ex.Invalidate()
}
}
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 tcell.KeyCtrlD, tcell.KeyDelete:
ex.deleteChar()
case tcell.KeyCtrlB, tcell.KeyLeft:
if ex.index > 0 {
ex.index--
ex.Invalidate()
}
case tcell.KeyCtrlF, tcell.KeyRight:
if ex.index < len(ex.command) {
ex.index++
ex.Invalidate()
}
case tcell.KeyCtrlA, tcell.KeyHome:
ex.index = 0
ex.Invalidate()
case tcell.KeyCtrlE, tcell.KeyEnd:
ex.index = len(ex.command)
ex.Invalidate()
case tcell.KeyCtrlW:
ex.deleteWord()
case tcell.KeyEnter:
//ex.ctx.Screen().HideCursor()
ex.commit(string(ex.command))
case tcell.KeyEsc, tcell.KeyCtrlC:
//ex.ctx.Screen().HideCursor()
ex.cancel()
default:
if event.Rune() != 0 {
ex.insert(event.Rune())
}
}
}
return true
}